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