Multiple VxLAN tunnels - egress service
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / confighelpers / ItmTunnelAggregationHelper.java
1 /*
2  * Copyright (c) 2017 Hewlett Packard Enterprise, Co. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.genius.itm.confighelpers;
10
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.ListenableFuture;
13
14 import java.math.BigInteger;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.concurrent.Callable;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
26 import org.opendaylight.genius.interfacemanager.globals.IfmConstants;
27 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
28 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo.InterfaceAdminState;
29 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
30 import org.opendaylight.genius.itm.globals.ITMConstants;
31 import org.opendaylight.genius.itm.impl.ItmUtils;
32 import org.opendaylight.genius.mdsalutil.ActionInfo;
33 import org.opendaylight.genius.mdsalutil.MDSALUtil;
34 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.InterfaceChildInfo;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info.InterfaceParentEntry;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info.InterfaceParentEntryKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info._interface.parent.entry.InterfaceChildEntry;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info._interface.parent.entry.InterfaceChildEntryBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info._interface.parent.entry.InterfaceChildEntryKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeLogicalGroup;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.ItmConfig;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.itm.config.TunnelAggregation;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnel;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
58 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62 @Singleton
63 public class ItmTunnelAggregationHelper {
64
65     public static final int ADD_TUNNEL = 0;
66     public static final int DEL_TUNNEL = 1;
67     public static final int MOD_TUNNEL = 2;
68     public static final int MOD_GROUP_TUNNEL = 3;
69     public static final int DEFAULT_WEIGHT = 1;
70     public static final long INVALID_ID = 0;
71
72     private static final Logger LOG = LoggerFactory.getLogger(ItmTunnelAggregationHelper.class);
73     private static boolean tunnelAggregationEnabled;
74     private final IInterfaceManager interfaceManager;
75     private final IMdsalApiManager mdsalManager;
76
77     @Inject
78     public ItmTunnelAggregationHelper(final IInterfaceManager interfaceMngr,
79                                       final IMdsalApiManager mdsalMngr, final ItmConfig itmConfig) {
80         interfaceManager = interfaceMngr;
81         mdsalManager = mdsalMngr;
82         initTunnelAggregationConfig(itmConfig);
83     }
84
85     public static boolean isTunnelAggregationEnabled() {
86         return tunnelAggregationEnabled;
87     }
88
89     public void createLogicalTunnelSelectGroup(BigInteger srcDpnId, String interfaceName, int lportTag) {
90         Group group = prepareLogicalTunnelSelectGroup(srcDpnId, interfaceName, lportTag);
91         LOG.debug("MULTIPLE_VxLAN_TUNNELS: group id {} installed for {} srcDpnId {}",
92                 group.getGroupId().getValue(), interfaceName, srcDpnId);
93         mdsalManager.syncInstallGroup(srcDpnId, group, ITMConstants.DELAY_TIME_IN_MILLISECOND);
94     }
95
96     public void updateLogicalTunnelSelectGroup(InterfaceParentEntry entry, DataBroker broker) {
97         String logicTunnelName = entry.getParentInterface();
98         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
99                     .interfaces.Interface ifaceConfig = ItmUtils.getInterface(logicTunnelName, interfaceManager);
100         if (ifaceConfig == null || !ifaceConfig.getType().isAssignableFrom(Tunnel.class)) {
101             return;
102         }
103         IfTunnel ifTunnel = ifaceConfig.getAugmentation(IfTunnel.class);
104         if (!ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeLogicalGroup.class)) {
105             return;
106         }
107         LOG.debug("MULTIPLE_VxLAN_TUNNELS: updateLogicalTunnelSelectGroup name {}", logicTunnelName);
108         DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
109         TunnelAggregationUpdateWorker worker =
110                 new TunnelAggregationUpdateWorker(null, null, ifaceConfig, entry, MOD_GROUP_TUNNEL, broker);
111         coordinator.enqueueJob(logicTunnelName, worker);
112     }
113
114     public void updateLogicalTunnelState(Interface ifaceState, int tunnelAction, DataBroker broker) {
115         updateLogicalTunnelState(null, ifaceState, tunnelAction, broker);
116     }
117
118     public void updateLogicalTunnelState(Interface ifStateOrigin, Interface ifStateUpdated,
119                                                 int tunnelAction, DataBroker broker) {
120         boolean tunnelAggregationEnabled = isTunnelAggregationEnabled();
121         if (!tunnelAggregationEnabled || ifStateUpdated == null) {
122             LOG.debug("MULTIPLE_VxLAN_TUNNELS: updateLogicalTunnelState - wrong configuration -"
123                     + " tunnelAggregationEnabled {} ifStateUpdated {}", tunnelAggregationEnabled, ifStateUpdated);
124             return;
125         }
126         String ifName = ifStateUpdated.getName();
127         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
128                 ItmUtils.getInterface(ifName, interfaceManager);
129         IfTunnel ifTunnel = iface != null ? iface.getAugmentation(IfTunnel.class) : null;
130         if (iface == null || ifTunnel == null) {
131             LOG.debug("MULTIPLE_VxLAN_TUNNELS: updateLogicalTunnelState - not tunnel interface {}", ifName);
132             return;
133         }
134         String logicTunnelName = null;
135         if (ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeLogicalGroup.class)) {
136             logicTunnelName = ifStateUpdated.getName();
137         } else {
138             ParentRefs parentRefs = iface.getAugmentation(ParentRefs.class);
139             if (ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class) && parentRefs != null) {
140                 logicTunnelName = parentRefs.getParentInterface();
141             }
142         }
143         if (logicTunnelName != null) {
144             DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
145             TunnelAggregationUpdateWorker worker =
146                     new TunnelAggregationUpdateWorker(ifStateOrigin, ifStateUpdated, iface, null, tunnelAction, broker);
147             coordinator.enqueueJob(logicTunnelName, worker);
148         }
149     }
150
151     private void initTunnelAggregationConfig(ItmConfig itmConfig) {
152         // Load balancing of VxLAN feature is guarded by a global configuration option in the ITM,
153         // only when the feature is enabled, the logical tunnel interfaces should be created.
154         boolean tunnelAggregationConfigEnabled = false;
155         List<TunnelAggregation> tunnelsConfig = itmConfig != null ? itmConfig.getTunnelAggregation() : null;
156         if (tunnelsConfig != null) {
157             for (TunnelAggregation tnlCfg : tunnelsConfig) {
158                 Class<? extends TunnelTypeBase> tunType = ItmUtils.getTunnelType(tnlCfg.getKey().getTunnelType());
159                 if (tunType.isAssignableFrom(TunnelTypeVxlan.class)) {
160                     tunnelAggregationConfigEnabled = tnlCfg.isEnabled();
161                     LOG.info("MULTIPLE_VxLAN_TUNNELS: tunnelAggregationEnabled {}", tunnelAggregationConfigEnabled);
162                     break;
163                 }
164             }
165         }
166         tunnelAggregationEnabled = tunnelAggregationConfigEnabled;
167     }
168
169     private Group prepareLogicalTunnelSelectGroup(BigInteger srcDpnId, String interfaceName, int lportTag) {
170         long groupId = interfaceManager.getLogicalTunnelSelectGroupId(lportTag);
171         Group group = MDSALUtil.buildGroup(groupId, interfaceName, GroupTypes.GroupSelect,
172                                            MDSALUtil.buildBucketLists(Collections.emptyList()));
173         return group;
174     }
175
176     private Bucket createBucket(String interfaceName, IfTunnel ifTunnel, ParentRefs parentRefs,
177                                        Integer ifIndex, int bucketId, int portNumber) {
178         List<ActionInfo> listActionInfo = interfaceManager.getInterfaceEgressActions(interfaceName);
179         if (listActionInfo == null || listActionInfo.isEmpty()) {
180             LOG.warn("MULTIPLE_VxLAN_TUNNELS: could not build Egress bucket for {}", interfaceName);
181         }
182         Integer portWeight = ifTunnel.getWeight() != null ? ifTunnel.getWeight() : DEFAULT_WEIGHT;
183         Bucket buckt = MDSALUtil.buildBucket(MDSALUtil.buildActions(listActionInfo), portWeight, bucketId,
184                                              portNumber, MDSALUtil.WATCH_GROUP);
185         return buckt;
186     }
187
188     private void updateTunnelAggregationGroup(InterfaceParentEntry parentEntry) {
189         String logicTunnelName = parentEntry.getParentInterface();
190         InternalTunnel logicInternalTunnel = ItmUtils.itmCache.getInternalTunnel(logicTunnelName);
191         if (logicInternalTunnel == null) {
192             LOG.debug("MULTIPLE_VxLAN_TUNNELS: {} not found in internal tunnels list", logicTunnelName);
193             return;
194         }
195         InterfaceInfo ifLogicTunnel = interfaceManager.getInterfaceInfoFromOperationalDataStore(logicTunnelName);
196         long groupId = ifLogicTunnel != null
197                 ? interfaceManager.getLogicalTunnelSelectGroupId(ifLogicTunnel.getInterfaceTag()) : INVALID_ID;
198         BigInteger srcDpnId = logicInternalTunnel.getSourceDPN();
199         List<Bucket> listBuckets = new ArrayList<>();
200         List<InterfaceChildEntry> interfaceChildEntries = parentEntry.getInterfaceChildEntry();
201         if (interfaceChildEntries == null || interfaceChildEntries.isEmpty()) {
202             LOG.debug("MULTIPLE_VxLAN_TUNNELS: empty child list in group {}", parentEntry.getParentInterface());
203             return;
204         }
205         for (InterfaceChildEntry interfaceChildEntry : interfaceChildEntries) {
206             String curChildName = interfaceChildEntry.getChildInterface();
207             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface
208                         childIface = ItmUtils.getInterface(curChildName, interfaceManager);
209             IfTunnel ifTunnel = childIface != null ? childIface.getAugmentation(IfTunnel.class) : null;
210             if (ifTunnel == null || !ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
211                 LOG.debug("MULTIPLE_VxLAN_TUNNELS: not tunnel interface {} found in group {}",
212                         curChildName, logicTunnelName);
213                 continue;
214             }
215             ParentRefs parentRefs = childIface.getAugmentation(ParentRefs.class);
216             if (parentRefs == null) {
217                 LOG.debug("MULTIPLE_VxLAN_TUNNELS: parent refs not specified for interface {} in group {}",
218                         curChildName, logicTunnelName);
219                 continue;
220             }
221             InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(curChildName);
222             if (ifInfo == null) {
223                 LOG.debug("MULTIPLE_VxLAN_TUNNELS: interface state not found for {} in groupId {}",
224                         curChildName, groupId);
225                 continue;
226             }
227             int bucketId = interfaceChildEntries.indexOf(interfaceChildEntry);
228             LOG.debug("MULTIPLE_VxLAN_TUNNELS: updateTunnelAggregationGroup - add bucketId {} to groupId {}",
229                     bucketId, groupId);
230             Bucket buckt = createBucket(curChildName, ifTunnel, parentRefs, ifInfo.getInterfaceTag(),
231                                         bucketId, ifInfo.getPortNo());
232             listBuckets.add(buckt);
233         }
234         if (!listBuckets.isEmpty()) {
235             Group group = MDSALUtil.buildGroup(groupId, logicTunnelName, GroupTypes.GroupSelect,
236                                                MDSALUtil.buildBucketLists(listBuckets));
237             mdsalManager.syncInstallGroup(srcDpnId, group, ITMConstants.DELAY_TIME_IN_MILLISECOND);
238         }
239     }
240
241     private void updateTunnelAggregationGroupBucket(Interface ifaceState, IfTunnel ifTunnel,
242                                                     ParentRefs parentRefs, InterfaceParentEntry groupParentEntry,
243                                                     int action, WriteTransaction tx) {
244         String logicTunnelName = parentRefs.getParentInterface();
245         List<InterfaceChildEntry> interfaceChildEntries = groupParentEntry.getInterfaceChildEntry();
246         if (interfaceChildEntries == null) {
247             LOG.debug("MULTIPLE_VxLAN_TUNNELS: empty child list in group {}", groupParentEntry.getParentInterface());
248             return;
249         }
250         String ifaceName = ifaceState.getName();
251         InterfaceChildEntry childEntry = new InterfaceChildEntryBuilder().setChildInterface(ifaceName)
252                 .setKey(new InterfaceChildEntryKey(ifaceName)).build();
253         int bucketId = interfaceChildEntries.indexOf(childEntry);
254         if (bucketId == -1) {
255             LOG.debug("MULTIPLE_VxLAN_TUNNELS: wrong child id for {} in group {}", ifaceName,
256                     groupParentEntry.getParentInterface());
257             return;
258         }
259         InterfaceInfo ifLogicTunnel = interfaceManager.getInterfaceInfoFromOperationalDataStore(logicTunnelName);
260         long groupId = ifLogicTunnel != null
261                 ? interfaceManager.getLogicalTunnelSelectGroupId(ifLogicTunnel.getInterfaceTag()) : INVALID_ID;
262         if (groupId == INVALID_ID) {
263             LOG.warn("MULTIPLE_VxLAN_TUNNELS: unknown group id for logic tunnel {}", logicTunnelName);
264             return;
265         }
266         String lowerLayerIf = ifaceState.getLowerLayerIf().get(0); // openflow:dpnid:portnum
267         String[] split = lowerLayerIf.split(IfmConstants.OF_URI_SEPARATOR);
268         BigInteger srcDpnId = new BigInteger(split[1]);
269         int portNumber = Integer.parseInt(split[2]);
270         if (action == ADD_TUNNEL) {
271             if (!mdsalManager.groupExists(srcDpnId, groupId)) {
272                 createLogicalTunnelSelectGroup(srcDpnId, logicTunnelName, ifLogicTunnel.getInterfaceTag());
273             }
274             Bucket buckt = createBucket(ifaceName, ifTunnel, parentRefs, ifaceState.getIfIndex(), bucketId, portNumber);
275             LOG.debug("MULTIPLE_VxLAN_TUNNELS: add bucketId {} to groupId {}", bucketId, groupId);
276             mdsalManager.addBucketToTx(srcDpnId, groupId, buckt, tx);
277         } else {
278             LOG.debug("MULTIPLE_VxLAN_TUNNELS: remove bucketId {} from groupId {}", bucketId, groupId);
279             mdsalManager.removeBucketToTx(srcDpnId, groupId, bucketId, tx);
280         }
281     }
282
283     private void updateLogicalTunnelGroupOperStatus(String logicalTunnelIfaceName, Interface ifaceState,
284                                                            InterfaceParentEntry parentEntry,
285                                                            DataBroker broker, WriteTransaction tx) {
286         if (parentEntry == null) {
287             LOG.debug("MULTIPLE_VxLAN_TUNNELS: uninitialized parent entry {}", logicalTunnelIfaceName);
288             return;
289         }
290         OperStatus newOperStatus = getAggregatedOperStatus(ifaceState, parentEntry);
291         if (logicalTunnelIfaceName.equals(ifaceState.getName())) { //the current interface is logical tunnel itself
292             if (ifaceState.getOperStatus() != newOperStatus) {
293                 updateInterfaceOperStatus(logicalTunnelIfaceName, ifaceState, newOperStatus, tx);
294             }
295         } else {
296             InterfaceInfo ifLogicInfo =
297                     interfaceManager.getInterfaceInfoFromOperationalDataStore(logicalTunnelIfaceName);
298             if (isLogicalTunnelStateUpdateNeeded(newOperStatus, ifLogicInfo)) {
299                 InstanceIdentifier<Interface> id = ItmUtils.buildStateInterfaceId(logicalTunnelIfaceName);
300                 Optional<Interface> ifState = ItmUtils.read(LogicalDatastoreType.OPERATIONAL, id, broker);
301                 if (ifState.isPresent()) {
302                     Interface ifStateLogicTunnel = ifState.get();
303                     updateInterfaceOperStatus(logicalTunnelIfaceName, ifStateLogicTunnel, newOperStatus, tx);
304                 }
305             }
306         }
307     }
308
309     private boolean isLogicalTunnelStateUpdateNeeded(OperStatus newOperStatus, InterfaceInfo ifLogicInfo) {
310         return ifLogicInfo != null && ((ifLogicInfo.getOpState() == InterfaceInfo.InterfaceOpState.UP
311                 && newOperStatus == OperStatus.Down)
312                 || (ifLogicInfo.getOpState() == InterfaceInfo.InterfaceOpState.DOWN && newOperStatus == OperStatus.Up));
313     }
314
315     private OperStatus getAggregatedOperStatus(Interface ifaceState, InterfaceParentEntry parentEntry) {
316         String logicalTunnelName = parentEntry.getParentInterface();
317         if (!logicalTunnelName.equals(ifaceState.getName()) && ifaceState.getOperStatus() == OperStatus.Up) {
318             return OperStatus.Up;
319         }
320
321         List<InterfaceChildEntry> interfaceChildEntries = parentEntry.getInterfaceChildEntry();
322         if (interfaceChildEntries == null || interfaceChildEntries.isEmpty()) {
323             LOG.debug("MULTIPLE_VxLAN_TUNNELS: OperStatus is Down, because of the empty child list in group {}",
324                     parentEntry.getParentInterface());
325             return OperStatus.Down;
326         }
327         for (InterfaceChildEntry interfaceChildEntry : interfaceChildEntries) {
328             String curChildInterface = interfaceChildEntry.getChildInterface();
329             if (!curChildInterface.equals(ifaceState.getName())) {
330                 InterfaceInfo ifInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(curChildInterface);
331                 if (ifInfo != null && InterfaceInfo.InterfaceOpState.UP.equals(ifInfo.getOpState())) {
332                     return OperStatus.Up;
333                 }
334             }
335         }
336         return OperStatus.Down;
337     }
338
339     private void updateInterfaceOperStatus(String ifaceName, Interface ifaceState,
340                                            OperStatus st, WriteTransaction tx) {
341         LOG.debug("MULTIPLE_VxLAN_TUNNELS: update OperStatus to be {} for {}", st.toString(), ifaceName);
342         InstanceIdentifier<Interface> idLogicGroup = ItmUtils.buildStateInterfaceId(ifaceName);
343         InterfaceBuilder ifaceBuilderChild = new InterfaceBuilder(ifaceState);
344         ifaceBuilderChild.setOperStatus(st);
345         tx.merge(LogicalDatastoreType.OPERATIONAL, idLogicGroup, ifaceBuilderChild.build(), true);
346     }
347
348     private void updateLogicalTunnelAdminStatus(String logicalTunnelName, Interface ifOrigin,
349             Interface ifUpdated, InterfaceParentEntry parentEntry, WriteTransaction tx) {
350
351         if (ifOrigin == null || ifUpdated == null || ifOrigin.getAdminStatus() == ifUpdated.getAdminStatus()) {
352             return;
353         }
354         List<InterfaceChildEntry> interfaceChildEntries = parentEntry.getInterfaceChildEntry();
355         if (interfaceChildEntries == null || interfaceChildEntries.isEmpty()) {
356             LOG.debug("MULTIPLE_VxLAN_TUNNELS: empty child list in group {}", logicalTunnelName);
357             return;
358         }
359         for (InterfaceChildEntry interfaceChildEntry : interfaceChildEntries) {
360             String curChildInterface = interfaceChildEntry.getChildInterface();
361             updateInterfaceAdminStatus(curChildInterface, ifUpdated.getAdminStatus(), tx);
362         }
363     }
364
365     private void updateInterfaceAdminStatus(String logicalTunnelName, Interface ifState, WriteTransaction tx) {
366         InterfaceInfo ifLogicTunnelInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(logicalTunnelName);
367         if (ifLogicTunnelInfo == null) {
368             return;
369         }
370         if (ifState.getAdminStatus() == AdminStatus.Up
371                 && ifLogicTunnelInfo.getAdminState() != InterfaceAdminState.ENABLED) {
372             updateInterfaceAdminStatus(ifState.getName(), AdminStatus.Down, tx);
373         }
374     }
375
376     private void updateInterfaceAdminStatus(String ifaceName, AdminStatus st, WriteTransaction tx) {
377         LOG.debug("MULTIPLE_VxLAN_TUNNELS: update AdminStatus to be {} for {}", st.toString(), ifaceName);
378         InstanceIdentifier<Interface> id = ItmUtils.buildStateInterfaceId(ifaceName);
379         InterfaceBuilder ifaceBuilderChild = new InterfaceBuilder();
380         ifaceBuilderChild.setKey(new InterfaceKey(ifaceName));
381         ifaceBuilderChild.setAdminStatus(st);
382         tx.merge(LogicalDatastoreType.OPERATIONAL, id, ifaceBuilderChild.build(), true);
383     }
384
385     private class TunnelAggregationUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
386
387         private final Interface ifStateOrigin;
388         private final Interface ifStateUpdated;
389         private final DataBroker dataBroker;
390         private final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
391                                                     .interfaces.rev140508.interfaces.Interface ifaceConfig;
392         private final int ifaceAction;
393         private final InterfaceParentEntry parentEntry;
394
395         TunnelAggregationUpdateWorker(Interface ifStateOrig, Interface ifStateUpdated,
396                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
397                 .interfaces.Interface iface, InterfaceParentEntry entry, int action, DataBroker broker) {
398             this.ifStateOrigin = ifStateOrig;
399             this.ifStateUpdated = ifStateUpdated;
400             this.ifaceConfig = iface;
401             this.ifaceAction = action;
402             this.dataBroker  = broker;
403             this.parentEntry = entry;
404         }
405
406         @Override
407         public List<ListenableFuture<Void>> call() throws Exception {
408             List<ListenableFuture<Void>> futures = new ArrayList<>();
409             if (ifaceAction == MOD_GROUP_TUNNEL) {
410                 updateTunnelAggregationGroup(parentEntry);
411                 return futures;
412             }
413             IfTunnel ifTunnel = ifaceConfig != null ? ifaceConfig.getAugmentation(IfTunnel.class) : null;
414             if (ifTunnel == null) {
415                 LOG.debug("MULTIPLE_VxLAN_TUNNELS: not tunnel interface {}", ifaceConfig.getName());
416                 return futures;
417             }
418             WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
419             if (ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeLogicalGroup.class)) {
420                 String logicTunnelIfaceName = ifStateUpdated.getName();
421                 InterfaceParentEntry parentEntry = getInterfaceParentEntry(logicTunnelIfaceName);
422                 updateLogicalTunnelGroupOperStatus(logicTunnelIfaceName, ifStateUpdated, parentEntry, dataBroker, tx);
423                 updateLogicalTunnelAdminStatus(logicTunnelIfaceName, ifStateOrigin, ifStateUpdated,
424                                                     parentEntry, tx);
425                 futures.add(tx.submit());
426                 return futures;
427             }
428             if (!ifTunnel.getTunnelInterfaceType().isAssignableFrom(TunnelTypeVxlan.class)) {
429                 LOG.debug("MULTIPLE_VxLAN_TUNNELS: wrong tunnel type {}", ifTunnel.getTunnelInterfaceType());
430                 return futures;
431             }
432             ParentRefs parentRefs = ifaceConfig.getAugmentation(ParentRefs.class);
433             if (parentRefs == null) {
434                 LOG.debug("MULTIPLE_VxLAN_TUNNELS: not updated parent ref for {}", ifaceConfig.getName());
435                 return futures;
436             }
437             String logicTunnelIfaceName = parentRefs.getParentInterface();
438             InterfaceParentEntry groupEntry = getInterfaceParentEntry(logicTunnelIfaceName);
439             if (groupEntry == null) {
440                 LOG.debug("MULTIPLE_VxLAN_TUNNELS: not found InterfaceParentEntry for {}", logicTunnelIfaceName);
441                 return futures;
442             }
443             if (ifaceAction == ADD_TUNNEL) {
444                 updateInterfaceAdminStatus(logicTunnelIfaceName, ifStateUpdated, tx);
445                 updateTunnelAggregationGroupBucket(ifStateUpdated, ifTunnel, parentRefs, groupEntry, ifaceAction, tx);
446             } else if (ifaceAction == DEL_TUNNEL) {
447                 updateTunnelAggregationGroupBucket(ifStateUpdated, ifTunnel, parentRefs, groupEntry, ifaceAction, tx);
448             }
449             updateLogicalTunnelGroupOperStatus(logicTunnelIfaceName, ifStateUpdated, groupEntry, dataBroker, tx);
450             futures.add(tx.submit());
451             return futures;
452         }
453
454         private InterfaceParentEntry getInterfaceParentEntry(String logicalGroupName) {
455             InterfaceParentEntryKey interfaceParentEntryKey = new InterfaceParentEntryKey(logicalGroupName);
456             InstanceIdentifier.InstanceIdentifierBuilder<InterfaceParentEntry> intfIdBuilder =
457                     InstanceIdentifier.builder(InterfaceChildInfo.class)
458                             .child(InterfaceParentEntry.class, interfaceParentEntryKey);
459             InstanceIdentifier<InterfaceParentEntry> intfId = intfIdBuilder.build();
460             Optional<InterfaceParentEntry> groupChildInfo =
461                     ItmUtils.read(LogicalDatastoreType.CONFIGURATION, intfId, dataBroker);
462             return groupChildInfo.isPresent() ? groupChildInfo.get() : null;
463         }
464     }
465 }