717d80f7acb298304c5ffc0c85c00c33f165f52a
[genius.git] / interfacemanager / interfacemanager-impl / src / main / java / org / opendaylight / genius / interfacemanager / listeners / InterfaceInventoryStateListener.java
1 /*
2  * Copyright (c) 2016, 2018 Ericsson India Global Services Pvt Ltd. 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 package org.opendaylight.genius.interfacemanager.listeners;
9
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
12
13 import com.google.common.base.Function;
14 import com.google.common.util.concurrent.ListenableFuture;
15
16 import com.google.common.util.concurrent.MoreExecutors;
17 import java.math.BigInteger;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.Objects;
22 import java.util.Optional;
23 import java.util.concurrent.Callable;
24 import java.util.concurrent.ExecutionException;
25 import javax.inject.Inject;
26 import javax.inject.Singleton;
27
28 import org.apache.aries.blueprint.annotation.service.Reference;
29 import org.checkerframework.checker.nullness.qual.Nullable;
30 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
31 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
32 import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
33 import org.opendaylight.genius.infra.Datastore.Configuration;
34 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
35 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
36 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
37 import org.opendaylight.genius.interfacemanager.IfmConstants;
38 import org.opendaylight.genius.interfacemanager.IfmUtil;
39 import org.opendaylight.genius.interfacemanager.InterfacemgrProvider;
40 import org.opendaylight.genius.interfacemanager.commons.AlivenessMonitorUtils;
41 import org.opendaylight.genius.interfacemanager.commons.InterfaceManagerCommonUtils;
42 import org.opendaylight.genius.interfacemanager.commons.InterfaceMetaUtils;
43 import org.opendaylight.genius.interfacemanager.recovery.impl.InterfaceServiceRecoveryHandler;
44 import org.opendaylight.genius.interfacemanager.renderer.ovs.statehelpers.OvsInterfaceStateAddHelper;
45 import org.opendaylight.genius.interfacemanager.renderer.ovs.statehelpers.OvsInterfaceStateUpdateHelper;
46 import org.opendaylight.genius.interfacemanager.servicebindings.flowbased.utilities.FlowBasedServicesUtils;
47 import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
48 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
49 import org.opendaylight.infrautils.utils.function.InterruptibleCheckedConsumer;
50 import org.opendaylight.serviceutils.srm.RecoverableListener;
51 import org.opendaylight.serviceutils.srm.ServiceRecoveryRegistry;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortReason;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info.InterfaceParentEntry;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406._interface.child.info._interface.parent.entry.InterfaceChildEntry;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
62 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66 /**
67  * This Class is a Data Change Listener for FlowCapableNodeConnector updates.
68  * This creates an entry in the interface-state OperDS for every node-connector
69  * used.
70  *
71  * <p>
72  * NOTE: This class just creates an ifstate entry whose interface-name will be
73  * the same as the node-connector portname. If PortName is not unique across
74  * DPNs, this implementation can have problems.
75  */
76 @Singleton
77 public class InterfaceInventoryStateListener
78         extends AsyncClusteredDataTreeChangeListenerBase<FlowCapableNodeConnector, InterfaceInventoryStateListener>
79         implements RecoverableListener {
80
81     private static final Logger LOG = LoggerFactory.getLogger(InterfaceInventoryStateListener.class);
82     private final DataBroker dataBroker;
83     private final ManagedNewTransactionRunner txRunner;
84     private final IdManagerService idManager;
85     private final EntityOwnershipUtils entityOwnershipUtils;
86     private final JobCoordinator coordinator;
87     private final InterfaceManagerCommonUtils interfaceManagerCommonUtils;
88     private final AlivenessMonitorUtils alivenessMonitorUtils;
89     private final OvsInterfaceStateUpdateHelper ovsInterfaceStateUpdateHelper;
90     private final OvsInterfaceStateAddHelper ovsInterfaceStateAddHelper;
91     private final InterfaceMetaUtils interfaceMetaUtils;
92     private final PortNameCache portNameCache;
93     private final InterfacemgrProvider interfacemgrProvider;
94
95     @Inject
96     public InterfaceInventoryStateListener(@Reference final DataBroker dataBroker,
97                                            final IdManagerService idManagerService,
98                                            final EntityOwnershipUtils entityOwnershipUtils,
99                                            @Reference final JobCoordinator coordinator,
100                                            final InterfaceManagerCommonUtils interfaceManagerCommonUtils,
101                                            final OvsInterfaceStateAddHelper ovsInterfaceStateAddHelper,
102                                            final OvsInterfaceStateUpdateHelper ovsInterfaceStateUpdateHelper,
103                                            final AlivenessMonitorUtils alivenessMonitorUtils,
104                                            final InterfaceMetaUtils interfaceMetaUtils,
105                                            final PortNameCache portNameCache,
106                                            final InterfaceServiceRecoveryHandler interfaceServiceRecoveryHandler,
107                                            @Reference final ServiceRecoveryRegistry serviceRecoveryRegistry,
108                                            final InterfacemgrProvider interfacemgrProvider) {
109         super(FlowCapableNodeConnector.class, InterfaceInventoryStateListener.class);
110         this.dataBroker = dataBroker;
111         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
112         this.idManager = idManagerService;
113         this.entityOwnershipUtils = entityOwnershipUtils;
114         this.coordinator = coordinator;
115         this.interfaceManagerCommonUtils = interfaceManagerCommonUtils;
116         this.alivenessMonitorUtils = alivenessMonitorUtils;
117         this.ovsInterfaceStateUpdateHelper = ovsInterfaceStateUpdateHelper;
118         this.ovsInterfaceStateAddHelper = ovsInterfaceStateAddHelper;
119         this.interfaceMetaUtils = interfaceMetaUtils;
120         this.portNameCache = portNameCache;
121         this.interfacemgrProvider = interfacemgrProvider;
122         registerListener();
123         serviceRecoveryRegistry.addRecoverableListener(interfaceServiceRecoveryHandler.buildServiceRegistryKey(),
124                 this);
125     }
126
127     @Override
128     public void registerListener() {
129         this.registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
130     }
131
132     @Override
133     protected InstanceIdentifier<FlowCapableNodeConnector> getWildCardPath() {
134         return InstanceIdentifier.create(Nodes.class).child(Node.class).child(NodeConnector.class)
135                 .augmentation(FlowCapableNodeConnector.class);
136     }
137
138     @Override
139     protected InterfaceInventoryStateListener getDataTreeChangeListener() {
140         return InterfaceInventoryStateListener.this;
141     }
142
143     @Override
144     protected void remove(InstanceIdentifier<FlowCapableNodeConnector> key,
145                           FlowCapableNodeConnector flowCapableNodeConnectorOld) {
146         String interfaceName = flowCapableNodeConnectorOld.getName();
147         if (interfacemgrProvider.isItmDirectTunnelsEnabled()
148             && InterfaceManagerCommonUtils.isTunnelPort(interfaceName)
149             && interfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceName) == null) {
150             LOG.debug("ITM Direct Tunnels is enabled, node connector removed event for"
151                     + " internal tunnel {}", interfaceName);
152             return;
153         }
154
155         if (!entityOwnershipUtils.isEntityOwner(IfmConstants.INTERFACE_CONFIG_ENTITY,
156                 IfmConstants.INTERFACE_CONFIG_ENTITY)) {
157             return;
158         }
159
160         LOG.debug("Received NodeConnector Remove Event: {}, {}", key, flowCapableNodeConnectorOld);
161         NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class))
162             .getId();
163         String portName = InterfaceManagerCommonUtils.getPortNameForInterface(nodeConnectorId,
164             flowCapableNodeConnectorOld.getName());
165
166         remove(nodeConnectorId, null, flowCapableNodeConnectorOld, portName, true);
167     }
168
169     private void remove(NodeConnectorId nodeConnectorIdNew, NodeConnectorId nodeConnectorIdOld,
170                         FlowCapableNodeConnector fcNodeConnectorNew, String portName, boolean isNetworkEvent) {
171         InterfaceStateRemoveWorker portStateRemoveWorker = new InterfaceStateRemoveWorker(idManager,
172                 nodeConnectorIdNew, nodeConnectorIdOld, fcNodeConnectorNew, portName,
173                 isNetworkEvent, true);
174         coordinator.enqueueJob(portName, portStateRemoveWorker, IfmConstants.JOB_MAX_RETRIES);
175         LOG.trace("Removing entry for port id {} from map",nodeConnectorIdNew.getValue());
176         portNameCache.remove(nodeConnectorIdNew.getValue());
177     }
178
179     @Override
180     protected void update(InstanceIdentifier<FlowCapableNodeConnector> key, FlowCapableNodeConnector fcNodeConnectorOld,
181         FlowCapableNodeConnector fcNodeConnectorNew) {
182         String interfaceName = fcNodeConnectorNew.getName();
183         if (interfacemgrProvider.isItmDirectTunnelsEnabled()
184             && InterfaceManagerCommonUtils.isTunnelPort(interfaceName)
185             && interfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceName) == null) {
186             LOG.debug("ITM Direct Tunnels is enabled, hence ignoring node connector Update event for"
187                     + " internal tunnel {}", interfaceName);
188             return;
189         }
190
191
192         if (fcNodeConnectorNew.getReason() == PortReason.Delete
193                 || !entityOwnershipUtils.isEntityOwner(IfmConstants.INTERFACE_CONFIG_ENTITY,
194                 IfmConstants.INTERFACE_CONFIG_ENTITY)) {
195             return;
196         }
197
198         LOG.debug("Received NodeConnector Update Event: {}, {}, {}", key, fcNodeConnectorOld, fcNodeConnectorNew);
199         NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class)).getId();
200         String portName = InterfaceManagerCommonUtils.getPortNameForInterface(nodeConnectorId,
201                 fcNodeConnectorNew.getName());
202
203         InterfaceStateUpdateWorker portStateUpdateWorker = new InterfaceStateUpdateWorker(key, fcNodeConnectorOld,
204             fcNodeConnectorNew, portName);
205         coordinator.enqueueJob(portName, portStateUpdateWorker, IfmConstants.JOB_MAX_RETRIES);
206     }
207
208     @Override
209     protected void add(InstanceIdentifier<FlowCapableNodeConnector> key, FlowCapableNodeConnector fcNodeConnectorNew) {
210         String interfaceName = fcNodeConnectorNew.getName();
211         if (interfacemgrProvider.isItmDirectTunnelsEnabled()
212             && InterfaceManagerCommonUtils.isTunnelPort(interfaceName)
213             && interfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceName) == null) {
214             LOG.debug("ITM Direct Tunnels is enabled, ignoring node connector add for"
215                     + " internal tunnel {}", interfaceName);
216             return;
217         }
218
219
220         if (!entityOwnershipUtils.isEntityOwner(IfmConstants.INTERFACE_CONFIG_ENTITY,
221                 IfmConstants.INTERFACE_CONFIG_ENTITY)) {
222             return;
223         }
224
225         LOG.debug("Received NodeConnector Add Event: {}, {}", key, fcNodeConnectorNew);
226         NodeConnectorId nodeConnectorId = InstanceIdentifier.keyOf(key.firstIdentifierOf(NodeConnector.class))
227             .getId();
228         LOG.trace("Adding entry for portid {} portname {} in map", nodeConnectorId.getValue(),
229                 fcNodeConnectorNew.getName());
230         portNameCache.put(nodeConnectorId.getValue(),fcNodeConnectorNew.getName());
231         String portName = InterfaceManagerCommonUtils.getPortNameForInterface(nodeConnectorId,
232             fcNodeConnectorNew.getName());
233
234         if (InterfaceManagerCommonUtils.isNovaPort(portName) || InterfaceManagerCommonUtils.isK8SPort(portName)) {
235             NodeConnectorId nodeConnectorIdOld =
236                     FlowBasedServicesUtils.getNodeConnectorIdFromInterface(portName, interfaceManagerCommonUtils);
237             if (nodeConnectorIdOld != null && !nodeConnectorId.equals(nodeConnectorIdOld)) {
238                 BigInteger dpnIdOld = IfmUtil.getDpnFromNodeConnectorId(nodeConnectorIdOld);
239                 BigInteger dpnIdNew = IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId);
240                 if (!Objects.equals(dpnIdOld, dpnIdNew)) {
241                     if (fcNodeConnectorNew.getReason() != PortReason.Add) {
242                         LOG.error("Dropping Port update event for {}, as DPN id is changed from {} to {}",
243                             fcNodeConnectorNew.getName(), dpnIdOld, dpnIdNew);
244                         return;
245                     }
246                 } else {
247                     LOG.warn("Port number update detected for {}", fcNodeConnectorNew.getName());
248                 }
249                 //VM Migration or Port Number Update: Delete existing interface entry for older DPN
250                 LOG.debug("Triggering NodeConnector Remove Event for the interface: {}, {}, {}", portName,
251                     nodeConnectorId, nodeConnectorIdOld);
252                 remove(nodeConnectorId, nodeConnectorIdOld, fcNodeConnectorNew, portName, false);
253                 // Adding a delay of 10sec for VM migration, so applications will have sufficient time
254                 // for processing remove before add
255                 try {
256                     Thread.sleep(IfmConstants.DELAY_TIME_IN_MILLISECOND);
257                 } catch (final InterruptedException e) {
258                     LOG.error("Error while waiting for the vm migration remove events to get processed");
259                 }
260             }
261         }
262
263         InterfaceStateAddWorker ifStateAddWorker = new InterfaceStateAddWorker(idManager, nodeConnectorId,
264             fcNodeConnectorNew, portName);
265         coordinator.enqueueJob(portName, ifStateAddWorker, IfmConstants.JOB_MAX_RETRIES);
266     }
267
268
269     private class InterfaceStateAddWorker implements Callable {
270         private final NodeConnectorId nodeConnectorId;
271         private final FlowCapableNodeConnector fcNodeConnectorNew;
272         private final String interfaceName;
273         private final IdManagerService idManager;
274
275         InterfaceStateAddWorker(IdManagerService idManager, NodeConnectorId nodeConnectorId,
276                                 FlowCapableNodeConnector fcNodeConnectorNew, String portName) {
277             this.nodeConnectorId = nodeConnectorId;
278             this.fcNodeConnectorNew = fcNodeConnectorNew;
279             this.interfaceName = portName;
280             this.idManager = idManager;
281         }
282
283         @Override
284         public Object call() {
285             List<ListenableFuture<Void>> futures = ovsInterfaceStateAddHelper.addState(nodeConnectorId,
286                     interfaceName, fcNodeConnectorNew);
287             List<InterfaceChildEntry> interfaceChildEntries = getInterfaceChildEntries(interfaceName);
288             for (InterfaceChildEntry interfaceChildEntry : interfaceChildEntries) {
289                 InterfaceStateAddWorker interfaceStateAddWorker = new InterfaceStateAddWorker(idManager,
290                         nodeConnectorId, fcNodeConnectorNew, interfaceChildEntry.getChildInterface());
291                 coordinator.enqueueJob(interfaceName, interfaceStateAddWorker);
292             }
293             return futures;
294         }
295
296         @Override
297         public String toString() {
298             return "InterfaceStateAddWorker{" + "nodeConnectorId=" + nodeConnectorId + ", fcNodeConnectorNew="
299                     + fcNodeConnectorNew + ", interfaceName='" + interfaceName + '\'' + '}';
300         }
301     }
302
303     private class InterfaceStateUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
304         private final InstanceIdentifier<FlowCapableNodeConnector> key;
305         private final FlowCapableNodeConnector fcNodeConnectorOld;
306         private final FlowCapableNodeConnector fcNodeConnectorNew;
307         private final String interfaceName;
308
309         InterfaceStateUpdateWorker(InstanceIdentifier<FlowCapableNodeConnector> key,
310                                    FlowCapableNodeConnector fcNodeConnectorOld,
311                                    FlowCapableNodeConnector fcNodeConnectorNew,
312                                    String portName) {
313             this.key = key;
314             this.fcNodeConnectorOld = fcNodeConnectorOld;
315             this.fcNodeConnectorNew = fcNodeConnectorNew;
316             this.interfaceName = portName;
317         }
318
319         @Override
320         public List<ListenableFuture<Void>> call() {
321             List<ListenableFuture<Void>> futures = ovsInterfaceStateUpdateHelper.updateState(
322                     interfaceName, fcNodeConnectorNew, fcNodeConnectorOld);
323             List<InterfaceChildEntry> interfaceChildEntries = getInterfaceChildEntries(interfaceName);
324             for (InterfaceChildEntry interfaceChildEntry : interfaceChildEntries) {
325                 InterfaceStateUpdateWorker interfaceStateUpdateWorker = new InterfaceStateUpdateWorker(key,
326                         fcNodeConnectorOld, fcNodeConnectorNew, interfaceChildEntry.getChildInterface());
327                 coordinator.enqueueJob(interfaceName, interfaceStateUpdateWorker);
328             }
329             return futures;
330         }
331
332         @Override
333         public String toString() {
334             return "InterfaceStateUpdateWorker{" + "key=" + key + ", fcNodeConnectorOld=" + fcNodeConnectorOld
335                     + ", fcNodeConnectorNew=" + fcNodeConnectorNew + ", interfaceName='" + interfaceName + '\'' + '}';
336         }
337     }
338
339     private class InterfaceStateRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
340         private final NodeConnectorId nodeConnectorIdNew;
341         private NodeConnectorId nodeConnectorIdOld;
342         private final FlowCapableNodeConnector fcNodeConnectorOld;
343         private final String interfaceName;
344         private final IdManagerService idManager;
345         private final boolean isNetworkEvent;
346         private final boolean isParentInterface;
347
348         InterfaceStateRemoveWorker(IdManagerService idManager, NodeConnectorId nodeConnectorIdNew,
349                                    NodeConnectorId nodeConnectorIdOld,
350                                    FlowCapableNodeConnector fcNodeConnectorOld, String interfaceName,
351                                    boolean isNetworkEvent,
352                                    boolean isParentInterface) {
353             this.nodeConnectorIdNew = nodeConnectorIdNew;
354             this.nodeConnectorIdOld = nodeConnectorIdOld;
355             this.fcNodeConnectorOld = fcNodeConnectorOld;
356             this.interfaceName = interfaceName;
357             this.idManager = idManager;
358             this.isNetworkEvent = isNetworkEvent;
359             this.isParentInterface = isParentInterface;
360         }
361
362         @Override
363         public List<ListenableFuture<Void>> call() {
364             // VM Migration: Skip OFPPR_DELETE event received after OFPPR_ADD
365             // for same interface from Older DPN
366             if (isParentInterface && isNetworkEvent) {
367                 nodeConnectorIdOld = FlowBasedServicesUtils.getNodeConnectorIdFromInterface(interfaceName,
368                         interfaceManagerCommonUtils);
369                 if (nodeConnectorIdOld != null && !nodeConnectorIdNew.equals(nodeConnectorIdOld)) {
370                     LOG.debug("Dropping the NodeConnector Remove Event for the interface: {}, {}, {}", interfaceName,
371                             nodeConnectorIdNew, nodeConnectorIdOld);
372                     return Collections.emptyList();
373                 }
374             }
375
376             List<ListenableFuture<Void>> futures = removeInterfaceStateConfiguration();
377
378             List<InterfaceChildEntry> interfaceChildEntries = getInterfaceChildEntries(interfaceName);
379             for (InterfaceChildEntry interfaceChildEntry : interfaceChildEntries) {
380                 // Fetch all interfaces on this port and trigger remove worker
381                 // for each of them
382                 InterfaceStateRemoveWorker interfaceStateRemoveWorker = new InterfaceStateRemoveWorker(idManager,
383                         nodeConnectorIdNew, nodeConnectorIdOld, fcNodeConnectorOld,
384                         interfaceChildEntry.getChildInterface(), isNetworkEvent, false);
385                 coordinator.enqueueJob(interfaceName, interfaceStateRemoveWorker);
386             }
387             return futures;
388         }
389
390         private List<ListenableFuture<Void>> removeInterfaceStateConfiguration() {
391             List<ListenableFuture<Void>> futures = new ArrayList<>();
392
393             //VM Migration: Use old nodeConnectorId to delete the interface entry
394             NodeConnectorId nodeConnectorId = nodeConnectorIdOld != null
395                     && !nodeConnectorIdNew.equals(nodeConnectorIdOld) ? nodeConnectorIdOld : nodeConnectorIdNew;
396             // delete the port entry from interface operational DS
397             BigInteger dpId = IfmUtil.getDpnFromNodeConnectorId(nodeConnectorId);
398
399             futures.add(txRunner.applyWithNewTransactionChainAndClose(txChain ->
400                 txChain.applyWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
401                     // In a genuine port delete scenario, the reason will be there in the incoming event, for all
402                     // remaining
403                     // cases treat the event as DPN disconnect, if old and new ports are same. Else, this is a VM
404                     // migration
405                     // scenario, and should be treated as port removal.
406                     LOG.debug("Removing interface state information for interface: {}", interfaceName);
407                     if (fcNodeConnectorOld.getReason() != PortReason.Delete
408                         && nodeConnectorIdNew.equals(nodeConnectorIdOld)) {
409                         //Remove event is because of connection lost between controller and switch, or switch shutdown.
410                         // Hence, don't remove the interface but set the status as "unknown"
411                         ovsInterfaceStateUpdateHelper.updateInterfaceStateOnNodeRemove(interfaceName,
412                             fcNodeConnectorOld,
413                             operTx);
414                     } else {
415                         InterfaceManagerCommonUtils.deleteStateEntry(operTx, interfaceName);
416                         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
417                             .Interface iface = interfaceManagerCommonUtils.getInterfaceFromConfigDS(interfaceName);
418
419                         if (InterfaceManagerCommonUtils.isTunnelInterface(iface)) {
420                             // If this interface is a tunnel interface, remove the tunnel ingress flow and stop LLDP
421                             // monitoring
422                             interfaceMetaUtils.removeLportTagInterfaceMap(operTx, interfaceName);
423                             return Optional.of((InterruptibleCheckedConsumer<TypedReadWriteTransaction<Configuration>,
424                                 ExecutionException>) confTx -> handleTunnelMonitoringRemoval(confTx, dpId,
425                                 iface.getName(),
426                                 iface.augmentation(IfTunnel.class)));
427                         }
428                         // remove ingress flow only for northbound configured interfaces
429                         // skip this check for non-unique ports(Ex: br-int,br-ex)
430                         if (iface != null || !interfaceName.contains(fcNodeConnectorOld.getName())) {
431                             FlowBasedServicesUtils.removeIngressFlow(interfaceName, dpId, txRunner, futures);
432                         }
433
434                         // Delete the Vpn Interface from DpnToInterface Op DS.
435                         InterfaceManagerCommonUtils.deleteDpnToInterface(dpId, interfaceName, operTx);
436                     }
437                     return Optional.empty();
438                 }).transform(new Function<Optional<?>, Void>() {
439                     @Nullable
440                     @Override
441                     public Void apply(@Nullable Optional<?> optionalJob) {
442                         if (optionalJob != null && optionalJob.isPresent()) {
443                             txChain.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
444                                 (InterruptibleCheckedConsumer<TypedReadWriteTransaction<Configuration>, ?
445                                     extends Exception>) optionalJob.get());
446                         }
447                         return null;
448                     }
449                 }, MoreExecutors.directExecutor())));
450             return futures;
451         }
452
453         private void handleTunnelMonitoringRemoval(TypedReadWriteTransaction<Configuration> tx, BigInteger dpId,
454             String removedInterfaceName, IfTunnel ifTunnel) throws ExecutionException, InterruptedException {
455             interfaceManagerCommonUtils.removeTunnelIngressFlow(tx, ifTunnel, dpId, removedInterfaceName);
456
457             IfmUtil.unbindService(txRunner, coordinator, removedInterfaceName,
458                     FlowBasedServicesUtils.buildDefaultServiceId(removedInterfaceName));
459
460             alivenessMonitorUtils.stopLLDPMonitoring(ifTunnel, removedInterfaceName);
461         }
462
463         @Override
464         public String toString() {
465             return "InterfaceStateRemoveWorker{" + "nodeConnectorIdNew=" + nodeConnectorIdNew + ", nodeConnectorIdOld="
466                     + nodeConnectorIdOld + ", fcNodeConnectorOld=" + fcNodeConnectorOld + ", interfaceName='"
467                     + interfaceName + '\'' + '}';
468         }
469     }
470
471     public List<InterfaceChildEntry> getInterfaceChildEntries(String interfaceName) {
472         InterfaceParentEntry interfaceParentEntry =
473                 interfaceMetaUtils.getInterfaceParentEntryFromConfigDS(interfaceName);
474         if (interfaceParentEntry != null && interfaceParentEntry.getInterfaceChildEntry() != null) {
475             return interfaceParentEntry.getInterfaceChildEntry();
476         }
477         return new ArrayList<>();
478     }
479 }