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