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