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