Add MDSALManager exceptions and missing methods
[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.base.Optional;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import java.math.BigInteger;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.concurrent.Callable;
20 import java.util.concurrent.ExecutionException;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
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.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.OvsBridgeEntryCache;
32 import org.opendaylight.genius.itm.cache.OvsBridgeRefEntryCache;
33 import org.opendaylight.genius.itm.cache.TunnelStateCache;
34 import org.opendaylight.genius.itm.impl.ITMBatchingUtils;
35 import org.opendaylight.genius.itm.impl.ItmUtils;
36 import org.opendaylight.genius.itm.impl.TunnelMonitoringConfig;
37 import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
38 import org.opendaylight.genius.itm.utils.DpnTepInterfaceInfo;
39 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
40 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefsBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeBase;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeLldp;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeLogicalGroup;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntry;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.OvsBridgeEntryKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.ovs.bridge.entry.OvsBridgeTunnelEntry;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.bridge.tunnel.info.ovs.bridge.entry.OvsBridgeTunnelEntryKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.meta.rev171210.ovs.bridge.ref.info.OvsBridgeRefEntry;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelList;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelOperStatus;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPointsBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.tunnel.end.points.TzMembership;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnel;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnelKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
66 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
67 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
68 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
69 import org.opendaylight.yangtools.yang.common.OperationFailedException;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
72
73 public class ItmInternalTunnelDeleteWorker {
74
75     private static final Logger LOG = LoggerFactory.getLogger(ItmInternalTunnelDeleteWorker.class) ;
76
77     private final DataBroker dataBroker;
78     private final ManagedNewTransactionRunner txRunner;
79     private final JobCoordinator jobCoordinator;
80     private final TunnelMonitoringConfig tunnelMonitoringConfig;
81     private final IInterfaceManager interfaceManager;
82     private final DpnTepStateCache dpnTepStateCache;
83     private final OvsBridgeEntryCache ovsBridgeEntryCache;
84     private final OvsBridgeRefEntryCache ovsBridgeRefEntryCache;
85     private final TunnelStateCache tunnelStateCache;
86     private final DirectTunnelUtils directTunnelUtils;
87
88     public ItmInternalTunnelDeleteWorker(DataBroker dataBroker, JobCoordinator jobCoordinator,
89                                          TunnelMonitoringConfig tunnelMonitoringConfig,
90                                          IInterfaceManager interfaceManager, DpnTepStateCache dpnTepStateCache,
91                                          OvsBridgeEntryCache ovsBridgeEntryCache,
92                                          OvsBridgeRefEntryCache ovsBridgeRefEntryCache,
93                                          TunnelStateCache tunnelStateCache,
94                                          DirectTunnelUtils directTunnelUtils) {
95         this.dataBroker = dataBroker;
96         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
97         this.jobCoordinator = jobCoordinator;
98         this.tunnelMonitoringConfig = tunnelMonitoringConfig;
99         this.interfaceManager = interfaceManager;
100         this.dpnTepStateCache = dpnTepStateCache;
101         this.ovsBridgeEntryCache = ovsBridgeEntryCache;
102         this.ovsBridgeRefEntryCache = ovsBridgeRefEntryCache;
103         this.tunnelStateCache = tunnelStateCache;
104         this.directTunnelUtils = directTunnelUtils;
105     }
106
107     @SuppressWarnings("checkstyle:IllegalCatch")
108     public List<ListenableFuture<Void>> deleteTunnels(IMdsalApiManager mdsalManager,
109             Collection<DPNTEPsInfo> dpnTepsList, Collection<DPNTEPsInfo> meshedDpnList) {
110         LOG.trace("TEPs to be deleted {} " , dpnTepsList);
111         return Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
112             if (dpnTepsList == null || dpnTepsList.size() == 0) {
113                 LOG.debug("no vtep to delete");
114                 return;
115             }
116
117             if (meshedDpnList == null || meshedDpnList.size() == 0) {
118                 LOG.debug("No Meshed Vteps");
119                 return;
120             }
121             for (DPNTEPsInfo srcDpn : dpnTepsList) {
122                 LOG.trace("Processing srcDpn {}", srcDpn);
123
124                 List<TunnelEndPoints> meshedEndPtCache = ItmUtils.getTEPsForDpn(srcDpn.getDPNID(), meshedDpnList);
125                 if (meshedEndPtCache == null) {
126                     LOG.debug("No Tunnel End Point configured for this DPN {}", srcDpn.getDPNID());
127                     continue;
128                 }
129                 LOG.debug("Entries in meshEndPointCache {} for DPN Id{} ", meshedEndPtCache.size(), srcDpn.getDPNID());
130                 for (TunnelEndPoints srcTep : srcDpn.getTunnelEndPoints()) {
131                     LOG.trace("Processing srcTep {}", srcTep);
132                     List<TzMembership> srcTZones = srcTep.getTzMembership();
133                     boolean tepDeleteFlag = false;
134                     // First, take care of tunnel removal, so run through all other DPNS other than srcDpn
135                     // In the tep received from Delete DCN, the membership list will always be 1
136                     // as the DCN is at transport zone level
137                     // Hence if a tunnel is shared across TZs, compare the original membership list between end points
138                     // to decide if tunnel to be deleted.
139                     for (DPNTEPsInfo dstDpn : meshedDpnList) {
140                         if (!srcDpn.getDPNID().equals(dstDpn.getDPNID())) {
141                             for (TunnelEndPoints dstTep : dstDpn.getTunnelEndPoints()) {
142                                 if (!ItmUtils.getIntersection(dstTep.getTzMembership(), srcTZones).isEmpty()) {
143                                     List<TzMembership> originalTzMembership =
144                                             ItmUtils.getOriginalTzMembership(srcTep, srcDpn.getDPNID(), meshedDpnList);
145                                     if (ItmUtils.getIntersection(dstTep.getTzMembership(),
146                                             originalTzMembership).size() == 1) {
147                                         if (interfaceManager.isItmDirectTunnelsEnabled()) {
148                                             if (checkIfTepInterfaceExists(dstDpn.getDPNID(), srcDpn.getDPNID())) {
149                                                 // remove all trunk interfaces
150                                                 LOG.trace("Invoking removeTrunkInterface between source TEP {} , "
151                                                         + "Destination TEP {} " ,srcTep , dstTep);
152                                                 removeTunnelInterfaceFromOvsdb(tx, srcTep, dstTep, srcDpn.getDPNID(),
153                                                         dstDpn.getDPNID());
154
155                                             }
156
157                                         } else {
158                                             if (checkIfTrunkExists(dstDpn.getDPNID(), srcDpn.getDPNID(),
159                                                     srcTep.getTunnelType(), dataBroker)) {
160                                                 // remove all trunk interfaces
161                                                 LOG.trace("Invoking removeTrunkInterface between source TEP {} , "
162                                                         + "Destination TEP {} ", srcTep, dstTep);
163                                                 removeTrunkInterface(tx, srcTep, dstTep, srcDpn.getDPNID(),
164                                                         dstDpn.getDPNID());
165                                             }
166                                         }
167                                     }
168                                 }
169                             }
170                         }
171                     }
172                     for (DPNTEPsInfo dstDpn : meshedDpnList) {
173                         // Second, take care of Tep TZ membership and identify if tep can be removed
174                         if (srcDpn.getDPNID().equals(dstDpn.getDPNID())) {
175                             // Same DPN, so remove the TZ membership
176                             for (TunnelEndPoints dstTep : dstDpn.getTunnelEndPoints()) {
177                                 if (dstTep.getIpAddress().equals(srcTep.getIpAddress())) {
178                                     // Remove the deleted TZ membership from the TEP
179                                     LOG.debug("Removing TZ list {} from Existing TZ list {} ", srcTZones,
180                                             dstTep.getTzMembership());
181                                     List<TzMembership> updatedList =
182                                             ItmUtils.removeTransportZoneMembership(dstTep, srcTZones);
183                                     if (updatedList.isEmpty()) {
184                                         LOG.debug(" This TEP can be deleted {}", srcTep);
185                                         tepDeleteFlag = true;
186                                     } else {
187                                         TunnelEndPointsBuilder modifiedTepBld = new TunnelEndPointsBuilder(dstTep);
188                                         modifiedTepBld.setTzMembership(updatedList);
189                                         TunnelEndPoints modifiedTep = modifiedTepBld.build() ;
190                                         InstanceIdentifier<TunnelEndPoints> tepPath = InstanceIdentifier
191                                                 .builder(DpnEndpoints.class)
192                                                 .child(DPNTEPsInfo.class, dstDpn.key())
193                                                 .child(TunnelEndPoints.class, dstTep.key()).build();
194
195                                         LOG.debug(" Store the modified Tep in DS {} ", modifiedTep);
196                                         tx.put(tepPath, modifiedTep);
197                                     }
198                                 }
199                             }
200                         }
201                     }
202                     if (tepDeleteFlag) {
203                         // Third, removing vtep / dpn from Tunnels OpDs.
204                         InstanceIdentifier<TunnelEndPoints> tepPath =
205                                 InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, srcDpn.key())
206                                         .child(TunnelEndPoints.class, srcTep.key()).build();
207
208                         LOG.trace("Tep Removal of TEP {} from DPNTEPSINFO CONFIG DS with Key {} ", srcTep,
209                                 srcTep.key());
210                         tx.delete(tepPath);
211                         // remove the tep from the cache
212                         meshedEndPtCache.remove(srcTep);
213                         Class<? extends TunnelMonitoringTypeBase> monitorProtocol =
214                                 tunnelMonitoringConfig.getMonitorProtocol();
215                         InstanceIdentifier<DPNTEPsInfo> dpnPath =
216                                 InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, srcDpn.key())
217                                         .build();
218
219                         if (meshedEndPtCache.isEmpty()) {
220                             // remove dpn if no vteps exist on dpn
221                             if (monitorProtocol.isAssignableFrom(TunnelMonitoringTypeLldp.class)) {
222                                 LOG.debug("Removing Terminating Service Table Flow ");
223                                 ItmUtils.removeTerminatingServiceTable(tx, srcDpn.getDPNID(), mdsalManager);
224                             }
225                             LOG.trace("DPN Removal from DPNTEPSINFO CONFIG DS {}", srcDpn.getDPNID());
226                             tx.delete(dpnPath);
227                             InstanceIdentifier<DpnEndpoints> tnlContainerPath =
228                                     InstanceIdentifier.builder(DpnEndpoints.class).build();
229                             Optional<DpnEndpoints> containerOptional = tx.read(tnlContainerPath).get();
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                                     tx.delete(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(TypedWriteTransaction<Configuration> tx, TunnelEndPoints srcTep,
253         TunnelEndPoints dstTep, BigInteger srcDpnId, BigInteger dstDpnId) {
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         tx.delete(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         tx.delete(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         tx.delete(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         tx.delete(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() {
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(TypedReadWriteTransaction<Configuration> tx, TunnelEndPoints srcTep,
370         TunnelEndPoints dstTep, BigInteger srcDpnId, BigInteger dstDpnId) {
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(tx, iface, parentRefs);
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(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     }
402
403     private boolean checkIfTepInterfaceExists(BigInteger srcDpnId, BigInteger dstDpnId) {
404         DpnTepInterfaceInfo dpnTepInterfaceInfo = dpnTepStateCache.getDpnTepInterface(srcDpnId,dstDpnId);
405         if (dpnTepInterfaceInfo != null) {
406             return dpnTepInterfaceInfo.getTunnelName() != null;
407         }
408         return false;
409     }
410
411     private void removeConfiguration(TypedReadWriteTransaction<Configuration> tx, Interface interfaceOld,
412         ParentRefs parentRefs) throws ExecutionException, InterruptedException, OperationFailedException {
413         IfTunnel ifTunnel = interfaceOld.augmentation(IfTunnel.class);
414         if (ifTunnel != null) {
415             // Check if the same transaction can be used across Config and operational shards
416             removeTunnelConfiguration(tx, parentRefs, interfaceOld.getName(), ifTunnel);
417         }
418     }
419
420     private void removeTunnelConfiguration(TypedReadWriteTransaction<Configuration> tx, ParentRefs parentRefs,
421         String interfaceName, IfTunnel ifTunnel)
422             throws ExecutionException, InterruptedException, OperationFailedException {
423
424         LOG.info("removing tunnel configuration for {}", interfaceName);
425         BigInteger dpId = null;
426         if (parentRefs != null) {
427             dpId = parentRefs.getDatapathNodeIdentifier();
428         }
429
430         if (dpId == null) {
431             return;
432         }
433
434         Optional<OvsBridgeRefEntry> ovsBridgeRefEntryOptional = ovsBridgeRefEntryCache.get(dpId);
435         Optional<OvsBridgeEntry> ovsBridgeEntryOptional;
436         OvsdbBridgeRef ovsdbBridgeRef = null;
437         if (ovsBridgeRefEntryOptional.isPresent()) {
438             ovsdbBridgeRef = ovsBridgeRefEntryOptional.get().getOvsBridgeReference();
439         } else {
440             ovsBridgeEntryOptional = ovsBridgeEntryCache.get(dpId);
441             if (ovsBridgeEntryOptional.isPresent()) {
442                 ovsdbBridgeRef = ovsBridgeEntryOptional.get().getOvsBridgeReference();
443             }
444         }
445
446         if (ovsdbBridgeRef != null) {
447             removeTerminationEndPoint(ovsdbBridgeRef.getValue(), interfaceName);
448         }
449
450         // delete tunnel ingress flow
451         removeTunnelIngressFlow(tx, interfaceName, dpId);
452
453         // delete bridge to tunnel interface mappings
454         OvsBridgeEntryKey bridgeEntryKey = new OvsBridgeEntryKey(dpId);
455         InstanceIdentifier<OvsBridgeEntry> bridgeEntryIid =
456                 DirectTunnelUtils.getOvsBridgeEntryIdentifier(bridgeEntryKey);
457
458         ovsBridgeEntryOptional = ovsBridgeEntryCache.get(dpId);
459         if (ovsBridgeEntryOptional.isPresent()) {
460             List<OvsBridgeTunnelEntry> bridgeTunnelEntries = ovsBridgeEntryOptional.get().getOvsBridgeTunnelEntry();
461             deleteBridgeInterfaceEntry(bridgeEntryKey, bridgeTunnelEntries, bridgeEntryIid, interfaceName);
462             // IfIndex needs to be removed only during State Clean up not Config
463             // TunnelMetaUtils.removeLportTagInterfaceMap(idManager, defaultOperationalShardTransaction, interfaceName);
464             cleanUpInterfaceWithUnknownState(interfaceName, parentRefs, ifTunnel);
465             directTunnelUtils.removeLportTagInterfaceMap(interfaceName);
466         }
467     }
468
469     private void removeTerminationEndPoint(InstanceIdentifier<?> bridgeIid, String interfaceName) {
470         LOG.debug("removing termination point for {}", interfaceName);
471         InstanceIdentifier<TerminationPoint> tpIid = DirectTunnelUtils.createTerminationPointInstanceIdentifier(
472                 InstanceIdentifier.keyOf(bridgeIid.firstIdentifierOf(Node.class)), interfaceName);
473         ITMBatchingUtils.delete(tpIid, ITMBatchingUtils.EntityType.TOPOLOGY_CONFIG);
474     }
475
476     private void removeTunnelIngressFlow(TypedReadWriteTransaction<Configuration> tx, String interfaceName,
477         BigInteger dpId) throws ExecutionException, InterruptedException {
478         directTunnelUtils.removeTunnelIngressFlow(tx, dpId, interfaceName);
479     }
480
481     // if the node is shutdown, there will be stale interface state entries,
482     // with unknown op-state, clear them.
483     private void cleanUpInterfaceWithUnknownState(String interfaceName, ParentRefs parentRefs, IfTunnel ifTunnel)
484         throws ReadFailedException {
485         Optional<StateTunnelList> stateTunnelList =
486                 tunnelStateCache.get(tunnelStateCache.getStateTunnelListIdentifier(interfaceName));
487         if (stateTunnelList.isPresent() && stateTunnelList.get().getOperState() == TunnelOperStatus.Unknown) {
488             String staleInterface = ifTunnel != null ? interfaceName : parentRefs.getParentInterface();
489             LOG.debug("cleaning up parent-interface for {}, since the oper-status is UNKNOWN", interfaceName);
490             directTunnelUtils.deleteTunnelStateEntry(staleInterface);
491         }
492     }
493
494     private void deleteBridgeInterfaceEntry(OvsBridgeEntryKey bridgeEntryKey,
495                                             List<OvsBridgeTunnelEntry> bridgeTunnelEntries,
496                                             InstanceIdentifier<OvsBridgeEntry> bridgeEntryIid,
497                                             String interfaceName) {
498         OvsBridgeTunnelEntryKey bridgeTunnelEntryKey = new OvsBridgeTunnelEntryKey(interfaceName);
499         InstanceIdentifier<OvsBridgeTunnelEntry> bridgeTunnelEntryIid =
500                 DirectTunnelUtils.getBridgeTunnelEntryIdentifier(bridgeEntryKey, bridgeTunnelEntryKey);
501         ITMBatchingUtils.delete(bridgeTunnelEntryIid, ITMBatchingUtils.EntityType.DEFAULT_CONFIG);
502         if (bridgeTunnelEntries.size() <= 1) {
503             ITMBatchingUtils.delete(bridgeEntryIid, ITMBatchingUtils.EntityType.DEFAULT_CONFIG);
504         }
505     }
506 }