OF port deletion complete implementation
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / confighelpers / ItmInternalTunnelDeleteWorker.java
1 /*
2  * Copyright (c) 2016, 2017 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.itm.confighelpers;
9
10 import static java.util.Collections.singletonList;
11 import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
12
13 import com.google.common.util.concurrent.ListenableFuture;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Objects;
19 import java.util.Optional;
20 import java.util.concurrent.Callable;
21 import java.util.concurrent.ExecutionException;
22 import org.eclipse.jdt.annotation.NonNull;
23 import org.opendaylight.genius.cloudscaler.api.TombstonedNodeManager;
24 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
25 import org.opendaylight.genius.itm.cache.DpnTepStateCache;
26 import org.opendaylight.genius.itm.cache.OvsBridgeEntryCache;
27 import org.opendaylight.genius.itm.cache.OvsBridgeRefEntryCache;
28 import org.opendaylight.genius.itm.cache.TunnelStateCache;
29 import org.opendaylight.genius.itm.impl.ITMBatchingUtils;
30 import org.opendaylight.genius.itm.impl.ItmUtils;
31 import org.opendaylight.genius.itm.impl.TunnelMonitoringConfig;
32 import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
33 import org.opendaylight.genius.itm.utils.DpnTepInterfaceInfo;
34 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
35 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
36 import org.opendaylight.mdsal.binding.api.DataBroker;
37 import org.opendaylight.mdsal.binding.util.Datastore.Configuration;
38 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
39 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
40 import org.opendaylight.mdsal.binding.util.TypedReadWriteTransaction;
41 import org.opendaylight.mdsal.binding.util.TypedWriteTransaction;
42 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
43 import org.opendaylight.mdsal.common.api.ReadFailedException;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefsBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeBase;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeLldp;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeLogicalGroup;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntry;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntryKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.ovs.bridge.entry.OvsBridgeTunnelEntry;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.ovs.bridge.entry.OvsBridgeTunnelEntryKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntry;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelList;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelOperStatus;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPointsBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.tunnel.end.points.TzMembership;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.tunnel.end.points.TzMembershipKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnel;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnelKey;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
70 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
71 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
72 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
73 import org.opendaylight.yangtools.yang.common.OperationFailedException;
74 import org.opendaylight.yangtools.yang.common.Uint64;
75 import org.slf4j.Logger;
76 import org.slf4j.LoggerFactory;
77
78 public class ItmInternalTunnelDeleteWorker {
79
80     private static final Logger LOG = LoggerFactory.getLogger(ItmInternalTunnelDeleteWorker.class) ;
81
82     private final DataBroker dataBroker;
83     private final ManagedNewTransactionRunner txRunner;
84     private final JobCoordinator jobCoordinator;
85     private final TunnelMonitoringConfig tunnelMonitoringConfig;
86     private final IInterfaceManager interfaceManager;
87     private final DpnTepStateCache dpnTepStateCache;
88     private final OvsBridgeEntryCache ovsBridgeEntryCache;
89     private final OvsBridgeRefEntryCache ovsBridgeRefEntryCache;
90     private final TunnelStateCache tunnelStateCache;
91     private final DirectTunnelUtils directTunnelUtils;
92     private final TombstonedNodeManager tombstonedNodeManager;
93
94     public ItmInternalTunnelDeleteWorker(DataBroker dataBroker, JobCoordinator jobCoordinator,
95                                          TunnelMonitoringConfig tunnelMonitoringConfig,
96                                          IInterfaceManager interfaceManager, DpnTepStateCache dpnTepStateCache,
97                                          OvsBridgeEntryCache ovsBridgeEntryCache,
98                                          OvsBridgeRefEntryCache ovsBridgeRefEntryCache,
99                                          TunnelStateCache tunnelStateCache,
100                                          DirectTunnelUtils directTunnelUtils,
101                                          TombstonedNodeManager tombstonedNodeManager) {
102         this.dataBroker = dataBroker;
103         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
104         this.jobCoordinator = jobCoordinator;
105         this.tunnelMonitoringConfig = tunnelMonitoringConfig;
106         this.interfaceManager = interfaceManager;
107         this.dpnTepStateCache = dpnTepStateCache;
108         this.ovsBridgeEntryCache = ovsBridgeEntryCache;
109         this.ovsBridgeRefEntryCache = ovsBridgeRefEntryCache;
110         this.tunnelStateCache = tunnelStateCache;
111         this.directTunnelUtils = directTunnelUtils;
112         this.tombstonedNodeManager = tombstonedNodeManager;
113     }
114
115     @SuppressWarnings("checkstyle:IllegalCatch")
116     public List<? extends ListenableFuture<?>> deleteTunnels(IMdsalApiManager mdsalManager,
117             Collection<DPNTEPsInfo> dpnTepsList, Collection<DPNTEPsInfo> meshedDpnList) {
118         LOG.trace("TEPs to be deleted {} " , dpnTepsList);
119         return Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
120             if (dpnTepsList == null || dpnTepsList.size() == 0) {
121                 LOG.debug("no vtep to delete");
122                 return;
123             }
124
125             if (meshedDpnList == null || meshedDpnList.size() == 0) {
126                 LOG.debug("No Meshed Vteps");
127                 return;
128             }
129             for (DPNTEPsInfo srcDpn : dpnTepsList) {
130                 LOG.trace("Processing srcDpn {}", srcDpn);
131                 List<TunnelEndPoints> meshedEndPtCache = ItmUtils.getTEPsForDpn(srcDpn.getDPNID(), meshedDpnList);
132                 if (meshedEndPtCache == null) {
133                     LOG.debug("No Tunnel End Point configured for this DPN {}", srcDpn.getDPNID());
134                     continue;
135                 }
136                 LOG.debug("Entries in meshEndPointCache {} for DPN Id{} ", meshedEndPtCache.size(), srcDpn.getDPNID());
137                 for (TunnelEndPoints srcTep : srcDpn.nonnullTunnelEndPoints()) {
138                     LOG.trace("Processing srcTep {}", srcTep);
139                     Boolean isDpnTombstoned = tombstonedNodeManager.isDpnTombstoned(srcDpn.getDPNID());
140                     @NonNull Map<TzMembershipKey, TzMembership> srcTZones = srcTep.nonnullTzMembership();
141                     boolean tepDeleteFlag = false;
142                     // First, take care of tunnel removal, so run through all other DPNS other than srcDpn
143                     // In the tep received from Delete DCN, the membership list will always be 1
144                     // as the DCN is at transport zone level
145                     // Hence if a tunnel is shared across TZs, compare the original membership list between end points
146                     // to decide if tunnel to be deleted.
147                     for (DPNTEPsInfo dstDpn : meshedDpnList) {
148                         if (!Objects.equals(srcDpn.getDPNID(), dstDpn.getDPNID())) {
149                             for (TunnelEndPoints dstTep : dstDpn.nonnullTunnelEndPoints()) {
150                                 if (!ItmUtils.getIntersection(dstTep.nonnullTzMembership(), srcTZones).isEmpty()) {
151                                     Map<TzMembershipKey, TzMembership> originalTzMembership =
152                                             ItmUtils.getOriginalTzMembership(srcTep, srcDpn.getDPNID(), meshedDpnList);
153                                     if (ItmUtils.getIntersection(dstTep.getTzMembership(),
154                                             originalTzMembership).size() == 1) {
155                                         if (interfaceManager.isItmDirectTunnelsEnabled()) {
156                                             if (checkIfTepInterfaceExists(dstDpn.getDPNID(), srcDpn.getDPNID())) {
157                                                 // remove all trunk interfaces
158                                                 LOG.trace("Invoking removeTrunkInterface between source TEP {} , "
159                                                         + "Destination TEP {} " ,srcTep , dstTep);
160                                                 removeTunnelInterfaceFromOvsdb(tx, srcTep, dstTep, srcDpn.getDPNID(),
161                                                         dstDpn.getDPNID());
162                                                 if (isDpnTombstoned) {
163                                                     LOG.trace("Removing tunnelState entry for {} while tombstoned "
164                                                             + "is set {}", srcDpn.getDPNID(), isDpnTombstoned);
165                                                     removeTunnelState(srcTep,dstTep);
166                                                 }
167                                             }
168                                         } else {
169                                             if (checkIfTrunkExists(dstDpn.getDPNID(), srcDpn.getDPNID(),
170                                                 srcTep.getTunnelType(), dataBroker)) {
171                                                 // remove all trunk interfaces
172                                                 LOG.trace("Invoking removeTrunkInterface between source TEP {} , "
173                                                         + "Destination TEP {} ", srcTep, dstTep);
174                                                 removeTrunkInterface(tx, srcTep, dstTep, srcDpn.getDPNID(),
175                                                         dstDpn.getDPNID());
176                                             }
177                                         }
178                                     }
179                                 }
180                             }
181                         }
182                     }
183
184                     for (DPNTEPsInfo dstDpn : meshedDpnList) {
185                         // Second, take care of Tep TZ membership and identify if tep can be removed
186                         if (Objects.equals(srcDpn.getDPNID(), dstDpn.getDPNID())) {
187                             // Same DPN, so remove the TZ membership
188                             for (TunnelEndPoints dstTep : dstDpn.nonnullTunnelEndPoints()) {
189                                 if (Objects.equals(dstTep.getIpAddress(), srcTep.getIpAddress())) {
190                                     // Remove the deleted TZ membership from the TEP
191                                     LOG.debug("Removing TZ list {} from Existing TZ list {} ", srcTZones,
192                                             dstTep.getTzMembership());
193                                     List<TzMembership> updatedList =
194                                             ItmUtils.removeTransportZoneMembership(dstTep, srcTZones);
195                                     if (updatedList.isEmpty()) {
196                                         LOG.debug(" This TEP can be deleted {}", srcTep);
197                                         tepDeleteFlag = true;
198                                     } else {
199                                         TunnelEndPointsBuilder modifiedTepBld = new TunnelEndPointsBuilder(dstTep);
200                                         modifiedTepBld.setTzMembership(updatedList);
201                                         TunnelEndPoints modifiedTep = modifiedTepBld.build() ;
202                                         InstanceIdentifier<TunnelEndPoints> tepPath = InstanceIdentifier
203                                                 .builder(DpnEndpoints.class)
204                                                 .child(DPNTEPsInfo.class, dstDpn.key())
205                                                 .child(TunnelEndPoints.class, dstTep.key()).build();
206
207                                         LOG.debug(" Store the modified Tep in DS {} ", modifiedTep);
208                                         tx.put(tepPath, modifiedTep);
209                                     }
210                                 }
211                             }
212                         }
213                     }
214                     if (tepDeleteFlag) {
215                         // Third, removing vtep / dpn from Tunnels OpDs.
216                         InstanceIdentifier<TunnelEndPoints> tepPath =
217                                 InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, srcDpn.key())
218                                         .child(TunnelEndPoints.class, srcTep.key()).build();
219
220                         LOG.trace("Tep Removal of TEP {} from DPNTEPSINFO CONFIG DS with Key {} ", srcTep,
221                                 srcTep.key());
222                         tx.delete(tepPath);
223                         // remove the tep from the cache
224                         meshedEndPtCache.remove(srcTep);
225                         Class<? extends TunnelMonitoringTypeBase> monitorProtocol =
226                                 tunnelMonitoringConfig.getMonitorProtocol();
227                         InstanceIdentifier<DPNTEPsInfo> dpnPath =
228                                 InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, srcDpn.key())
229                                         .build();
230
231                         if (meshedEndPtCache.isEmpty()) {
232                             // remove dpn if no vteps exist on dpn
233                             if (monitorProtocol.isAssignableFrom(TunnelMonitoringTypeLldp.class)) {
234                                 LOG.debug("Removing Terminating Service Table Flow ");
235                                 ItmUtils.removeTerminatingServiceTable(tx, srcDpn.getDPNID(), mdsalManager);
236                             }
237                             LOG.trace("DPN Removal from DPNTEPSINFO CONFIG DS {}", srcDpn.getDPNID());
238                             tx.delete(dpnPath);
239                             InstanceIdentifier<DpnEndpoints> tnlContainerPath =
240                                     InstanceIdentifier.builder(DpnEndpoints.class).build();
241                             Optional<DpnEndpoints> containerOptional = tx.read(tnlContainerPath).get();
242                             // remove container if no DPNs are present
243                             if (containerOptional.isPresent()) {
244                                 DpnEndpoints deps = containerOptional.get();
245                                 if (deps.getDPNTEPsInfo() == null || deps.getDPNTEPsInfo().isEmpty()) {
246                                     LOG.trace("Container Removal from DPNTEPSINFO CONFIG DS");
247                                     tx.delete(tnlContainerPath);
248                                 }
249                             }
250                         }
251                     }
252                     if (interfaceManager.isItmDirectTunnelsEnabled()) {
253                         // SF419 Remove the DPNSTEPs DS
254                         LOG.debug("Deleting TEP Interface information from Config datastore with DPNs-Teps "
255                                 + "for source Dpn {}", srcDpn.getDPNID());
256                         // Clean up the DPN TEPs State DS
257                         dpnTepStateCache.removeTepFromDpnTepInterfaceConfigDS(srcDpn.getDPNID());
258                     }
259                 }
260             }
261         }));
262     }
263
264     private void removeTrunkInterface(TypedWriteTransaction<Configuration> tx, TunnelEndPoints srcTep,
265             TunnelEndPoints dstTep, Uint64 srcDpnId, Uint64 dstDpnId) {
266         String trunkfwdIfName = ItmUtils.getTrunkInterfaceName(srcTep.getInterfaceName(),
267                 srcTep.getIpAddress().stringValue(),
268                 dstTep.getIpAddress().stringValue(),
269                 srcTep.getTunnelType().getName());
270         LOG.trace("Removing forward Trunk Interface {}" , trunkfwdIfName);
271         InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(trunkfwdIfName);
272         LOG.debug(" Removing Trunk Interface Name - {} , Id - {} from Config DS ",
273                 trunkfwdIfName, trunkIdentifier) ;
274         tx.delete(trunkIdentifier);
275         ItmUtils.ITM_CACHE.removeInterface(trunkfwdIfName);
276         // also update itm-state ds -- Delete the forward tunnel-interface from the tunnel list
277         InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(TunnelList.class)
278                 .child(InternalTunnel.class, new InternalTunnelKey(dstDpnId, srcDpnId, srcTep.getTunnelType()));
279         tx.delete(path) ;
280         ItmUtils.ITM_CACHE.removeInternalTunnel(trunkfwdIfName);
281         // Release the Ids for the forward trunk interface Name
282         ItmUtils.releaseIdForTrunkInterfaceName(srcTep.getInterfaceName(),
283                 srcTep.getIpAddress().stringValue(),
284                 dstTep.getIpAddress().stringValue(),
285                 srcTep.getTunnelType().getName());
286         removeLogicalGroupTunnel(srcDpnId, dstDpnId);
287
288         String trunkRevIfName = ItmUtils.getTrunkInterfaceName(dstTep.getInterfaceName(),
289                 dstTep.getIpAddress().stringValue(),
290                 srcTep.getIpAddress().stringValue(),
291                 srcTep.getTunnelType().getName());
292         LOG.trace("Removing Reverse Trunk Interface {}", trunkRevIfName);
293         trunkIdentifier = ItmUtils.buildId(trunkRevIfName);
294         LOG.debug(" Removing Trunk Interface Name - {} , Id - {} from Config DS ",
295                 trunkRevIfName, trunkIdentifier) ;
296         tx.delete(trunkIdentifier);
297         ItmUtils.ITM_CACHE.removeInternalTunnel(trunkRevIfName);
298         // also update itm-state ds -- Delete the reverse tunnel-interface from the tunnel list
299         path = InstanceIdentifier.create(TunnelList.class)
300                 .child(InternalTunnel.class, new InternalTunnelKey(srcDpnId, dstDpnId, dstTep.getTunnelType()));
301         tx.delete(path) ;
302
303         // Release the Ids for the reverse trunk interface Name
304         ItmUtils.releaseIdForTrunkInterfaceName(dstTep.getInterfaceName(),
305                 dstTep.getIpAddress().stringValue(),
306                 srcTep.getIpAddress().stringValue(),
307                 dstTep.getTunnelType().getName());
308         removeLogicalGroupTunnel(dstDpnId, srcDpnId);
309     }
310
311     private static boolean checkIfTrunkExists(Uint64 srcDpnId, Uint64 dstDpnId,
312                                               Class<? extends TunnelTypeBase> tunType, DataBroker dataBroker) {
313         InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(TunnelList.class)
314                 .child(InternalTunnel.class, new InternalTunnelKey(dstDpnId, srcDpnId, tunType));
315         return ItmUtils.read(LogicalDatastoreType.CONFIGURATION,path, dataBroker).isPresent();
316     }
317
318     private void removeLogicalGroupTunnel(Uint64 srcDpnId, Uint64 dstDpnId) {
319         boolean tunnelAggregationEnabled = ItmTunnelAggregationHelper.isTunnelAggregationEnabled();
320         if (!tunnelAggregationEnabled) {
321             return;
322         }
323         String logicTunnelName = ItmUtils.getLogicalTunnelGroupName(srcDpnId, dstDpnId);
324         ItmTunnelAggregationDeleteWorker addWorker =
325                 new ItmTunnelAggregationDeleteWorker(logicTunnelName, srcDpnId, dstDpnId, dataBroker);
326         jobCoordinator.enqueueJob(logicTunnelName, addWorker);
327     }
328
329     private static class ItmTunnelAggregationDeleteWorker implements Callable<List<? extends ListenableFuture<?>>> {
330
331         private final String logicTunnelName;
332         private final Uint64 srcDpnId;
333         private final Uint64 dstDpnId;
334         private final ManagedNewTransactionRunner txRunner;
335
336         ItmTunnelAggregationDeleteWorker(String groupName, Uint64 srcDpnId, Uint64 dstDpnId, DataBroker db) {
337             this.logicTunnelName = groupName;
338             this.srcDpnId = srcDpnId;
339             this.dstDpnId = dstDpnId;
340             this.txRunner = new ManagedNewTransactionRunnerImpl(db);
341         }
342
343         @Override
344         public List<? extends ListenableFuture<?>> call() {
345             Collection<InternalTunnel> tunnels = ItmUtils.ITM_CACHE.getAllInternalTunnel();
346
347             //The logical tunnel interface be removed only when the last tunnel interface on each OVS is deleted
348             boolean emptyTunnelGroup = true;
349             boolean foundLogicGroupIface = false;
350             for (InternalTunnel tunl : tunnels) {
351                 if (Objects.equals(tunl.getSourceDPN(), srcDpnId) && Objects.equals(tunl.getDestinationDPN(),
352                         dstDpnId)) {
353                     if (tunl.getTransportType() != null && tunl.getTransportType().isAssignableFrom(
354                             TunnelTypeVxlan.class)
355                             && tunl.getTunnelInterfaceNames() != null && !tunl.getTunnelInterfaceNames().isEmpty()) {
356                         emptyTunnelGroup = false;
357                         break;
358                     } else if (tunl.getTransportType() != null && tunl.getTransportType().isAssignableFrom(
359                             TunnelTypeLogicalGroup.class)) {
360                         foundLogicGroupIface = true;
361                     }
362                 }
363             }
364             if (emptyTunnelGroup && foundLogicGroupIface) {
365                 return singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
366                     LOG.debug("MULTIPLE_VxLAN_TUNNELS: remove the logical tunnel group {} because a last tunnel"
367                         + " interface on srcDpnId {} dstDpnId {} is removed", logicTunnelName, srcDpnId, dstDpnId);
368                     InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(logicTunnelName);
369                     tx.delete(trunkIdentifier);
370                     ItmUtils.ITM_CACHE.removeInterface(logicTunnelName);
371                     InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(TunnelList.class)
372                             .child(InternalTunnel.class,
373                                     new InternalTunnelKey(dstDpnId, srcDpnId, TunnelTypeLogicalGroup.class));
374                     tx.delete(path);
375                     ItmUtils.ITM_CACHE.removeInternalTunnel(logicTunnelName);
376                 }));
377             } else if (!emptyTunnelGroup) {
378                 LOG.debug("MULTIPLE_VxLAN_TUNNELS: not last tunnel in logical tunnel group {}", logicTunnelName);
379             }
380             return Collections.emptyList();
381         }
382     }
383
384     private void removeTunnelInterfaceFromOvsdb(TypedReadWriteTransaction<Configuration> tx, TunnelEndPoints srcTep,
385         TunnelEndPoints dstTep, Uint64 srcDpnId, Uint64 dstDpnId) {
386         String trunkfwdIfName = ItmUtils.getTrunkInterfaceName(srcTep.getInterfaceName(),
387                 srcTep.getIpAddress().getIpv4Address().getValue(),
388                 dstTep.getIpAddress().getIpv4Address().getValue(),
389                 srcTep.getTunnelType().getName());
390         LOG.trace("Removing forward Trunk Interface {}", trunkfwdIfName);
391         ParentRefs parentRefs = new ParentRefsBuilder().setDatapathNodeIdentifier(srcDpnId).build();
392         Interface iface = dpnTepStateCache.getInterfaceFromCache(trunkfwdIfName);
393         // ITM DIRECT TUNNELS -- Call the OVS Worker directly
394         if (iface != null) {
395             try {
396                 removeConfiguration(tx, iface, parentRefs);
397             } catch (ExecutionException | InterruptedException | OperationFailedException e) {
398                 LOG.error("Cannot Delete Tunnel {} as OVS Bridge Entry is NULL ", iface.getName(), e);
399             }
400         }
401         String trunkRevIfName = ItmUtils.getTrunkInterfaceName(dstTep.getInterfaceName(),
402                 dstTep.getIpAddress().getIpv4Address().getValue(),
403                 srcTep.getIpAddress().getIpv4Address().getValue(),
404                 srcTep.getTunnelType().getName());
405         parentRefs = new ParentRefsBuilder().setDatapathNodeIdentifier(dstDpnId).build();
406         iface = dpnTepStateCache.getInterfaceFromCache(trunkRevIfName);
407
408         if (iface != null) {
409             try {
410                 LOG.trace("Removing Reverse Trunk Interface {}", trunkRevIfName);
411                 removeConfiguration(tx, iface, parentRefs);
412             } catch (ExecutionException | InterruptedException | OperationFailedException e) {
413                 LOG.error("Cannot Delete Tunnel {} as OVS Bridge Entry is NULL ", iface.getName(), e);
414             }
415         }
416     }
417
418     private void removeTunnelState(TunnelEndPoints srcTep, TunnelEndPoints dstTep) {
419         String trunkfwdIfName = ItmUtils.getTrunkInterfaceName(srcTep.getInterfaceName(),
420                 srcTep.getIpAddress().getIpv4Address().getValue(),
421                 dstTep.getIpAddress().getIpv4Address().getValue(),
422                 srcTep.getTunnelType().getName());
423         LOG.trace("Removing tunnelstate for {}", trunkfwdIfName);
424         directTunnelUtils.deleteTunnelStateEntry(trunkfwdIfName);
425
426         String trunkRevIfName = ItmUtils.getTrunkInterfaceName(dstTep.getInterfaceName(),
427                 dstTep.getIpAddress().getIpv4Address().getValue(),
428                 srcTep.getIpAddress().getIpv4Address().getValue(),
429                 srcTep.getTunnelType().getName());
430         LOG.trace("Removing tunnelstate for {}", trunkRevIfName);
431         directTunnelUtils.deleteTunnelStateEntry(trunkRevIfName);
432     }
433
434     private boolean checkIfTepInterfaceExists(Uint64 srcDpnId, Uint64 dstDpnId) {
435         DpnTepInterfaceInfo dpnTepInterfaceInfo = dpnTepStateCache.getDpnTepInterface(srcDpnId, dstDpnId);
436         if (dpnTepInterfaceInfo != null) {
437             return dpnTepInterfaceInfo.getTunnelName() != null;
438         }
439         return false;
440     }
441
442     private void removeConfiguration(TypedReadWriteTransaction<Configuration> tx, Interface interfaceOld,
443             ParentRefs parentRefs) throws ExecutionException, InterruptedException, OperationFailedException {
444         IfTunnel ifTunnel = interfaceOld.augmentation(IfTunnel.class);
445         if (ifTunnel != null) {
446             // Check if the same transaction can be used across Config and operational shards
447             removeTunnelConfiguration(tx, parentRefs, interfaceOld.getName(), ifTunnel);
448         }
449     }
450
451     private void removeTunnelConfiguration(TypedReadWriteTransaction<Configuration> tx, ParentRefs parentRefs,
452         String interfaceName, IfTunnel ifTunnel)
453             throws ExecutionException, InterruptedException, OperationFailedException {
454
455         LOG.info("removing tunnel configuration for {}", interfaceName);
456         Uint64 dpId = null;
457         if (parentRefs != null) {
458             dpId = parentRefs.getDatapathNodeIdentifier();
459         }
460
461         if (dpId == null) {
462             return;
463         }
464
465         Optional<OvsBridgeRefEntry> ovsBridgeRefEntryOptional = ovsBridgeRefEntryCache.get(dpId);
466         Optional<OvsBridgeEntry> ovsBridgeEntryOptional;
467         OvsdbBridgeRef ovsdbBridgeRef = null;
468         if (ovsBridgeRefEntryOptional.isPresent()) {
469             ovsdbBridgeRef = ovsBridgeRefEntryOptional.get().getOvsBridgeReference();
470         } else {
471             ovsBridgeEntryOptional = ovsBridgeEntryCache.get(dpId);
472             if (ovsBridgeEntryOptional.isPresent()) {
473                 ovsdbBridgeRef = ovsBridgeEntryOptional.get().getOvsBridgeReference();
474             }
475         }
476
477         if (ovsdbBridgeRef != null) {
478             removeTerminationEndPoint(ovsdbBridgeRef.getValue(), interfaceName);
479         }
480         removeTunnelIngressFlow(tx, interfaceName, dpId);
481
482         // delete bridge to tunnel interface mappings
483         OvsBridgeEntryKey bridgeEntryKey = new OvsBridgeEntryKey(dpId);
484         InstanceIdentifier<OvsBridgeEntry> bridgeEntryIid =
485                 DirectTunnelUtils.getOvsBridgeEntryIdentifier(bridgeEntryKey);
486         ovsBridgeEntryOptional = ovsBridgeEntryCache.get(dpId);
487
488
489         if (ovsBridgeEntryOptional.isPresent()) {
490             @NonNull Map<OvsBridgeTunnelEntryKey, OvsBridgeTunnelEntry> bridgeTunnelEntries =
491                     ovsBridgeEntryOptional.get().nonnullOvsBridgeTunnelEntry();
492
493             deleteBridgeInterfaceEntry(bridgeEntryKey, bridgeTunnelEntries, bridgeEntryIid, interfaceName);
494             // IfIndex needs to be removed only during State Clean up not Config
495             cleanUpInterfaceWithUnknownState(interfaceName, parentRefs, ifTunnel);
496             directTunnelUtils.removeLportTagInterfaceMap(interfaceName);
497         }
498     }
499
500     private void removeTerminationEndPoint(InstanceIdentifier<?> bridgeIid, String interfaceName) {
501         LOG.debug("removing termination point for {}", interfaceName);
502         InstanceIdentifier<TerminationPoint> tpIid = DirectTunnelUtils.createTerminationPointInstanceIdentifier(
503                 InstanceIdentifier.keyOf(bridgeIid.firstIdentifierOf(Node.class)), interfaceName);
504         ITMBatchingUtils.delete(tpIid, ITMBatchingUtils.EntityType.TOPOLOGY_CONFIG);
505     }
506
507     private void removeTunnelIngressFlow(TypedReadWriteTransaction<Configuration> tx, String interfaceName,
508             Uint64 dpId) throws ExecutionException, InterruptedException {
509         directTunnelUtils.removeTunnelIngressFlow(tx, dpId, interfaceName);
510     }
511
512     // if the node is shutdown, there will be stale interface state entries,
513     // with unknown op-state, clear them.
514     private void cleanUpInterfaceWithUnknownState(String interfaceName, ParentRefs parentRefs, IfTunnel ifTunnel)
515         throws ReadFailedException {
516         Optional<StateTunnelList> stateTunnelList =
517                 tunnelStateCache.get(tunnelStateCache.getStateTunnelListIdentifier(interfaceName));
518         if (stateTunnelList.isPresent() && stateTunnelList.get().getOperState() == TunnelOperStatus.Unknown) {
519             String staleInterface = ifTunnel != null ? interfaceName : parentRefs.getParentInterface();
520             LOG.debug("cleaning up parent-interface for {}, since the oper-status is UNKNOWN", interfaceName);
521             directTunnelUtils.deleteTunnelStateEntry(staleInterface);
522         }
523     }
524
525     private void deleteBridgeInterfaceEntry(OvsBridgeEntryKey bridgeEntryKey,
526                                             Map<OvsBridgeTunnelEntryKey, OvsBridgeTunnelEntry> bridgeTunnelEntries,
527                                             InstanceIdentifier<OvsBridgeEntry> bridgeEntryIid,
528                                             String interfaceName) {
529         OvsBridgeTunnelEntryKey bridgeTunnelEntryKey = new OvsBridgeTunnelEntryKey(interfaceName);
530         InstanceIdentifier<OvsBridgeTunnelEntry> bridgeTunnelEntryIid =
531                 DirectTunnelUtils.getBridgeTunnelEntryIdentifier(bridgeEntryKey, bridgeTunnelEntryKey);
532         ITMBatchingUtils.delete(bridgeTunnelEntryIid, ITMBatchingUtils.EntityType.DEFAULT_CONFIG);
533         if (bridgeTunnelEntries.size() <= 1) {
534             ITMBatchingUtils.delete(bridgeEntryIid, ITMBatchingUtils.EntityType.DEFAULT_CONFIG);
535         }
536     }
537 }