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