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 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;
81 public class InterVpnLinkListener extends AsyncDataTreeChangeListenerBase<InterVpnLink, InterVpnLinkListener> {
83 private static final Logger LOG = LoggerFactory.getLogger(InterVpnLinkListener.class);
85 private static final long INVALID_ID = 0;
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;
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;
127 public void start() {
128 LOG.info("{} start", getClass().getSimpleName());
129 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
133 protected InstanceIdentifier<InterVpnLink> getWildCardPath() {
134 return InstanceIdentifier.create(InterVpnLinks.class).child(InterVpnLink.class);
138 protected InterVpnLinkListener getDataTreeChangeListener() {
139 return InterVpnLinkListener.this;
143 protected void add(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink add) {
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());
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);
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 "
167 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
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);
178 if (VpnUtil.getVpnInstance(this.dataBroker, vpn2Name) == null) {
179 String errMsg = "InterVpnLink " + ivpnLinkName + " creation error: could not find 2nd endpoint Vpn "
181 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
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);
191 interVpnLinkCache.addInterVpnLinkToCaches(add);
193 // Wait for VPN Operational data ready
194 long vpn1Id = VpnUtil.getVpnId(dataBroker, vpn1Name);
195 if (vpn1Id == VpnConstants.INVALID_ID) {
197 vpnOpDataSyncer.waitForVpnDataReady(VpnOpDataSyncer.VpnOpDataType.vpnInstanceToId, vpn1Name,
198 VpnConstants.PER_VPN_INSTANCE_MAX_WAIT_TIME_IN_MILLISECONDS);
201 "InterVpnLink " + ivpnLinkName + " creation error: Operational Data for VPN " + vpn1Name
202 + " not ready after " + VpnConstants.PER_INTERFACE_MAX_WAIT_TIME_IN_MILLISECONDS
204 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
208 long vpn2Id = VpnUtil.getVpnId(dataBroker, vpn2Name);
209 if (vpn2Id == VpnConstants.INVALID_ID) {
211 vpnOpDataSyncer.waitForVpnDataReady(VpnOpDataSyncer.VpnOpDataType.vpnInstanceToId,vpn2Name,
212 VpnConstants.PER_VPN_INSTANCE_MAX_WAIT_TIME_IN_MILLISECONDS);
215 "InterVpnLink " + ivpnLinkName + " creation error: Operational Data for VPN " + vpn2Name
216 + " not ready after " + VpnConstants.PER_INTERFACE_MAX_WAIT_TIME_IN_MILLISECONDS
218 setInError(vpnLinkStateIid, vpnLinkState, errMsg);
223 List<BigInteger> firstDpnList = ivpnLinkLocator.selectSuitableDpns(add);
224 if (firstDpnList != null && !firstDpnList.isEmpty()) {
225 List<BigInteger> secondDpnList = firstDpnList;
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();
236 InterVpnLinkUtil.updateInterVpnLinkState(dataBroker, ivpnLinkName, InterVpnLinkState.State.Active,
237 firstEndPointState, secondEndPointState, interVpnLinkCache);
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);
252 // Program static routes if needed
253 Optional<InterVpnLinkDataComposite> interVpnLink =
254 interVpnLinkCache.getInterVpnLinkByName(ivpnLinkName);
255 ivpnLinkService.handleStaticRoutes(interVpnLink.get());
257 // Now, if the corresponding flags are activated, there will be some routes exchange
258 ivpnLinkService.exchangeRoutes(interVpnLink.get());
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);
276 private boolean checkVpnAvailability(InterVpnLinkKey key, String vpnName) {
277 Preconditions.checkNotNull(vpnName);
279 List<InterVpnLinkDataComposite> allInterVpnLinks = interVpnLinkCache.getAllInterVpnLinks();
280 if (allInterVpnLinks.isEmpty()) {
284 return allInterVpnLinks.stream().noneMatch(ivl -> !ivl.getInterVpnLinkName().equals(key.getName())
285 && ivl.isVpnLinked(vpnName));
289 protected void remove(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink del) {
291 LOG.debug("Reacting to InterVpnLink {} removal", del.getName());
293 // Remove learnt routes
294 // Remove entries in the LPortDispatcher table
295 // Remove the corresponding entries in InterVpnLinkState
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());
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());
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);
324 LOG.info("Could not get first endpoint state attributes for InterVpnLink {}", del.getName());
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);
335 LOG.info("Could not get second endpoint state attributes for InterVpnLink {}", del.getName());
339 VpnUtil.removeVrfEntries(dataBroker, rd1, vrfEntriesSecondEndpoint);
340 VpnUtil.removeVrfEntries(dataBroker, rd2, vrfEntriesFirstEndpoint);
341 VpnUtil.withdrawRoutes(bgpManager, rd1, vrfEntriesSecondEndpoint);
342 VpnUtil.withdrawRoutes(bgpManager, rd2, vrfEntriesFirstEndpoint);
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());
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.
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);
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) {
372 String interVpnLinkName = del.getName();
373 LOG.debug("Removing endpoint flows for vpn {}. InterVpnLink={}. OtherEndpointLportTag={}",
374 vpnUuid, interVpnLinkName, otherEndpointLportTag);
376 LOG.debug("VPN {} endpoint is not instantiated in any DPN for InterVpnLink {}",
377 vpnUuid, interVpnLinkName);
381 for (BigInteger dpnId : dpns) {
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)
389 mdsalManager.removeFlow(dpnId, flow);
391 // Also remove the 'fake' iface from the VpnToDpn map
392 InterVpnLinkUtil.removeIVpnLinkIfaceFromVpnFootprint(vpnFootprintService, vpnUuid, rd, dpnId);
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);
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);
407 private void releaseVpnLinkLPortTag(String idKey) {
408 ReleaseIdInput releaseIdInput =
409 new ReleaseIdInputBuilder().setPoolName(VpnConstants.PSEUDO_LPORT_TAG_ID_POOL_NAME).setIdKey(idKey).build();
411 JdkFutures.addErrorLogging(idManager.releaseId(releaseIdInput), LOG, "Release Id");
415 protected void update(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink original, InterVpnLink update) {
417 LOG.debug("Update InterVpnLink {}. "
418 + " original=[1stEndpoint=[vpn=<{}> ipAddr=<{}>] 2ndEndpoint=[vpn=<{}> ipAddr=<{}>]]"
419 + " update=[1stEndpoint=[vpn=<{}> ipAddr=<{}>] 2ndEndpoint=[vpn=<{}> ipAddr=<{}>]]",
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());
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));
432 private Long allocateVpnLinkLportTag(String idKey) {
433 AllocateIdInput getIdInput =
434 new AllocateIdInputBuilder().setPoolName(VpnConstants.PSEUDO_LPORT_TAG_ID_POOL_NAME)
438 Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
439 RpcResult<AllocateIdOutput> rpcResult = result.get();
440 if (rpcResult.isSuccessful()) {
441 return rpcResult.getResult().getIdValue();
443 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
445 } catch (InterruptedException | ExecutionException e) {
446 LOG.warn("Exception when getting Unique Id", e);
451 protected void setInError(final InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid,
452 final InterVpnLinkState vpnLinkState,
454 LOG.error("Setting InterVpnLink {} in error. Reason: {}", vpnLinkState.getInterVpnLinkName(), errorMsg);
456 // Setting InterVPNLink in error state in MDSAL
457 InterVpnLinkState vpnLinkErrorState =
458 new InterVpnLinkStateBuilder(vpnLinkState).setState(InterVpnLinkState.State.Error)
459 .setErrorDescription(errorMsg)
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);
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>() {
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);
480 public void onSuccess(Object arg) {
481 LOG.trace("Error notification for InterVpnLink successfully sent. VpnLinkName={} state={}",
482 vpnLinkState.getInterVpnLinkName(), vpnLinkState);
484 }, MoreExecutors.directExecutor());
488 * Removes all the flows from FIB/LFIB matching an endpoint from the intervpnlink.
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
494 private void cleanUpInterVPNRoutes(final String interVpnLinkName,
495 List<VrfEntry> vrfEntries,
496 final boolean isVpnFirstEndPoint) {
498 for (VrfEntry vrfEntry : vrfEntries) {
499 fibManager.removeInterVPNLinkRouteFlows(interVpnLinkName, isVpnFirstEndPoint, vrfEntry);