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