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