Freeze upstream versions
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / intervpnlink / InterVpnLinkListener.java
1 /*
2  * Copyright (c) 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.netvirt.vpnmanager.intervpnlink;
9
10 import static java.util.Objects.requireNonNull;
11 import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
12
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import com.google.common.util.concurrent.MoreExecutors;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.Optional;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Future;
22 import javax.annotation.PreDestroy;
23 import javax.inject.Inject;
24 import javax.inject.Singleton;
25 import org.opendaylight.genius.mdsalutil.MDSALUtil;
26 import org.opendaylight.genius.mdsalutil.NwConstants;
27 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
28 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
29 import org.opendaylight.infrautils.utils.concurrent.Executors;
30 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
31 import org.opendaylight.mdsal.binding.api.DataBroker;
32 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
33 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
34 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
35 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
36 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
37 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
38 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
39 import org.opendaylight.netvirt.vpnmanager.VpnConstants;
40 import org.opendaylight.netvirt.vpnmanager.VpnFootprintService;
41 import org.opendaylight.netvirt.vpnmanager.VpnOpDataSyncer;
42 import org.opendaylight.netvirt.vpnmanager.VpnUtil;
43 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.IVpnLinkService;
44 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
45 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
46 import org.opendaylight.netvirt.vpnmanager.intervpnlink.tasks.InterVpnLinkCleanedCheckerTask;
47 import org.opendaylight.netvirt.vpnmanager.intervpnlink.tasks.InterVpnLinkCreatorTask;
48 import org.opendaylight.netvirt.vpnmanager.intervpnlink.tasks.InterVpnLinkRemoverTask;
49 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinkCreationError;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinkCreationErrorBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinks;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.creation.error.InterVpnLinkCreationErrorMessage;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.creation.error.InterVpnLinkCreationErrorMessageBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkStateBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.FirstEndpointState;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.FirstEndpointStateBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.SecondEndpointState;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.inter.vpn.link.state.SecondEndpointStateBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLinkKey;
75 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
76 import org.opendaylight.yangtools.yang.common.RpcResult;
77 import org.opendaylight.yangtools.yang.common.Uint32;
78 import org.opendaylight.yangtools.yang.common.Uint64;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
81
82 @Singleton
83 public class InterVpnLinkListener extends AbstractAsyncDataTreeChangeListener<InterVpnLink> {
84
85     private static final Logger LOG = LoggerFactory.getLogger(InterVpnLinkListener.class);
86
87     private static final long INVALID_ID = 0;
88
89     private final DataBroker dataBroker;
90     private final ManagedNewTransactionRunner txRunner;
91     private final IMdsalApiManager mdsalManager;
92     private final IdManagerService idManager;
93     private final IBgpManager bgpManager;
94     private final IFibManager fibManager;
95     private final NotificationPublishService notificationsService;
96     private final IVpnLinkService ivpnLinkService;
97     private final InterVpnLinkLocator ivpnLinkLocator;
98     private final VpnFootprintService vpnFootprintService;
99     private final VpnOpDataSyncer vpnOpDataSyncer;
100     private final JobCoordinator jobCoordinator;
101     private final InterVpnLinkCache interVpnLinkCache;
102     private final VpnUtil vpnUtil;
103     private final InterVpnLinkUtil interVpnLinkUtil;
104
105     @Inject
106     public InterVpnLinkListener(final DataBroker dataBroker, final IdManagerService idManager,
107                                 final IMdsalApiManager mdsalManager, final IBgpManager bgpManager,
108                                 final IFibManager fibManager, final NotificationPublishService notifService,
109                                 final IVpnLinkService interVpnLinkService,
110                                 final InterVpnLinkLocator interVpnLinkLocator,
111                                 final VpnFootprintService vpnFootprintService,
112                                 final VpnOpDataSyncer vpnOpDataSyncer,
113                                 final JobCoordinator jobCoordinator,
114                                 final InterVpnLinkCache interVpnLinkCache, final VpnUtil vpnUtil,
115                                 final InterVpnLinkUtil interVpnLinkUtil) {
116         super(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(InterVpnLinks.class)
117                 .child(InterVpnLink.class),
118                 Executors.newListeningSingleThreadExecutor("InterVpnLinkListener", LOG));
119         this.dataBroker = dataBroker;
120         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
121         this.idManager = idManager;
122         this.mdsalManager = mdsalManager;
123         this.bgpManager = bgpManager;
124         this.fibManager = fibManager;
125         this.notificationsService = notifService;
126         this.ivpnLinkService = interVpnLinkService;
127         this.ivpnLinkLocator = interVpnLinkLocator;
128         this.vpnFootprintService = vpnFootprintService;
129         this.vpnOpDataSyncer = vpnOpDataSyncer;
130         this.jobCoordinator = jobCoordinator;
131         this.interVpnLinkCache = interVpnLinkCache;
132         this.vpnUtil = vpnUtil;
133         this.interVpnLinkUtil = interVpnLinkUtil;
134     }
135
136     public void start() {
137         LOG.info("{} start", getClass().getSimpleName());
138     }
139
140     @Override
141     @PreDestroy
142     public void close() {
143         super.close();
144         Executors.shutdownAndAwaitTermination(getExecutorService());
145     }
146
147     @Override
148     public void add(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink add) {
149
150         String ivpnLinkName = add.getName();
151         LOG.debug("Reacting to IVpnLink {} creation. Vpn1=[name={}  EndpointIp={}]  Vpn2=[name={} endpointIP={}]",
152                   ivpnLinkName, add.getFirstEndpoint().getVpnUuid(), add.getFirstEndpoint().getIpAddress(),
153                   add.getSecondEndpoint().getVpnUuid(), add.getSecondEndpoint().getIpAddress());
154
155         // Create VpnLink state
156         InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid = InterVpnLinkUtil.getInterVpnLinkStateIid(ivpnLinkName);
157         InterVpnLinkState vpnLinkState = new InterVpnLinkStateBuilder().setInterVpnLinkName(ivpnLinkName).build();
158         MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnLinkStateIid, vpnLinkState);
159
160         InterVpnLinkKey key = add.key();
161         Uuid vpn1Uuid = add.getFirstEndpoint().getVpnUuid();
162         String vpn1Name = vpn1Uuid.getValue();
163         Uuid vpn2Uuid = add.getSecondEndpoint().getVpnUuid();
164         String vpn2Name = vpn2Uuid.getValue();
165         String vpn1PrimaryRd = vpnUtil.getPrimaryRd(vpn1Name);
166         String vpn2PrimaryRd = vpnUtil.getPrimaryRd(vpn1Name);
167         if (!vpnUtil.isVpnPendingDelete(vpn1PrimaryRd)
168                 && !vpnUtil.isVpnPendingDelete(vpn2PrimaryRd)) {
169             if (vpnUtil.getVpnInstance(vpn1Name) == null) {
170                 String errMsg = "InterVpnLink " + ivpnLinkName + " creation error: could not find 1st endpoint Vpn "
171                         + vpn1Name;
172                 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
173                 return;
174             }
175             if (!checkVpnAvailability(key, vpn1Name)) {
176                 String errMsg = "InterVpnLink " + ivpnLinkName + " creation error: Vpn " + vpn1Name
177                         + " is already associated to an inter-vpn-link ";
178                 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
179                 return;
180             }
181
182             // Second VPN
183             if (vpnUtil.getVpnInstance(vpn2Name) == null) {
184                 String errMsg = "InterVpnLink " + ivpnLinkName + " creation error: could not find 2nd endpoint Vpn "
185                         + vpn2Name;
186                 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
187                 return;
188             }
189             if (!checkVpnAvailability(key, vpn2Name)) {
190                 String errMsg = "InterVpnLink " + ivpnLinkName + " creation error: Vpn " + vpn2Name
191                         + " is already associated with an inter-vpn-link";
192                 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
193                 return;
194             }
195
196             interVpnLinkCache.addInterVpnLinkToCaches(add);
197
198             // Wait for VPN Operational data ready
199             Uint32 vpn1Id = vpnUtil.getVpnId(vpn1Name);
200             if (VpnConstants.INVALID_ID.equals(vpn1Id)) {
201                 boolean vpn1Ready =
202                         vpnOpDataSyncer.waitForVpnDataReady(VpnOpDataSyncer.VpnOpDataType.vpnInstanceToId, vpn1Name,
203                                 VpnConstants.PER_VPN_INSTANCE_MAX_WAIT_TIME_IN_MILLISECONDS);
204                 if (!vpn1Ready) {
205                     String errMsg =
206                             "InterVpnLink " + ivpnLinkName + " creation error: Operational Data for VPN " + vpn1Name
207                                     + " not ready after " + VpnConstants.PER_INTERFACE_MAX_WAIT_TIME_IN_MILLISECONDS
208                                     + " milliseconds";
209                     setInError(vpnLinkStateIid, vpnLinkState, errMsg);
210                     return;
211                 }
212             }
213             Uint32 vpn2Id = vpnUtil.getVpnId(vpn2Name);
214             if (VpnConstants.INVALID_ID.equals(vpn2Id)) {
215                 boolean vpn1Ready =
216                         vpnOpDataSyncer.waitForVpnDataReady(VpnOpDataSyncer.VpnOpDataType.vpnInstanceToId,vpn2Name,
217                                 VpnConstants.PER_VPN_INSTANCE_MAX_WAIT_TIME_IN_MILLISECONDS);
218                 if (!vpn1Ready) {
219                     String errMsg =
220                             "InterVpnLink " + ivpnLinkName + " creation error: Operational Data for VPN " + vpn2Name
221                                     + " not ready after " + VpnConstants.PER_INTERFACE_MAX_WAIT_TIME_IN_MILLISECONDS
222                                     + " milliseconds";
223                     setInError(vpnLinkStateIid, vpnLinkState, errMsg);
224                     return;
225                 }
226             }
227
228             List<Uint64> firstDpnList = ivpnLinkLocator.selectSuitableDpns(add);
229             if (firstDpnList != null && !firstDpnList.isEmpty()) {
230                 List<Uint64> secondDpnList = firstDpnList;
231
232                 Long firstVpnLportTag = allocateVpnLinkLportTag(key.getName() + vpn1Name);
233                 Long secondVpnLportTag = allocateVpnLinkLportTag(key.getName() + vpn2Name);
234                 FirstEndpointState firstEndPointState =
235                         new FirstEndpointStateBuilder().setVpnUuid(vpn1Uuid).setDpId(firstDpnList)
236                                 .setLportTag(firstVpnLportTag).build();
237                 SecondEndpointState secondEndPointState =
238                         new SecondEndpointStateBuilder().setVpnUuid(vpn2Uuid).setDpId(secondDpnList)
239                                 .setLportTag(secondVpnLportTag).build();
240
241                 interVpnLinkUtil.updateInterVpnLinkState(ivpnLinkName, InterVpnLinkState.State.Active,
242                         firstEndPointState, secondEndPointState, interVpnLinkCache);
243
244                 // Note that in the DPN of the firstEndpoint we install the lportTag of the secondEndpoint and viceversa
245                 interVpnLinkUtil.installLPortDispatcherTableFlow(ivpnLinkName, firstDpnList, vpn2Name,
246                         secondVpnLportTag);
247                 interVpnLinkUtil.installLPortDispatcherTableFlow(ivpnLinkName, secondDpnList, vpn1Name,
248                         firstVpnLportTag);
249                 // Update the VPN -> DPNs Map.
250                 // Note: when a set of DPNs is calculated for Vpn1, these DPNs are added to the VpnToDpn map of Vpn2.
251                 // Why? because we do the handover from Vpn1 to Vpn2 in those DPNs, so in those DPNs we must know how
252                 // to reach to Vpn2 targets. If new Vpn2 targets are added later, the Fib will be maintained in these
253                 // DPNs even if Vpn2 is not physically present there.
254                 interVpnLinkUtil.updateVpnFootprint(vpn2Name, vpn2PrimaryRd, firstDpnList);
255                 interVpnLinkUtil.updateVpnFootprint(vpn1Name, vpn1PrimaryRd, secondDpnList);
256
257                 // Program static routes if needed
258                 Optional<InterVpnLinkDataComposite> interVpnLink =
259                         interVpnLinkCache.getInterVpnLinkByName(ivpnLinkName);
260                 ivpnLinkService.handleStaticRoutes(interVpnLink.get());
261
262                 // Now, if the corresponding flags are activated, there will be some routes exchange
263                 ivpnLinkService.exchangeRoutes(interVpnLink.get());
264             } else {
265                 // If there is no connection to DPNs, the InterVpnLink is created and the InterVpnLinkState is also
266                 // created with the corresponding LPortTags but no DPN is assigned since there is no DPN operative.
267                 Long firstVpnLportTag = allocateVpnLinkLportTag(key.getName() + vpn1Name);
268                 Long secondVpnLportTag = allocateVpnLinkLportTag(key.getName() + vpn2Name);
269                 FirstEndpointState firstEndPointState =
270                         new FirstEndpointStateBuilder().setVpnUuid(vpn1Uuid).setLportTag(firstVpnLportTag)
271                                 .setDpId(Collections.emptyList()).build();
272                 SecondEndpointState secondEndPointState =
273                         new SecondEndpointStateBuilder().setVpnUuid(vpn2Uuid).setLportTag(secondVpnLportTag)
274                                 .setDpId(Collections.emptyList()).build();
275                 interVpnLinkUtil.updateInterVpnLinkState(ivpnLinkName, InterVpnLinkState.State.Error,
276                         firstEndPointState, secondEndPointState, interVpnLinkCache);
277             }
278         }
279     }
280
281     private boolean checkVpnAvailability(InterVpnLinkKey key, String vpnName) {
282         requireNonNull(vpnName);
283
284         List<InterVpnLinkDataComposite> allInterVpnLinks = interVpnLinkCache.getAllInterVpnLinks();
285         if (allInterVpnLinks.isEmpty()) {
286             return true;
287         }
288
289         return allInterVpnLinks.stream().noneMatch(ivl -> !ivl.getInterVpnLinkName().equals(key.getName())
290                                                           && ivl.isVpnLinked(vpnName));
291     }
292
293     @Override
294     public void remove(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink del) {
295
296         LOG.debug("Reacting to InterVpnLink {} removal", del.getName());
297
298         // Remove learnt routes
299         // Remove entries in the LPortDispatcher table
300         // Remove the corresponding entries in InterVpnLinkState
301
302         // For each endpoint, remove all routes that have been learnt by intervpnLink
303         String vpn1Uuid = del.getFirstEndpoint().getVpnUuid().getValue();
304         String rd1 = vpnUtil.getVpnRd(vpn1Uuid);
305         LOG.debug("Removing leaked routes in VPN {}  rd={}", vpn1Uuid, rd1);
306         vpnUtil.removeVrfEntriesByOrigin(rd1, RouteOrigin.INTERVPN);
307         List<VrfEntry> vrfEntriesSecondEndpoint =
308             vpnUtil.findVrfEntriesByNexthop(rd1, del.getSecondEndpoint().getIpAddress().getValue());
309
310         String vpn2Uuid = del.getSecondEndpoint().getVpnUuid().getValue();
311         String rd2 = vpnUtil.getVpnRd(vpn2Uuid);
312         LOG.debug("Removing leaked routes in VPN {}  rd={}", vpn2Uuid, rd2);
313         vpnUtil.removeVrfEntriesByOrigin(rd2, RouteOrigin.INTERVPN);
314         List<VrfEntry> vrfEntriesFirstEndpoint =
315             vpnUtil.findVrfEntriesByNexthop(rd2, del.getFirstEndpoint().getIpAddress().getValue());
316
317         Optional<InterVpnLinkState> optIVpnLinkState = interVpnLinkUtil.getInterVpnLinkState(del.getName());
318         if (optIVpnLinkState.isPresent()) {
319             InterVpnLinkState interVpnLinkState = optIVpnLinkState.get();
320             boolean isVpnFirstEndPoint = true;
321             if (interVpnLinkState.getFirstEndpointState() != null) {
322                 Long firstEndpointLportTag = interVpnLinkState.getFirstEndpointState().getLportTag().toJava();
323                 removeVpnLinkEndpointFlows(del, vpn2Uuid, rd1,
324                     interVpnLinkState.getSecondEndpointState().getDpId(),
325                     firstEndpointLportTag.intValue(),
326                     del.getFirstEndpoint().getIpAddress().getValue(),
327                     vrfEntriesSecondEndpoint, isVpnFirstEndPoint);
328             } else {
329                 LOG.info("Could not get first endpoint state attributes for InterVpnLink {}", del.getName());
330             }
331             isVpnFirstEndPoint = false;
332             if (interVpnLinkState.getSecondEndpointState() != null) {
333                 Long secondEndpointLportTag = interVpnLinkState.getSecondEndpointState().getLportTag().toJava();
334                 removeVpnLinkEndpointFlows(del, vpn1Uuid, rd2,
335                                            interVpnLinkState.getFirstEndpointState().getDpId(),
336                                            secondEndpointLportTag.intValue(),
337                                            del.getSecondEndpoint().getIpAddress().getValue(),
338                                            vrfEntriesFirstEndpoint, isVpnFirstEndPoint);
339             } else {
340                 LOG.info("Could not get second endpoint state attributes for InterVpnLink {}", del.getName());
341             }
342         }
343
344         vpnUtil.removeVrfEntries(rd1, vrfEntriesSecondEndpoint);
345         vpnUtil.removeVrfEntries(rd2, vrfEntriesFirstEndpoint);
346         vpnUtil.withdrawRoutes(rd1, vrfEntriesSecondEndpoint);
347         vpnUtil.withdrawRoutes(rd2, vrfEntriesFirstEndpoint);
348
349         // Release idManager with LPortTag associated to endpoints
350         LOG.debug("Releasing InterVpnLink {} endpoints LportTags", del.getName());
351         InterVpnLinkKey key = del.key();
352         Uuid firstEndpointVpnUuid = del.getFirstEndpoint().getVpnUuid();
353         Uuid secondEndpointVpnUuid = del.getSecondEndpoint().getVpnUuid();
354         releaseVpnLinkLPortTag(key.getName() + firstEndpointVpnUuid.getValue());
355         releaseVpnLinkLPortTag(key.getName() + secondEndpointVpnUuid.getValue());
356
357         // Routes with nextHop pointing to an end-point of the inter-vpn-link are populated into FIB table.
358         // The action in that case is a nx_resubmit to LPortDispatcher table. This is done in FibManager.
359         // At this point. we need to check if is there any entry in FIB table pointing to LPortDispatcher table.
360         // Remove it in that case.
361
362         // Removing the InterVpnLinkState
363         InstanceIdentifier<InterVpnLinkState> interVpnLinkStateIid =
364             InterVpnLinkUtil.getInterVpnLinkStateIid(del.getName());
365         LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx ->
366             tx.delete(interVpnLinkStateIid)), LOG, "Error deleting inter-VPN link state {}", interVpnLinkStateIid);
367     }
368
369     // We're catching Exception here to continue deleting as much as possible
370     // TODO Rework this so it's done in one transaction
371     @SuppressWarnings("checkstyle:IllegalCatch")
372     private void removeVpnLinkEndpointFlows(InterVpnLink del, String vpnUuid, String rd, List<Uint64> dpns,
373                                             int otherEndpointLportTag, String otherEndpointIpAddr,
374                                             List<VrfEntry> vrfEntries, final boolean isVpnFirstEndPoint) {
375
376         String interVpnLinkName = del.getName();
377         LOG.debug("Removing endpoint flows for vpn {}.  InterVpnLink={}.  OtherEndpointLportTag={}",
378             vpnUuid, interVpnLinkName, otherEndpointLportTag);
379         if (dpns == null) {
380             LOG.debug("VPN {} endpoint is not instantiated in any DPN for InterVpnLink {}",
381                 vpnUuid, interVpnLinkName);
382             return;
383         }
384
385         for (Uint64 dpnId : dpns) {
386             try {
387                 // Removing flow from LportDispatcher table
388                 String flowRef = InterVpnLinkUtil.getLportDispatcherFlowRef(interVpnLinkName, otherEndpointLportTag);
389                 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
390                 Flow flow = new FlowBuilder().withKey(flowKey).setId(new FlowId(flowRef))
391                     .setTableId(NwConstants.LPORT_DISPATCHER_TABLE).setFlowName(flowRef)
392                     .build();
393                 mdsalManager.removeFlow(dpnId, flow);
394
395                 // Also remove the 'fake' iface from the VpnToDpn map
396                 interVpnLinkUtil.removeIVpnLinkIfaceFromVpnFootprint(vpnUuid, rd, dpnId);
397
398             } catch (Exception e) {
399                 // Whatever happens it should not stop it from trying to remove as much as possible
400                 LOG.warn("Error while removing InterVpnLink {} Endpoint flows on dpn {}. Reason: ",
401                     interVpnLinkName, dpnId, e);
402             }
403         }
404         // Removing flow from FIB and LFIB tables
405         LOG.trace("Removing flow in FIB and LFIB tables for vpn {} interVpnLink {} otherEndpointIpAddr {}",
406             vpnUuid, interVpnLinkName, otherEndpointIpAddr);
407         cleanUpInterVPNRoutes(interVpnLinkName, vrfEntries, isVpnFirstEndPoint);
408     }
409
410
411     private void releaseVpnLinkLPortTag(String idKey) {
412         ReleaseIdInput releaseIdInput =
413             new ReleaseIdInputBuilder().setPoolName(VpnConstants.PSEUDO_LPORT_TAG_ID_POOL_NAME).setIdKey(idKey).build();
414
415         LoggingFutures.addErrorLogging(idManager.releaseId(releaseIdInput), LOG, "Release Id");
416     }
417
418     @Override
419     public void update(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink original, InterVpnLink update) {
420
421         LOG.debug("Update InterVpnLink {}. "
422                 + " original=[1stEndpoint=[vpn=<{}> ipAddr=<{}>] 2ndEndpoint=[vpn=<{}> ipAddr=<{}>]]"
423                 + " update=[1stEndpoint=[vpn=<{}> ipAddr=<{}>] 2ndEndpoint=[vpn=<{}> ipAddr=<{}>]]",
424             original.getName(),
425             original.getFirstEndpoint().getVpnUuid(), original.getFirstEndpoint().getIpAddress(),
426             original.getSecondEndpoint().getVpnUuid(), original.getSecondEndpoint().getIpAddress(),
427             update.getFirstEndpoint().getVpnUuid(), update.getFirstEndpoint().getIpAddress(),
428             update.getSecondEndpoint().getVpnUuid(), update.getSecondEndpoint().getIpAddress());
429
430         String specificJobKey = "InterVpnLink.update." + original.getName();
431         jobCoordinator.enqueueJob(specificJobKey, new InterVpnLinkRemoverTask(dataBroker, identifier));
432         jobCoordinator.enqueueJob(specificJobKey, new InterVpnLinkCleanedCheckerTask(dataBroker, original,
433                 interVpnLinkUtil, vpnUtil));
434         jobCoordinator.enqueueJob(specificJobKey, new InterVpnLinkCreatorTask(dataBroker, update));
435     }
436
437     private Long allocateVpnLinkLportTag(String idKey) {
438         AllocateIdInput getIdInput =
439             new AllocateIdInputBuilder().setPoolName(VpnConstants.PSEUDO_LPORT_TAG_ID_POOL_NAME)
440                 .setIdKey(idKey)
441                 .build();
442         try {
443             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
444             RpcResult<AllocateIdOutput> rpcResult = result.get();
445             if (rpcResult.isSuccessful()) {
446                 return rpcResult.getResult().getIdValue().toJava();
447             } else {
448                 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
449             }
450         } catch (InterruptedException | ExecutionException e) {
451             LOG.warn("Exception when getting Unique Id", e);
452         }
453         return INVALID_ID;
454     }
455
456     protected void setInError(final InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid,
457         final InterVpnLinkState vpnLinkState,
458         String errorMsg) {
459         LOG.error("Setting InterVpnLink {} in error. Reason: {}", vpnLinkState.getInterVpnLinkName(), errorMsg);
460
461         // Setting InterVPNLink in error state in MDSAL
462         InterVpnLinkState vpnLinkErrorState =
463             new InterVpnLinkStateBuilder(vpnLinkState).setState(InterVpnLinkState.State.Error)
464                 .setErrorDescription(errorMsg)
465                 .build();
466         LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx ->
467             tx.mergeParentStructurePut(vpnLinkStateIid, vpnLinkErrorState)),
468                 LOG, "Error storing the VPN link error state for {}, {}", vpnLinkStateIid, vpnLinkErrorState);
469
470         // Sending out an error Notification
471         InterVpnLinkCreationErrorMessage errMsg =
472             new InterVpnLinkCreationErrorMessageBuilder().setErrorMessage(errorMsg).build();
473         InterVpnLinkCreationError notif =
474             new InterVpnLinkCreationErrorBuilder().setInterVpnLinkCreationErrorMessage(errMsg).build();
475         final ListenableFuture<?> eventFuture = this.notificationsService.offerNotification(notif);
476         Futures.addCallback(eventFuture, new FutureCallback<Object>() {
477             @Override
478             public void onFailure(Throwable error) {
479                 LOG.warn("Error when sending notification about InterVpnLink creation issue. InterVpnLink name={} "
480                                 + "state={}.", vpnLinkState.getInterVpnLinkName(), vpnLinkState, error);
481             }
482
483             @Override
484             public void onSuccess(Object arg) {
485                 LOG.trace("Error notification for InterVpnLink successfully sent. VpnLinkName={} state={}",
486                     vpnLinkState.getInterVpnLinkName(), vpnLinkState);
487             }
488         }, MoreExecutors.directExecutor());
489     }
490
491     /**
492      * Removes all the flows from FIB/LFIB matching an endpoint from the intervpnlink.
493      *
494      * @param interVpnLinkName name of the intervpnlink
495      * @param vrfEntries list of vrfs matching the first/second intervpnlink endpoints
496      * @param isVpnFirstEndPoint indicates whether vrfEntries belong to the vpn of the first endpoint
497      */
498     private void cleanUpInterVPNRoutes(final String interVpnLinkName,
499         List<VrfEntry> vrfEntries,
500         final boolean isVpnFirstEndPoint) {
501
502         for (VrfEntry vrfEntry : vrfEntries) {
503             fibManager.removeInterVPNLinkRouteFlows(interVpnLinkName, isVpnFirstEndPoint, vrfEntry);
504         }
505     }
506 }