Cleanup
[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 com.google.common.base.Optional;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.List;
17 import java.util.concurrent.Callable;
18
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
23 import org.opendaylight.genius.itm.impl.ItmUtils;
24 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeBase;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeLldp;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeLogicalGroup;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelList;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPointsBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.tunnel.end.points.TzMembership;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnel;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnelKey;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 public class ItmInternalTunnelDeleteWorker {
44     private static final Logger LOG = LoggerFactory.getLogger(ItmInternalTunnelDeleteWorker.class) ;
45
46     @SuppressWarnings("checkstyle:IllegalCatch")
47     public static List<ListenableFuture<Void>> deleteTunnels(DataBroker dataBroker,
48                                                              IMdsalApiManager mdsalManager,
49                                                              List<DPNTEPsInfo> dpnTepsList,
50                                                              List<DPNTEPsInfo> meshedDpnList) {
51         LOG.trace("TEPs to be deleted {} " , dpnTepsList);
52         List<ListenableFuture<Void>> futures = new ArrayList<>();
53         WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
54         try {
55             if (dpnTepsList == null || dpnTepsList.size() == 0) {
56                 LOG.debug("no vtep to delete");
57                 return futures ;
58             }
59
60             if (meshedDpnList == null || meshedDpnList.size() == 0) {
61                 LOG.debug("No Meshed Vteps");
62                 return futures ;
63             }
64             for (DPNTEPsInfo srcDpn : dpnTepsList) {
65                 LOG.trace("Processing srcDpn {}", srcDpn);
66
67                 List<TunnelEndPoints> meshedEndPtCache = ItmUtils.getTEPsForDpn(srcDpn.getDPNID(), meshedDpnList);
68                 if (meshedEndPtCache == null) {
69                     LOG.debug("No Tunnel End Point configured for this DPN {}", srcDpn.getDPNID());
70                     continue ;
71                 }
72                 LOG.debug("Entries in meshEndPointCache {} for DPN Id{} ", meshedEndPtCache.size(), srcDpn.getDPNID());
73                 for (TunnelEndPoints srcTep : srcDpn.getTunnelEndPoints()) {
74                     LOG.trace("Processing srcTep {}", srcTep);
75                     List<TzMembership> srcTZones = srcTep.getTzMembership();
76                     boolean tepDeleteFlag = false;
77                     // First, take care of tunnel removal, so run through all other DPNS other than srcDpn
78                     // In the tep received from Delete DCN, the membership list will always be 1
79                     // as the DCN is at transport zone level
80                     // Hence if a tunnel is shared across TZs, compare the original membership list between end points
81                     // to decide if tunnel to be deleted.
82                     for (DPNTEPsInfo dstDpn : meshedDpnList) {
83                         if (!srcDpn.getDPNID().equals(dstDpn.getDPNID())) {
84                             for (TunnelEndPoints dstTep : dstDpn.getTunnelEndPoints()) {
85                                 if (!ItmUtils.getIntersection(dstTep.getTzMembership(), srcTZones).isEmpty()) {
86                                     List<TzMembership> originalTzMembership =
87                                             ItmUtils.getOriginalTzMembership(srcTep, srcDpn.getDPNID(), meshedDpnList);
88                                     if (ItmUtils.getIntersection(dstTep.getTzMembership(), originalTzMembership).size()
89                                             == 1) {
90                                         if (checkIfTrunkExists(dstDpn.getDPNID(), srcDpn.getDPNID(),
91                                                 srcTep.getTunnelType(), dataBroker)) {
92                                             // remove all trunk interfaces
93                                             LOG.trace("Invoking removeTrunkInterface between source TEP {} , "
94                                                     + "Destination TEP {} ", srcTep, dstTep);
95                                             removeTrunkInterface(dataBroker, srcTep, dstTep, srcDpn
96                                                     .getDPNID(), dstDpn.getDPNID(), writeTransaction);
97                                         }
98                                     }
99                                 }
100                             }
101                         }
102                     }
103                     for (DPNTEPsInfo dstDpn : meshedDpnList) {
104                         // Second, take care of Tep TZ membership and identify if tep can be removed
105                         if (srcDpn.getDPNID().equals(dstDpn.getDPNID())) {
106                             // Same DPN, so remove the TZ membership
107                             for (TunnelEndPoints dstTep : dstDpn.getTunnelEndPoints()) {
108                                 if (dstTep.getIpAddress().equals(srcTep.getIpAddress())) {
109                                     // Remove the deleted TZ membership from the TEP
110                                     LOG.debug("Removing TZ list {} from Existing TZ list {} ",
111                                             srcTZones, dstTep.getTzMembership());
112                                     List<TzMembership> updatedList =
113                                             ItmUtils.removeTransportZoneMembership(dstTep, srcTZones);
114                                     if (updatedList.isEmpty()) {
115                                         LOG.debug(" This TEP can be deleted {}", srcTep);
116                                         tepDeleteFlag = true;
117                                     } else {
118                                         TunnelEndPointsBuilder modifiedTepBld = new TunnelEndPointsBuilder(dstTep);
119                                         modifiedTepBld.setTzMembership(updatedList);
120                                         TunnelEndPoints modifiedTep = modifiedTepBld.build() ;
121                                         InstanceIdentifier<TunnelEndPoints> tepPath = InstanceIdentifier
122                                                 .builder(DpnEndpoints.class)
123                                                 .child(DPNTEPsInfo.class, dstDpn.getKey())
124                                                 .child(TunnelEndPoints.class, dstTep.getKey()).build();
125
126                                         LOG.debug(" Store the modified Tep in DS {} ", modifiedTep);
127                                         writeTransaction.put(LogicalDatastoreType.CONFIGURATION, tepPath, modifiedTep);
128                                     }
129                                 }
130                             }
131                         }
132                     }
133                     if (tepDeleteFlag) {
134                         // Third, removing vtep / dpn from Tunnels OpDs.
135                         InstanceIdentifier<TunnelEndPoints> tepPath =
136                                 InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, srcDpn.getKey())
137                                         .child(TunnelEndPoints.class, srcTep.getKey()).build();
138
139                         LOG.trace("Tep Removal of TEP {} from DPNTEPSINFO CONFIG DS with Key {} ",
140                                 srcTep, srcTep.getKey());
141                         writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, tepPath);
142                         // remove the tep from the cache
143                         meshedEndPtCache.remove(srcTep);
144                         Class<? extends TunnelMonitoringTypeBase> monitorProtocol =
145                                 ItmUtils.determineMonitorProtocol(dataBroker);
146                         InstanceIdentifier<DPNTEPsInfo> dpnPath =
147                                 InstanceIdentifier.builder(DpnEndpoints.class).child(DPNTEPsInfo.class, srcDpn.getKey())
148                                         .build();
149
150                         if (meshedEndPtCache.isEmpty()) {
151                             // remove dpn if no vteps exist on dpn
152                             if (monitorProtocol.isAssignableFrom(TunnelMonitoringTypeLldp.class)) {
153                                 LOG.debug("Removing Terminating Service Table Flow ");
154                                 ItmUtils.setUpOrRemoveTerminatingServiceTable(srcDpn.getDPNID(), mdsalManager, false);
155                             }
156                             LOG.trace("DPN Removal from DPNTEPSINFO CONFIG DS {}", srcDpn.getDPNID());
157                             writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, dpnPath);
158                             InstanceIdentifier<DpnEndpoints> tnlContainerPath =
159                                     InstanceIdentifier.builder(DpnEndpoints.class).build();
160                             Optional<DpnEndpoints> containerOptional =
161                                     ItmUtils.read(LogicalDatastoreType.CONFIGURATION,
162                                             tnlContainerPath, dataBroker);
163                             // remove container if no DPNs are present
164                             if (containerOptional.isPresent()) {
165                                 DpnEndpoints deps = containerOptional.get();
166                                 if (deps.getDPNTEPsInfo() == null || deps.getDPNTEPsInfo().isEmpty()) {
167                                     LOG.trace("Container Removal from DPNTEPSINFO CONFIG DS");
168                                     writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, tnlContainerPath);
169                                 }
170                             }
171                         }
172                     }
173                 }
174             }
175             futures.add(writeTransaction.submit());
176         } catch (Exception e1) {
177             LOG.error("exception while deleting tep", e1);
178         }
179         return futures ;
180     }
181
182     private static void removeTrunkInterface(DataBroker dataBroker,
183                                              TunnelEndPoints srcTep, TunnelEndPoints dstTep, BigInteger srcDpnId,
184                                              BigInteger dstDpnId, WriteTransaction transaction) {
185         String trunkfwdIfName = ItmUtils.getTrunkInterfaceName(srcTep.getInterfaceName(),
186                 new String(srcTep.getIpAddress().getValue()),
187                 new String(dstTep.getIpAddress().getValue()),
188                 srcTep.getTunnelType().getName());
189         LOG.trace("Removing forward Trunk Interface " + trunkfwdIfName);
190         InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(trunkfwdIfName);
191         LOG.debug(" Removing Trunk Interface Name - {} , Id - {} from Config DS ",
192                 trunkfwdIfName, trunkIdentifier) ;
193         transaction.delete(LogicalDatastoreType.CONFIGURATION, trunkIdentifier);
194         ItmUtils.ITM_CACHE.removeInterface(trunkfwdIfName);
195         // also update itm-state ds -- Delete the forward tunnel-interface from the tunnel list
196         InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(TunnelList.class)
197                 .child(InternalTunnel.class, new InternalTunnelKey(dstDpnId, srcDpnId, srcTep.getTunnelType()));
198         transaction.delete(LogicalDatastoreType.CONFIGURATION,path) ;
199         ItmUtils.ITM_CACHE.removeInternalTunnel(trunkfwdIfName);
200         // Release the Ids for the forward trunk interface Name
201         ItmUtils.releaseIdForTrunkInterfaceName(srcTep.getInterfaceName(),
202                 new String(srcTep.getIpAddress().getValue()),
203                 new String(dstTep.getIpAddress().getValue()),
204                 srcTep.getTunnelType().getName());
205         removeLogicalGroupTunnel(srcDpnId, dstDpnId, dataBroker);
206
207         String trunkRevIfName = ItmUtils.getTrunkInterfaceName(dstTep.getInterfaceName(),
208                 new String(dstTep.getIpAddress().getValue()),
209                 new String(srcTep.getIpAddress().getValue()),
210                 srcTep.getTunnelType().getName());
211         LOG.trace("Removing Reverse Trunk Interface {}", trunkRevIfName);
212         trunkIdentifier = ItmUtils.buildId(trunkRevIfName);
213         LOG.debug(" Removing Trunk Interface Name - {} , Id - {} from Config DS ",
214                 trunkRevIfName, trunkIdentifier) ;
215         transaction.delete(LogicalDatastoreType.CONFIGURATION, trunkIdentifier);
216         ItmUtils.ITM_CACHE.removeInternalTunnel(trunkRevIfName);
217         // also update itm-state ds -- Delete the reverse tunnel-interface from the tunnel list
218         path = InstanceIdentifier.create(TunnelList.class)
219                 .child(InternalTunnel.class, new InternalTunnelKey(srcDpnId, dstDpnId, dstTep.getTunnelType()));
220         transaction.delete(LogicalDatastoreType.CONFIGURATION,path) ;
221
222         // Release the Ids for the reverse trunk interface Name
223         ItmUtils.releaseIdForTrunkInterfaceName(dstTep.getInterfaceName(),
224                 new String(dstTep.getIpAddress().getValue()),
225                 new String(srcTep.getIpAddress().getValue()),
226                 dstTep.getTunnelType().getName());
227         removeLogicalGroupTunnel(dstDpnId, srcDpnId, dataBroker);
228     }
229
230     private static boolean checkIfTrunkExists(BigInteger srcDpnId, BigInteger dstDpnId,
231                                               Class<? extends TunnelTypeBase> tunType, DataBroker dataBroker) {
232         InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(TunnelList.class)
233                 .child(InternalTunnel.class, new InternalTunnelKey(dstDpnId, srcDpnId, tunType));
234         return ItmUtils.read(LogicalDatastoreType.CONFIGURATION,path, dataBroker).isPresent();
235     }
236
237     private static void removeLogicalGroupTunnel(BigInteger srcDpnId, BigInteger dstDpnId,
238                                                  DataBroker dataBroker) {
239         boolean tunnelAggregationEnabled = ItmTunnelAggregationHelper.isTunnelAggregationEnabled();
240         if (!tunnelAggregationEnabled) {
241             return;
242         }
243         String logicTunnelName = ItmUtils.getLogicalTunnelGroupName(srcDpnId, dstDpnId);
244         DataStoreJobCoordinator coordinator = DataStoreJobCoordinator.getInstance();
245         ItmTunnelAggregationDeleteWorker addWorker =
246                 new ItmTunnelAggregationDeleteWorker(logicTunnelName, srcDpnId, dstDpnId, dataBroker);
247         coordinator.enqueueJob(logicTunnelName, addWorker);
248     }
249
250     private static class ItmTunnelAggregationDeleteWorker implements Callable<List<ListenableFuture<Void>>> {
251
252         private final String logicTunnelName;
253         private final BigInteger srcDpnId;
254         private final BigInteger dstDpnId;
255         private final DataBroker dataBroker;
256
257         ItmTunnelAggregationDeleteWorker(String groupName, BigInteger srcDpnId, BigInteger dstDpnId, DataBroker db) {
258             this.logicTunnelName = groupName;
259             this.srcDpnId = srcDpnId;
260             this.dstDpnId = dstDpnId;
261             this.dataBroker = db;
262         }
263
264         @Override
265         public List<ListenableFuture<Void>> call() throws Exception {
266             Collection<InternalTunnel> tunnels = ItmUtils.ITM_CACHE.getAllInternalTunnel();
267             if (tunnels == null) {
268                 return Collections.emptyList();
269             }
270             //The logical tunnel interface be removed only when the last tunnel interface on each OVS is deleted
271             boolean emptyTunnelGroup = true;
272             boolean foundLogicGroupIface = false;
273             for (InternalTunnel tunl : tunnels) {
274                 if (tunl.getSourceDPN().equals(srcDpnId) && tunl.getDestinationDPN().equals(dstDpnId)) {
275                     if (tunl.getTransportType().isAssignableFrom(TunnelTypeVxlan.class)
276                             && tunl.getTunnelInterfaceNames() != null && !tunl.getTunnelInterfaceNames().isEmpty()) {
277                         emptyTunnelGroup = false;
278                         break;
279                     } else if (tunl.getTransportType().isAssignableFrom(TunnelTypeLogicalGroup.class)) {
280                         foundLogicGroupIface = true;
281                     }
282                 }
283             }
284             if (emptyTunnelGroup && foundLogicGroupIface) {
285                 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
286                 LOG.debug("MULTIPLE_VxLAN_TUNNELS: remove the logical tunnel group {} because a last tunnel"
287                     + " interface on srcDpnId {} dstDpnId {} is removed", logicTunnelName, srcDpnId, dstDpnId);
288                 InstanceIdentifier<Interface> trunkIdentifier = ItmUtils.buildId(logicTunnelName);
289                 tx.delete(LogicalDatastoreType.CONFIGURATION, trunkIdentifier);
290                 ItmUtils.ITM_CACHE.removeInterface(logicTunnelName);
291                 InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(TunnelList.class)
292                         .child(InternalTunnel.class,
293                                 new InternalTunnelKey(dstDpnId, srcDpnId, TunnelTypeLogicalGroup.class));
294                 tx.delete(LogicalDatastoreType.CONFIGURATION, path);
295                 ItmUtils.ITM_CACHE.removeInternalTunnel(logicTunnelName);
296                 return Collections.singletonList(tx.submit());
297             } else if (!emptyTunnelGroup) {
298                 LOG.debug("MULTIPLE_VxLAN_TUNNELS: not last tunnel in logical tunnel group {}", logicTunnelName);
299             }
300             return Collections.emptyList();
301         }
302     }
303 }