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.LoggingFutures;
33 import org.opendaylight.mdsal.binding.api.DataBroker;
34 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
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;
83 public class InterVpnLinkListener extends AbstractAsyncDataTreeChangeListener<InterVpnLink> {
85 private static final Logger LOG = LoggerFactory.getLogger(InterVpnLinkListener.class);
87 private static final long INVALID_ID = 0;
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;
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;
136 public void start() {
137 LOG.info("{} start", getClass().getSimpleName());
142 public void close() {
144 Executors.shutdownAndAwaitTermination(getExecutorService());
148 public void add(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink add) {
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());
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);
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 "
172 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
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);
183 if (vpnUtil.getVpnInstance(vpn2Name) == null) {
184 String errMsg = "InterVpnLink " + ivpnLinkName + " creation error: could not find 2nd endpoint Vpn "
186 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
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);
196 interVpnLinkCache.addInterVpnLinkToCaches(add);
198 // Wait for VPN Operational data ready
199 Uint32 vpn1Id = vpnUtil.getVpnId(vpn1Name);
200 if (VpnConstants.INVALID_ID.equals(vpn1Id)) {
202 vpnOpDataSyncer.waitForVpnDataReady(VpnOpDataSyncer.VpnOpDataType.vpnInstanceToId, vpn1Name,
203 VpnConstants.PER_VPN_INSTANCE_MAX_WAIT_TIME_IN_MILLISECONDS);
206 "InterVpnLink " + ivpnLinkName + " creation error: Operational Data for VPN " + vpn1Name
207 + " not ready after " + VpnConstants.PER_INTERFACE_MAX_WAIT_TIME_IN_MILLISECONDS
209 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
213 Uint32 vpn2Id = vpnUtil.getVpnId(vpn2Name);
214 if (VpnConstants.INVALID_ID.equals(vpn2Id)) {
216 vpnOpDataSyncer.waitForVpnDataReady(VpnOpDataSyncer.VpnOpDataType.vpnInstanceToId,vpn2Name,
217 VpnConstants.PER_VPN_INSTANCE_MAX_WAIT_TIME_IN_MILLISECONDS);
220 "InterVpnLink " + ivpnLinkName + " creation error: Operational Data for VPN " + vpn2Name
221 + " not ready after " + VpnConstants.PER_INTERFACE_MAX_WAIT_TIME_IN_MILLISECONDS
223 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
228 List<Uint64> firstDpnList = ivpnLinkLocator.selectSuitableDpns(add);
229 if (firstDpnList != null && !firstDpnList.isEmpty()) {
230 List<Uint64> secondDpnList = firstDpnList;
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();
241 interVpnLinkUtil.updateInterVpnLinkState(ivpnLinkName, InterVpnLinkState.State.Active,
242 firstEndPointState, secondEndPointState, interVpnLinkCache);
244 // Note that in the DPN of the firstEndpoint we install the lportTag of the secondEndpoint and viceversa
245 interVpnLinkUtil.installLPortDispatcherTableFlow(ivpnLinkName, firstDpnList, vpn2Name,
247 interVpnLinkUtil.installLPortDispatcherTableFlow(ivpnLinkName, secondDpnList, vpn1Name,
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);
257 // Program static routes if needed
258 Optional<InterVpnLinkDataComposite> interVpnLink =
259 interVpnLinkCache.getInterVpnLinkByName(ivpnLinkName);
260 ivpnLinkService.handleStaticRoutes(interVpnLink.get());
262 // Now, if the corresponding flags are activated, there will be some routes exchange
263 ivpnLinkService.exchangeRoutes(interVpnLink.get());
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);
281 private boolean checkVpnAvailability(InterVpnLinkKey key, String vpnName) {
282 Preconditions.checkNotNull(vpnName);
284 List<InterVpnLinkDataComposite> allInterVpnLinks = interVpnLinkCache.getAllInterVpnLinks();
285 if (allInterVpnLinks.isEmpty()) {
289 return allInterVpnLinks.stream().noneMatch(ivl -> !ivl.getInterVpnLinkName().equals(key.getName())
290 && ivl.isVpnLinked(vpnName));
294 public void remove(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink del) {
296 LOG.debug("Reacting to InterVpnLink {} removal", del.getName());
298 // Remove learnt routes
299 // Remove entries in the LPortDispatcher table
300 // Remove the corresponding entries in InterVpnLinkState
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());
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());
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);
329 LOG.info("Could not get first endpoint state attributes for InterVpnLink {}", del.getName());
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);
340 LOG.info("Could not get second endpoint state attributes for InterVpnLink {}", del.getName());
344 vpnUtil.removeVrfEntries(rd1, vrfEntriesSecondEndpoint);
345 vpnUtil.removeVrfEntries(rd2, vrfEntriesFirstEndpoint);
346 vpnUtil.withdrawRoutes(rd1, vrfEntriesSecondEndpoint);
347 vpnUtil.withdrawRoutes(rd2, vrfEntriesFirstEndpoint);
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());
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.
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);
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) {
376 String interVpnLinkName = del.getName();
377 LOG.debug("Removing endpoint flows for vpn {}. InterVpnLink={}. OtherEndpointLportTag={}",
378 vpnUuid, interVpnLinkName, otherEndpointLportTag);
380 LOG.debug("VPN {} endpoint is not instantiated in any DPN for InterVpnLink {}",
381 vpnUuid, interVpnLinkName);
385 for (Uint64 dpnId : dpns) {
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)
393 mdsalManager.removeFlow(dpnId, flow);
395 // Also remove the 'fake' iface from the VpnToDpn map
396 interVpnLinkUtil.removeIVpnLinkIfaceFromVpnFootprint(vpnUuid, rd, dpnId);
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);
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);
411 private void releaseVpnLinkLPortTag(String idKey) {
412 ReleaseIdInput releaseIdInput =
413 new ReleaseIdInputBuilder().setPoolName(VpnConstants.PSEUDO_LPORT_TAG_ID_POOL_NAME).setIdKey(idKey).build();
415 LoggingFutures.addErrorLogging(idManager.releaseId(releaseIdInput), LOG, "Release Id");
419 public void update(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink original, InterVpnLink update) {
421 LOG.debug("Update InterVpnLink {}. "
422 + " original=[1stEndpoint=[vpn=<{}> ipAddr=<{}>] 2ndEndpoint=[vpn=<{}> ipAddr=<{}>]]"
423 + " update=[1stEndpoint=[vpn=<{}> ipAddr=<{}>] 2ndEndpoint=[vpn=<{}> ipAddr=<{}>]]",
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());
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));
437 private Long allocateVpnLinkLportTag(String idKey) {
438 AllocateIdInput getIdInput =
439 new AllocateIdInputBuilder().setPoolName(VpnConstants.PSEUDO_LPORT_TAG_ID_POOL_NAME)
443 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
444 RpcResult<AllocateIdOutput> rpcResult = result.get();
445 if (rpcResult.isSuccessful()) {
446 return rpcResult.getResult().getIdValue().toJava();
448 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
450 } catch (InterruptedException | ExecutionException e) {
451 LOG.warn("Exception when getting Unique Id", e);
456 protected void setInError(final InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid,
457 final InterVpnLinkState vpnLinkState,
459 LOG.error("Setting InterVpnLink {} in error. Reason: {}", vpnLinkState.getInterVpnLinkName(), errorMsg);
461 // Setting InterVPNLink in error state in MDSAL
462 InterVpnLinkState vpnLinkErrorState =
463 new InterVpnLinkStateBuilder(vpnLinkState).setState(InterVpnLinkState.State.Error)
464 .setErrorDescription(errorMsg)
466 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx ->
467 tx.mergeParentStructurePut(vpnLinkStateIid, vpnLinkErrorState)),
468 LOG, "Error storing the VPN link error state for {}, {}", vpnLinkStateIid, vpnLinkErrorState);
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>() {
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);
484 public void onSuccess(Object arg) {
485 LOG.trace("Error notification for InterVpnLink successfully sent. VpnLinkName={} state={}",
486 vpnLinkState.getInterVpnLinkName(), vpnLinkState);
488 }, MoreExecutors.directExecutor());
492 * Removes all the flows from FIB/LFIB matching an endpoint from the intervpnlink.
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
498 private void cleanUpInterVPNRoutes(final String interVpnLinkName,
499 List<VrfEntry> vrfEntries,
500 final boolean isVpnFirstEndPoint) {
502 for (VrfEntry vrfEntry : vrfEntries) {
503 fibManager.removeInterVPNLinkRouteFlows(interVpnLinkName, isVpnFirstEndPoint, vrfEntry);