2 * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.vpnmanager.intervpnlink;
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
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;
84 public class InterVpnLinkListener extends AbstractAsyncDataTreeChangeListener<InterVpnLink> {
86 private static final Logger LOG = LoggerFactory.getLogger(InterVpnLinkListener.class);
88 private static final long INVALID_ID = 0;
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;
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;
137 public void start() {
138 LOG.info("{} start", getClass().getSimpleName());
143 public void close() {
145 Executors.shutdownAndAwaitTermination(getExecutorService());
149 public void add(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink add) {
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());
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);
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 "
173 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
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);
184 if (vpnUtil.getVpnInstance(vpn2Name) == null) {
185 String errMsg = "InterVpnLink " + ivpnLinkName + " creation error: could not find 2nd endpoint Vpn "
187 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
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);
197 interVpnLinkCache.addInterVpnLinkToCaches(add);
199 // Wait for VPN Operational data ready
200 Uint32 vpn1Id = vpnUtil.getVpnId(vpn1Name);
201 if (VpnConstants.INVALID_ID.equals(vpn1Id)) {
203 vpnOpDataSyncer.waitForVpnDataReady(VpnOpDataSyncer.VpnOpDataType.vpnInstanceToId, vpn1Name,
204 VpnConstants.PER_VPN_INSTANCE_MAX_WAIT_TIME_IN_MILLISECONDS);
207 "InterVpnLink " + ivpnLinkName + " creation error: Operational Data for VPN " + vpn1Name
208 + " not ready after " + VpnConstants.PER_INTERFACE_MAX_WAIT_TIME_IN_MILLISECONDS
210 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
214 Uint32 vpn2Id = vpnUtil.getVpnId(vpn2Name);
215 if (VpnConstants.INVALID_ID.equals(vpn2Id)) {
217 vpnOpDataSyncer.waitForVpnDataReady(VpnOpDataSyncer.VpnOpDataType.vpnInstanceToId,vpn2Name,
218 VpnConstants.PER_VPN_INSTANCE_MAX_WAIT_TIME_IN_MILLISECONDS);
221 "InterVpnLink " + ivpnLinkName + " creation error: Operational Data for VPN " + vpn2Name
222 + " not ready after " + VpnConstants.PER_INTERFACE_MAX_WAIT_TIME_IN_MILLISECONDS
224 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
229 List<Uint64> firstDpnList = ivpnLinkLocator.selectSuitableDpns(add);
230 if (firstDpnList != null && !firstDpnList.isEmpty()) {
231 List<Uint64> secondDpnList = firstDpnList;
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();
242 interVpnLinkUtil.updateInterVpnLinkState(ivpnLinkName, InterVpnLinkState.State.Active,
243 firstEndPointState, secondEndPointState, interVpnLinkCache);
245 // Note that in the DPN of the firstEndpoint we install the lportTag of the secondEndpoint and viceversa
246 interVpnLinkUtil.installLPortDispatcherTableFlow(ivpnLinkName, firstDpnList, vpn2Name,
248 interVpnLinkUtil.installLPortDispatcherTableFlow(ivpnLinkName, secondDpnList, vpn1Name,
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);
258 // Program static routes if needed
259 Optional<InterVpnLinkDataComposite> interVpnLink =
260 interVpnLinkCache.getInterVpnLinkByName(ivpnLinkName);
261 ivpnLinkService.handleStaticRoutes(interVpnLink.get());
263 // Now, if the corresponding flags are activated, there will be some routes exchange
264 ivpnLinkService.exchangeRoutes(interVpnLink.get());
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);
282 private boolean checkVpnAvailability(InterVpnLinkKey key, String vpnName) {
283 Preconditions.checkNotNull(vpnName);
285 List<InterVpnLinkDataComposite> allInterVpnLinks = interVpnLinkCache.getAllInterVpnLinks();
286 if (allInterVpnLinks.isEmpty()) {
290 return allInterVpnLinks.stream().noneMatch(ivl -> !ivl.getInterVpnLinkName().equals(key.getName())
291 && ivl.isVpnLinked(vpnName));
295 public void remove(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink del) {
297 LOG.debug("Reacting to InterVpnLink {} removal", del.getName());
299 // Remove learnt routes
300 // Remove entries in the LPortDispatcher table
301 // Remove the corresponding entries in InterVpnLinkState
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());
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());
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);
330 LOG.info("Could not get first endpoint state attributes for InterVpnLink {}", del.getName());
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);
341 LOG.info("Could not get second endpoint state attributes for InterVpnLink {}", del.getName());
345 vpnUtil.removeVrfEntries(rd1, vrfEntriesSecondEndpoint);
346 vpnUtil.removeVrfEntries(rd2, vrfEntriesFirstEndpoint);
347 vpnUtil.withdrawRoutes(rd1, vrfEntriesSecondEndpoint);
348 vpnUtil.withdrawRoutes(rd2, vrfEntriesFirstEndpoint);
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());
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.
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);
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) {
377 String interVpnLinkName = del.getName();
378 LOG.debug("Removing endpoint flows for vpn {}. InterVpnLink={}. OtherEndpointLportTag={}",
379 vpnUuid, interVpnLinkName, otherEndpointLportTag);
381 LOG.debug("VPN {} endpoint is not instantiated in any DPN for InterVpnLink {}",
382 vpnUuid, interVpnLinkName);
386 for (Uint64 dpnId : dpns) {
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)
394 mdsalManager.removeFlow(dpnId, flow);
396 // Also remove the 'fake' iface from the VpnToDpn map
397 interVpnLinkUtil.removeIVpnLinkIfaceFromVpnFootprint(vpnUuid, rd, dpnId);
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);
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);
412 private void releaseVpnLinkLPortTag(String idKey) {
413 ReleaseIdInput releaseIdInput =
414 new ReleaseIdInputBuilder().setPoolName(VpnConstants.PSEUDO_LPORT_TAG_ID_POOL_NAME).setIdKey(idKey).build();
416 LoggingFutures.addErrorLogging(idManager.releaseId(releaseIdInput), LOG, "Release Id");
420 public void update(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink original, InterVpnLink update) {
422 LOG.debug("Update InterVpnLink {}. "
423 + " original=[1stEndpoint=[vpn=<{}> ipAddr=<{}>] 2ndEndpoint=[vpn=<{}> ipAddr=<{}>]]"
424 + " update=[1stEndpoint=[vpn=<{}> ipAddr=<{}>] 2ndEndpoint=[vpn=<{}> ipAddr=<{}>]]",
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());
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));
438 private Long allocateVpnLinkLportTag(String idKey) {
439 AllocateIdInput getIdInput =
440 new AllocateIdInputBuilder().setPoolName(VpnConstants.PSEUDO_LPORT_TAG_ID_POOL_NAME)
444 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
445 RpcResult<AllocateIdOutput> rpcResult = result.get();
446 if (rpcResult.isSuccessful()) {
447 return rpcResult.getResult().getIdValue().toJava();
449 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
451 } catch (InterruptedException | ExecutionException e) {
452 LOG.warn("Exception when getting Unique Id", e);
457 protected void setInError(final InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid,
458 final InterVpnLinkState vpnLinkState,
460 LOG.error("Setting InterVpnLink {} in error. Reason: {}", vpnLinkState.getInterVpnLinkName(), errorMsg);
462 // Setting InterVPNLink in error state in MDSAL
463 InterVpnLinkState vpnLinkErrorState =
464 new InterVpnLinkStateBuilder(vpnLinkState).setState(InterVpnLinkState.State.Error)
465 .setErrorDescription(errorMsg)
467 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx ->
468 tx.mergeParentStructurePut(vpnLinkStateIid, vpnLinkErrorState)),
469 LOG, "Error storing the VPN link error state for {}, {}", vpnLinkStateIid, vpnLinkErrorState);
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>() {
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);
485 public void onSuccess(Object arg) {
486 LOG.trace("Error notification for InterVpnLink successfully sent. VpnLinkName={} state={}",
487 vpnLinkState.getInterVpnLinkName(), vpnLinkState);
489 }, MoreExecutors.directExecutor());
493 * Removes all the flows from FIB/LFIB matching an endpoint from the intervpnlink.
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
499 private void cleanUpInterVPNRoutes(final String interVpnLinkName,
500 List<VrfEntry> vrfEntries,
501 final boolean isVpnFirstEndPoint) {
503 for (VrfEntry vrfEntry : vrfEntries) {
504 fibManager.removeInterVPNLinkRouteFlows(interVpnLinkName, isVpnFirstEndPoint, vrfEntry);