2 * Copyright (c) 2016 - 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;
10 import static java.util.Collections.emptyList;
11 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
13 import static org.opendaylight.mdsal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
15 import com.google.common.base.Preconditions;
16 import com.google.common.collect.Iterators;
17 import com.google.common.util.concurrent.FutureCallback;
18 import com.google.common.util.concurrent.Futures;
19 import com.google.common.util.concurrent.ListenableFuture;
20 import com.google.common.util.concurrent.MoreExecutors;
21 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.HashSet;
25 import java.util.List;
27 import java.util.Objects;
28 import java.util.Optional;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.concurrent.ConcurrentLinkedQueue;
32 import java.util.concurrent.ExecutionException;
33 import java.util.concurrent.locks.ReentrantLock;
34 import java.util.function.Consumer;
35 import java.util.function.Predicate;
36 import java.util.stream.Collectors;
37 import javax.annotation.PreDestroy;
38 import javax.inject.Inject;
39 import javax.inject.Singleton;
40 import org.eclipse.jdt.annotation.Nullable;
41 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
42 import org.opendaylight.genius.infra.Datastore.Configuration;
43 import org.opendaylight.genius.infra.Datastore.Operational;
44 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
45 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
46 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
47 import org.opendaylight.genius.infra.TypedWriteTransaction;
48 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
49 import org.opendaylight.genius.mdsalutil.NWUtil;
50 import org.opendaylight.genius.mdsalutil.NwConstants;
51 import org.opendaylight.genius.mdsalutil.cache.InstanceIdDataObjectCache;
52 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
53 import org.opendaylight.genius.utils.JvmGlobalLocks;
54 import org.opendaylight.infrautils.caches.CacheProvider;
55 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
56 import org.opendaylight.infrautils.utils.concurrent.Executors;
57 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
58 import org.opendaylight.mdsal.binding.api.DataBroker;
59 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
60 import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
61 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
62 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
63 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
64 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
65 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
66 import org.opendaylight.netvirt.vpnmanager.api.InterfaceUtils;
67 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
68 import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderHandler;
69 import org.opendaylight.netvirt.vpnmanager.populator.input.L3vpnInput;
70 import org.opendaylight.netvirt.vpnmanager.populator.intfc.VpnPopulator;
71 import org.opendaylight.netvirt.vpnmanager.populator.registry.L3vpnRegistry;
72 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
73 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
74 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterfaceBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.VrfEntryBase;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListKey;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntryBuilder;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntryKey;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTarget;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.Adjacencies;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.VpnInterfaces;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.Adjacency;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.Adjacency.AdjacencyType;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.AdjacencyBuilder;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.VpnInterface;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.VpnInterfaceKey;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.vpn._interface.VpnInstanceNames;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes.NetworkType;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
118 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
119 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
120 import org.opendaylight.yangtools.yang.common.Uint32;
121 import org.opendaylight.yangtools.yang.common.Uint64;
122 import org.slf4j.Logger;
123 import org.slf4j.LoggerFactory;
126 public class VpnInterfaceManager extends AbstractAsyncDataTreeChangeListener<VpnInterface> {
128 private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
129 private static final short DJC_MAX_RETRIES = 3;
131 private final DataBroker dataBroker;
132 private final ManagedNewTransactionRunner txRunner;
133 private final IBgpManager bgpManager;
134 private final IFibManager fibManager;
135 private final IMdsalApiManager mdsalManager;
136 private final IdManagerService idManager;
137 private final OdlInterfaceRpcService ifaceMgrRpcService;
138 private final VpnFootprintService vpnFootprintService;
139 private final IInterfaceManager interfaceManager;
140 private final IVpnManager vpnManager;
141 private final ArpResponderHandler arpResponderHandler;
142 private final JobCoordinator jobCoordinator;
143 private final VpnUtil vpnUtil;
145 private final ConcurrentHashMap<String, Runnable> vpnIntfMap = new ConcurrentHashMap<>();
147 private final Map<String, ConcurrentLinkedQueue<UnprocessedVpnInterfaceData>> unprocessedVpnInterfaces =
148 new ConcurrentHashMap<>();
150 private final InstanceIdDataObjectCache<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryCache;
153 public VpnInterfaceManager(final DataBroker dataBroker,
154 final IBgpManager bgpManager,
155 final IdManagerService idManager,
156 final IMdsalApiManager mdsalManager,
157 final IFibManager fibManager,
158 final OdlInterfaceRpcService ifaceMgrRpcService,
159 final VpnFootprintService vpnFootprintService,
160 final IInterfaceManager interfaceManager,
161 final IVpnManager vpnManager,
162 final ArpResponderHandler arpResponderHandler,
163 final JobCoordinator jobCoordinator,
164 final CacheProvider cacheProvider,
165 final VpnUtil vpnUtil) {
166 super(dataBroker, LogicalDatastoreType.CONFIGURATION,
167 InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class),
168 Executors.newListeningSingleThreadExecutor("VpnInterfaceManager", LOG));
170 this.dataBroker = dataBroker;
171 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
172 this.bgpManager = bgpManager;
173 this.idManager = idManager;
174 this.mdsalManager = mdsalManager;
175 this.fibManager = fibManager;
176 this.ifaceMgrRpcService = ifaceMgrRpcService;
177 this.vpnFootprintService = vpnFootprintService;
178 this.interfaceManager = interfaceManager;
179 this.vpnManager = vpnManager;
180 this.arpResponderHandler = arpResponderHandler;
181 this.jobCoordinator = jobCoordinator;
182 this.vpnUtil = vpnUtil;
184 vpnInstanceOpDataEntryCache = new InstanceIdDataObjectCache<>(VpnInstanceOpDataEntry.class, dataBroker,
185 LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(
186 VpnInstanceOpData.class).child(VpnInstanceOpDataEntry.class).build(), cacheProvider);
190 public Runnable isNotifyTaskQueued(String intfName) {
191 return vpnIntfMap.remove(intfName);
194 public void start() {
195 LOG.info("{} start", getClass().getSimpleName());
200 public void close() {
202 vpnInstanceOpDataEntryCache.close();
203 Executors.shutdownAndAwaitTermination(getExecutorService());
207 public void add(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface) {
208 LOG.trace("Received VpnInterface add event: vpnInterface={}", vpnInterface);
209 LOG.info("add: intfName {} onto vpnName {}", vpnInterface.getName(),
210 VpnHelper.getVpnInterfaceVpnInstanceNamesString(vpnInterface.getVpnInstanceNames()));
211 addVpnInterface(identifier, vpnInterface, null, null);
214 private boolean canHandleNewVpnInterface(final InstanceIdentifier<VpnInterface> identifier,
215 final VpnInterface vpnInterface, String vpnName) {
216 // FIXME: separate this out somehow?
217 final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnName);
220 if (isVpnInstanceReady(vpnName)) {
223 addToUnprocessedVpnInterfaces(identifier, vpnInterface, vpnName);
230 // TODO Clean up the exception handling
231 @SuppressWarnings("checkstyle:IllegalCatch")
232 private void addVpnInterface(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface,
233 final @Nullable List<Adjacency> oldAdjs, final @Nullable List<Adjacency> newAdjs) {
234 for (VpnInstanceNames vpnInterfaceVpnInstance : vpnInterface.nonnullVpnInstanceNames()) {
235 String vpnName = vpnInterfaceVpnInstance.getVpnName();
236 addVpnInterfaceCall(identifier, vpnInterface, oldAdjs, newAdjs, vpnName);
240 private void addVpnInterfaceCall(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface,
241 final List<Adjacency> oldAdjs, final List<Adjacency> newAdjs, String vpnName) {
242 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class);
243 final String interfaceName = key.getName();
245 if (!canHandleNewVpnInterface(identifier, vpnInterface, vpnName)) {
246 LOG.error("add: VpnInstance {} for vpnInterface {} not ready, holding on ",
247 vpnName, vpnInterface.getName());
250 InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier = VpnUtil
251 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
252 List<Adjacency> copyOldAdjs = null;
253 if (oldAdjs != null) {
254 copyOldAdjs = new ArrayList<>();
255 copyOldAdjs.addAll(oldAdjs);
257 List<Adjacency> copyNewAdjs = null;
258 if (newAdjs != null) {
259 copyNewAdjs = new ArrayList<>();
260 copyNewAdjs.addAll(newAdjs);
262 addVpnInterfaceToVpn(vpnInterfaceOpIdentifier, vpnInterface, copyOldAdjs, copyNewAdjs, identifier, vpnName);
265 private void addVpnInterfaceToVpn(final InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier,
266 final VpnInterface vpnInterface, final @Nullable List<Adjacency> oldAdjs,
267 final @Nullable List<Adjacency> newAdjs,
268 final InstanceIdentifier<VpnInterface> identifier, String vpnName) {
269 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class);
270 final String interfaceName = key.getName();
271 String primaryRd = vpnUtil.getPrimaryRd(vpnName);
272 if (!vpnUtil.isVpnPendingDelete(primaryRd)) {
273 Interface interfaceState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker, interfaceName);
274 boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(vpnName);
275 if (interfaceState != null) {
277 final Uint64 dpnId = InterfaceUtils.getDpIdFromInterface(interfaceState);
278 final int ifIndex = interfaceState.getIfIndex();
279 jobCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName, () -> {
280 // TODO Deal with sequencing — the config tx must only submitted if the oper tx goes in
281 // (the inventory tx goes in last)
282 List<ListenableFuture<Void>> futures = new ArrayList<>();
283 //set of prefix used, as entry in prefix-to-interface datastore
284 // is prerequisite for refresh Fib to avoid race condition leading to
285 // missing remote next hop in bucket actions on bgp-vpn delete
286 Set<String> prefixListForRefreshFib = new HashSet<>();
287 ListenableFuture<Void> confFuture =
288 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
289 confTx -> futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
290 operTx -> futures.add(
291 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, invTx -> {
293 "addVpnInterface: VPN Interface add event - intfName {} vpnName {}"
295 vpnInterface.getName(), vpnName, vpnInterface.getDpnId());
296 processVpnInterfaceUp(dpnId, vpnInterface, primaryRd, ifIndex, false,
297 confTx, operTx, invTx, interfaceState, vpnName,
298 prefixListForRefreshFib);
299 if (oldAdjs != null && !oldAdjs.equals(newAdjs)) {
300 LOG.info("addVpnInterface: Adjacency changed upon VPNInterface {}"
301 + " Update for swapping VPN {} case.", interfaceName, vpnName);
302 if (newAdjs != null) {
303 for (Adjacency adj : newAdjs) {
304 if (oldAdjs.contains(adj)) {
307 if (!isBgpVpnInternetVpn
308 || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
309 addNewAdjToVpnInterface(vpnInterfaceOpIdentifier,
310 primaryRd, adj, dpnId, operTx, confTx, invTx,
311 prefixListForRefreshFib);
316 for (Adjacency adj : oldAdjs) {
317 if (!isBgpVpnInternetVpn
318 || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
319 delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId,
325 Futures.addCallback(confFuture,
326 new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
327 MoreExecutors.directExecutor());
328 futures.add(confFuture);
329 Futures.addCallback(confFuture, new PostVpnInterfaceWorker(interfaceName, true, "Config"),
330 MoreExecutors.directExecutor());
331 LOG.info("addVpnInterface: Addition of interface {} in VPN {} on dpn {}"
332 + " processed successfully", interfaceName, vpnName, dpnId);
335 } catch (NumberFormatException | IllegalStateException e) {
336 LOG.error("addVpnInterface: Unable to retrieve dpnId from interface operational data store for "
337 + "interface {}. Interface addition on vpn {} failed", interfaceName,
341 } else if (Boolean.TRUE.equals(vpnInterface.isRouterInterface())) {
342 jobCoordinator.enqueueJob("VPNINTERFACE-" + vpnInterface.getName(),
344 ListenableFuture<Void> future =
345 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
346 createFibEntryForRouterInterface(primaryRd, vpnInterface, interfaceName,
348 LOG.info("addVpnInterface: Router interface {} for vpn {} on dpn {}", interfaceName,
349 vpnName, vpnInterface.getDpnId());
351 ListenableFutures.addErrorLogging(future, LOG,
352 "Error creating FIB entry for interface {} on VPN {}", vpnInterface.getName(), vpnName);
353 return Collections.singletonList(future);
356 LOG.info("addVpnInterface: Handling addition of VPN interface {} on vpn {} skipped as interfaceState"
357 + " is not available", interfaceName, vpnName);
360 LOG.error("addVpnInterface: Handling addition of VPN interface {} on vpn {} dpn {} skipped"
361 + " as vpn is pending delete", interfaceName, vpnName,
362 vpnInterface.getDpnId());
366 // "Unconditional wait" and "Wait not in loop" wrt the VpnNotifyTask below - suppressing the FB violation -
367 // see comments below.
368 @SuppressFBWarnings({"UW_UNCOND_WAIT", "WA_NOT_IN_LOOP"})
369 protected void processVpnInterfaceUp(final Uint64 dpId, VpnInterface vpnInterface, final String primaryRd,
370 final int lportTag, boolean isInterfaceUp,
371 TypedWriteTransaction<Configuration> writeConfigTxn,
372 TypedWriteTransaction<Operational> writeOperTxn,
373 TypedReadWriteTransaction<Configuration> writeInvTxn,
374 Interface interfaceState, final String vpnName,
375 Set<String> prefixListForRefreshFib) throws ExecutionException, InterruptedException {
376 final String interfaceName = vpnInterface.getName();
377 Optional<VpnInterfaceOpDataEntry> optOpVpnInterface = vpnUtil.getVpnInterfaceOpDataEntry(interfaceName,
379 VpnInterfaceOpDataEntry opVpnInterface = optOpVpnInterface.isPresent() ? optOpVpnInterface.get() : null;
380 boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(vpnName);
381 if (!isInterfaceUp) {
382 LOG.info("processVpnInterfaceUp: Binding vpn service to interface {} onto dpn {} for vpn {}",
383 interfaceName, dpId, vpnName);
384 Uint32 vpnId = vpnUtil.getVpnId(vpnName);
385 if (VpnConstants.INVALID_ID.equals(vpnId)) {
386 LOG.warn("processVpnInterfaceUp: VpnInstance to VPNId mapping not available for VpnName {}"
387 + " processing vpninterface {} on dpn {}, bailing out now.", vpnName, interfaceName,
392 boolean waitForVpnInterfaceOpRemoval = false;
393 if (opVpnInterface != null) {
394 String opVpnName = opVpnInterface.getVpnInstanceName();
395 String primaryInterfaceIp = null;
396 if (Objects.equals(opVpnName, vpnName)) {
397 // Please check if the primary VRF Entry does not exist for VPNInterface
398 // If so, we have to process ADD, as this might be a DPN Restart with Remove and Add triggered
400 // However, if the primary VRF Entry for this VPNInterface exists, please continue bailing out !
401 List<Adjacency> adjs = vpnUtil.getAdjacenciesForVpnInterfaceFromConfig(interfaceName);
403 LOG.error("processVpnInterfaceUp: VPN Interface {} on dpn {} for vpn {} failed as adjacencies"
404 + " for this vpn interface could not be obtained", interfaceName, dpId,
408 for (Adjacency adj : adjs) {
409 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
410 primaryInterfaceIp = adj.getIpAddress();
414 if (primaryInterfaceIp == null) {
415 LOG.error("processVpnInterfaceUp: VPN Interface {} addition on dpn {} for vpn {} failed"
416 + " as primary adjacency for this vpn interface could not be obtained", interfaceName,
420 // Get the rd of the vpn instance
421 VrfEntry vrf = vpnUtil.getVrfEntry(primaryRd, primaryInterfaceIp);
423 LOG.error("processVpnInterfaceUp: VPN Interface {} on dpn {} for vpn {} already provisioned ,"
424 + " bailing out from here.", interfaceName, dpId, vpnName);
427 waitForVpnInterfaceOpRemoval = true;
429 LOG.error("processVpnInterfaceUp: vpn interface {} to go to configured vpn {} on dpn {},"
430 + " but in operational vpn {}", interfaceName, vpnName, dpId, opVpnName);
433 if (!waitForVpnInterfaceOpRemoval) {
434 // Add the VPNInterface and quit
435 vpnFootprintService.updateVpnToDpnMapping(dpId, vpnName, primaryRd, interfaceName,
436 null/*ipAddressSourceValuePair*/,
438 processVpnInterfaceAdjacencies(dpId, lportTag, vpnName, primaryRd, interfaceName,
439 vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState, prefixListForRefreshFib);
440 if (!isBgpVpnInternetVpn) {
441 vpnUtil.bindService(vpnName, interfaceName, false /*isTunnelInterface*/);
443 LOG.info("processVpnInterfaceUp: Plumbed vpn interface {} onto dpn {} for vpn {}", interfaceName,
445 if (interfaceManager.isExternalInterface(interfaceName)) {
446 processExternalVpnInterface(interfaceName, vpnName, dpId, lportTag,
447 NwConstants.ADD_FLOW);
452 // FIB didn't get a chance yet to clean up this VPNInterface
453 // Let us give it a chance here !
454 LOG.info("processVpnInterfaceUp: Trying to add VPN Interface {} on dpn {} for vpn {},"
455 + " but waiting for FIB to clean up! ", interfaceName, dpId, vpnName);
457 Runnable notifyTask = new VpnNotifyTask();
458 synchronized (notifyTask) {
459 // Per FB's "Unconditional wait" violation, the code should really verify that the condition it
460 // intends to wait for is not already satisfied before calling wait. However the VpnNotifyTask is
461 // published here while holding the lock on it so this path will hit the wait before notify can be
463 vpnIntfMap.put(interfaceName, notifyTask);
465 notifyTask.wait(VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS);
466 } catch (InterruptedException e) {
471 vpnIntfMap.remove(interfaceName);
474 if (opVpnInterface != null) {
475 LOG.warn("processVpnInterfaceUp: VPN Interface {} removal on dpn {} for vpn {}"
476 + " by FIB did not complete on time," + " bailing addition ...", interfaceName,
478 vpnUtil.unsetScheduledToRemoveForVpnInterface(interfaceName);
481 // VPNInterface got removed, proceed with Add
482 LOG.info("processVpnInterfaceUp: Continuing to plumb vpn interface {} onto dpn {} for vpn {}",
483 interfaceName, dpId, vpnName);
484 vpnFootprintService.updateVpnToDpnMapping(dpId, vpnName, primaryRd, interfaceName,
485 null/*ipAddressSourceValuePair*/,
487 processVpnInterfaceAdjacencies(dpId, lportTag, vpnName, primaryRd, interfaceName,
488 vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState, prefixListForRefreshFib);
489 if (!isBgpVpnInternetVpn) {
490 vpnUtil.bindService(vpnName, interfaceName, false/*isTunnelInterface*/);
492 LOG.info("processVpnInterfaceUp: Plumbed vpn interface {} onto dpn {} for vpn {} after waiting for"
493 + " FIB to clean up", interfaceName, dpId, vpnName);
494 if (interfaceManager.isExternalInterface(interfaceName)) {
495 processExternalVpnInterface(interfaceName, vpnName, dpId,
496 lportTag, NwConstants.ADD_FLOW);
500 // Interface is retained in the DPN, but its Link Up.
501 // Advertise prefixes again for this interface to BGP
502 InstanceIdentifier<VpnInterface> identifier =
503 VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName());
504 InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier =
505 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
506 advertiseAdjacenciesForVpnToBgp(primaryRd, dpId, vpnInterfaceOpIdentifier, vpnName, interfaceName);
507 // Perform similar operation as interface add event for extraroutes.
508 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
509 Optional<Adjacencies> optAdjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
510 LogicalDatastoreType.CONFIGURATION, path);
511 if (!optAdjacencies.isPresent()) {
512 LOG.trace("No config adjacencies present for vpninterface {}", vpnInterface);
515 List<Adjacency> adjacencies = optAdjacencies.get().nonnullAdjacency();
516 for (Adjacency adjacency : adjacencies) {
517 if (adjacency.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
520 // if BGPVPN Internet, filter only IPv6 Adjacencies
521 if (isBgpVpnInternetVpn && !vpnUtil.isAdjacencyEligibleToVpnInternet(adjacency)) {
524 addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adjacency,
525 dpId, writeOperTxn, writeConfigTxn, writeInvTxn, prefixListForRefreshFib);
527 } catch (InterruptedException | ExecutionException e) {
528 LOG.error("processVpnInterfaceUp: Failed to read data store for interface {} vpn {} rd {} dpn {}",
529 interfaceName, vpnName, primaryRd, dpId);
534 private void processExternalVpnInterface(String interfaceName, String vpnName, Uint64 dpId,
535 int lportTag, int addOrRemove) {
538 // vpn instance of ext-net interface is the network-id
539 extNetworkId = new Uuid(vpnName);
540 } catch (IllegalArgumentException e) {
541 LOG.error("processExternalVpnInterface: VPN instance {} is not Uuid. Processing external vpn interface {}"
542 + " on dpn {} failed", vpnName, interfaceName, dpId);
546 List<Uuid> routerIds = vpnUtil.getExternalNetworkRouterIds(extNetworkId);
547 if (routerIds == null || routerIds.isEmpty()) {
548 LOG.info("processExternalVpnInterface: No router is associated with {}."
549 + " Bailing out of processing external vpn interface {} on dpn {} for vpn {}",
550 extNetworkId.getValue(), interfaceName, dpId, vpnName);
554 LOG.info("processExternalVpnInterface: Router-ids {} associated with exernal vpn-interface {} on dpn {}"
555 + " for vpn {}", routerIds, interfaceName, dpId, vpnName);
556 for (Uuid routerId : routerIds) {
557 String routerName = routerId.getValue();
558 Uint64 primarySwitch = vpnUtil.getPrimarySwitchForRouter(routerName);
559 if (Objects.equals(primarySwitch, dpId)) {
560 Routers router = vpnUtil.getExternalRouter(routerName);
561 if (router != null) {
562 if (addOrRemove == NwConstants.ADD_FLOW) {
563 vpnManager.addArpResponderFlowsToExternalNetworkIps(routerName,
564 VpnUtil.getIpsListFromExternalIps(router.getExternalIps()), router.getExtGwMacAddress(),
565 dpId, interfaceName, lportTag);
567 vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerName,
568 VpnUtil.getIpsListFromExternalIps(router.getExternalIps()),
569 dpId, interfaceName, lportTag);
572 LOG.error("processExternalVpnInterface: No external-router found for router-id {}. Bailing out of"
573 + " processing external vpn-interface {} on dpn {} for vpn {}", routerName,
574 interfaceName, dpId, vpnName);
580 // TODO Clean up the exception handling
581 @SuppressWarnings("checkstyle:IllegalCatch")
582 private void advertiseAdjacenciesForVpnToBgp(final String rd, Uint64 dpnId,
583 final InstanceIdentifier<VpnInterfaceOpDataEntry> identifier,
584 String vpnName, String interfaceName) {
586 LOG.error("advertiseAdjacenciesForVpnFromBgp: Unable to recover rd for interface {} on dpn {} in vpn {}",
587 interfaceName, dpnId, vpnName);
590 if (rd.equals(vpnName)) {
591 LOG.info("advertiseAdjacenciesForVpnFromBgp: Ignoring BGP advertisement for interface {} on dpn {}"
592 + " as it is in internal vpn{} with rd {}", interfaceName, dpnId, vpnName, rd);
596 LOG.info("advertiseAdjacenciesForVpnToBgp: Advertising interface {} on dpn {} in vpn {} with rd {} ",
597 interfaceName, dpnId, vpnName, rd);
599 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
600 if (nextHopIp == null) {
601 LOG.error("advertiseAdjacenciesForVpnToBgp: NextHop for interface {} on dpn {} is null,"
602 + " returning from advertising route with rd {} vpn {} to bgp", interfaceName, dpnId,
609 InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
610 Optional<AdjacenciesOp> adjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
611 LogicalDatastoreType.OPERATIONAL, path);
612 if (adjacencies.isPresent()) {
613 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
614 if (nextHops != null && !nextHops.isEmpty()) {
615 LOG.debug("advertiseAdjacenciesForVpnToBgp: NextHops are {} for interface {} on dpn {} for vpn {}"
616 + " rd {}", nextHops, interfaceName, dpnId, vpnName, rd);
617 VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(rd);
618 Uint32 l3vni = vpnInstanceOpData.getL3vni();
619 VrfEntry.EncapType encapType = VpnUtil.isL3VpnOverVxLan(l3vni)
620 ? VrfEntry.EncapType.Vxlan : VrfEntry.EncapType.Mplsgre;
621 for (Adjacency nextHop : nextHops) {
622 if (nextHop.getAdjacencyType() == AdjacencyType.ExtraRoute) {
625 String gatewayMac = null;
626 Uint32 label = Uint32.ZERO;
627 if (VpnUtil.isL3VpnOverVxLan(l3vni)) {
628 final VpnPortipToPort gwPort = vpnUtil.getNeutronPortFromVpnPortFixedIp(
629 vpnInstanceOpData.getVpnInstanceName(), nextHop.getIpAddress());
630 gatewayMac = arpResponderHandler.getGatewayMacAddressForInterface(gwPort, interfaceName)
633 label = nextHop.getLabel();
636 LOG.info("VPN ADVERTISE: advertiseAdjacenciesForVpnToBgp: Adding Fib Entry rd {} prefix {}"
637 + " nexthop {} label {}", rd, nextHop.getIpAddress(), nextHopIp, label);
638 bgpManager.advertisePrefix(rd, nextHop.getMacAddress(), nextHop.getIpAddress(), nextHopIp,
639 encapType, label, l3vni, Uint32.ZERO /*l2vni*/,
641 LOG.info("VPN ADVERTISE: advertiseAdjacenciesForVpnToBgp: Added Fib Entry rd {} prefix {}"
642 + " nexthop {} label {} for interface {} on dpn {} for vpn {}", rd,
643 nextHop.getIpAddress(), nextHopIp, label, interfaceName, dpnId, vpnName);
644 } catch (Exception e) {
645 LOG.error("advertiseAdjacenciesForVpnToBgp: Failed to advertise prefix {} in vpn {}"
646 + " with rd {} for interface {} on dpn {}", nextHop.getIpAddress(), vpnName, rd,
647 interfaceName, dpnId, e);
652 } catch (InterruptedException | ExecutionException e) {
653 LOG.error("advertiseAdjacenciesForVpnToBgp: Failed to read data store for interface {} dpn {} nexthop {}"
654 + "vpn {} rd {}", interfaceName, dpnId, nextHopIp, vpnName, rd);
658 // TODO Clean up the exception handling
659 @SuppressWarnings("checkstyle:IllegalCatch")
660 private void withdrawAdjacenciesForVpnFromBgp(final InstanceIdentifier<VpnInterfaceOpDataEntry> identifier,
661 String vpnName, String interfaceName, TypedWriteTransaction<Configuration> writeConfigTxn,
662 TypedWriteTransaction<Operational> writeOperTx) {
664 InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
665 String rd = vpnUtil.getVpnRd(interfaceName);
667 LOG.error("withdrawAdjacenciesForVpnFromBgp: Unable to recover rd for interface {} in vpn {}",
668 interfaceName, vpnName);
671 if (rd.equals(vpnName)) {
673 "withdrawAdjacenciesForVpnFromBgp: Ignoring BGP withdrawal for interface {} as it is in "
674 + "internal vpn{} with rd {}", interfaceName, vpnName, rd);
678 LOG.info("withdrawAdjacenciesForVpnFromBgp: For interface {} in vpn {} with rd {}", interfaceName,
680 Optional<AdjacenciesOp> adjacencies = Optional.empty();
682 adjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
684 } catch (InterruptedException | ExecutionException e) {
685 LOG.error("withdrawAdjacenciesForVpnFromBgp: Failed to read data store for interface {} vpn {}",
686 interfaceName, vpnName);
688 if (adjacencies.isPresent()) {
689 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
691 if (nextHops != null && !nextHops.isEmpty()) {
692 LOG.trace("withdrawAdjacenciesForVpnFromBgp: NextHops are {} for interface {} in vpn {} rd {}",
693 nextHops, interfaceName, vpnName, rd);
694 for (Adjacency nextHop : nextHops) {
696 if (nextHop.getAdjacencyType() != AdjacencyType.ExtraRoute) {
697 LOG.info("VPN WITHDRAW: withdrawAdjacenciesForVpnFromBgp: Removing Fib Entry rd {}"
698 + " prefix {} for interface {} in vpn {}", rd, nextHop.getIpAddress(),
699 interfaceName, vpnName);
700 bgpManager.withdrawPrefix(rd, nextHop.getIpAddress());
701 LOG.info("VPN WITHDRAW: withdrawAdjacenciesForVpnFromBgp: Removed Fib Entry rd {}"
702 + " prefix {} for interface {} in vpn {}", rd, nextHop.getIpAddress(),
703 interfaceName, vpnName);
704 } else if (nextHop.getNextHopIpList() != null) {
705 // Perform similar operation as interface delete event for extraroutes.
706 String allocatedRd = nextHop.getVrfId();
707 for (String nh : nextHop.getNextHopIpList()) {
708 deleteExtraRouteFromCurrentAndImportingVpns(
709 vpnName, nextHop.getIpAddress(), nh, allocatedRd, interfaceName, writeConfigTxn,
713 } catch (Exception e) {
714 LOG.error("withdrawAdjacenciesForVpnFromBgp: Failed to withdraw prefix {} in vpn {} with rd {}"
715 + " for interface {} ", nextHop.getIpAddress(), vpnName, rd, interfaceName, e);
722 @SuppressWarnings("checkstyle:IllegalCatch")
723 protected void processVpnInterfaceAdjacencies(Uint64 dpnId, final int lportTag, String vpnName,
724 String primaryRd, String interfaceName, final Uint32 vpnId,
725 TypedWriteTransaction<Configuration> writeConfigTxn,
726 TypedWriteTransaction<Operational> writeOperTxn,
727 TypedReadWriteTransaction<Configuration> writeInvTxn,
728 Interface interfaceState, Set<String> prefixListForRefreshFib)
729 throws ExecutionException, InterruptedException {
730 InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
732 Optional<VpnInterface> vpnInteface = Optional.empty();
734 vpnInteface = SingleTransactionDataBroker.syncReadOptional(dataBroker,
735 LogicalDatastoreType.CONFIGURATION, identifier);
736 } catch (InterruptedException | ExecutionException e) {
737 LOG.error("processVpnInterfaceAdjacencies: Failed to read data store for interface {} vpn {} rd {}"
738 + "dpn {}", interfaceName, vpnName, primaryRd, dpnId);
740 Uuid intfnetworkUuid = null;
741 NetworkType networkType = null;
742 Long segmentationId = Long.valueOf(-1);
743 Adjacencies adjacencies = null;
744 if (vpnInteface.isPresent()) {
745 intfnetworkUuid = vpnInteface.get().getNetworkId();
746 networkType = vpnInteface.get().getNetworkType();
747 segmentationId = vpnInteface.get().getSegmentationId().toJava();
748 adjacencies = vpnInteface.get().augmentation(Adjacencies.class);
749 if (adjacencies == null) {
750 addVpnInterfaceToOperational(vpnName, interfaceName, dpnId, null/*adjacencies*/, lportTag,
751 null/*gwMac*/, null/*gatewayIp*/, writeOperTxn);
755 // Get the rd of the vpn instance
756 String nextHopIp = null;
757 String gatewayIp = null;
759 nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
760 } catch (Exception e) {
761 LOG.error("processVpnInterfaceAdjacencies: Unable to retrieve endpoint ip address for "
762 + "dpnId {} for vpnInterface {} vpnName {}", dpnId, interfaceName, vpnName);
764 List<String> nhList = new ArrayList<>();
765 if (nextHopIp != null) {
766 nhList.add(nextHopIp);
767 LOG.debug("processVpnInterfaceAdjacencies: NextHop for interface {} on dpn {} in vpn {} is {}",
768 interfaceName, dpnId, vpnName, nhList);
770 Optional<String> gwMac = Optional.empty();
771 String vpnInterfaceSubnetGwMacAddress = null;
772 VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(primaryRd);
773 Uint32 l3vni = vpnInstanceOpData.getL3vni() != null ? vpnInstanceOpData.getL3vni() : Uint32.ZERO;
774 boolean isL3VpnOverVxLan = VpnUtil.isL3VpnOverVxLan(l3vni);
775 VrfEntry.EncapType encapType = isL3VpnOverVxLan ? VrfEntry.EncapType.Vxlan : VrfEntry.EncapType.Mplsgre;
776 VpnPopulator registeredPopulator = L3vpnRegistry.getRegisteredPopulator(encapType);
777 List<Adjacency> nextHops = adjacencies != null ? adjacencies.getAdjacency() : emptyList();
778 List<Adjacency> value = new ArrayList<>();
779 for (Adjacency nextHop : nextHops) {
780 String rd = primaryRd;
781 String nexthopIpValue = nextHop.getIpAddress().split("/")[0];
782 if (vpnInstanceOpData.getBgpvpnType() == VpnInstanceOpDataEntry.BgpvpnType.BGPVPNInternet
783 && NWUtil.isIpv4Address(nexthopIpValue)) {
784 String prefix = nextHop.getIpAddress() == null ? "null" :
785 VpnUtil.getIpPrefix(nextHop.getIpAddress());
786 LOG.debug("processVpnInterfaceAdjacencies: UnsupportedOperation : Not Adding prefix {} to interface {}"
787 + " as InternetVpn has an IPV4 address {}", prefix, interfaceName, vpnName);
790 if (nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
791 String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
792 Prefixes.PrefixCue prefixCue = nextHop.isPhysNetworkFunc()
793 ? Prefixes.PrefixCue.PhysNetFunc : Prefixes.PrefixCue.None;
794 LOG.debug("processVpnInterfaceAdjacencies: Adding prefix {} to interface {} with nextHops {} on dpn {}"
795 + " for vpn {}", prefix, interfaceName, nhList, dpnId, vpnName);
797 Prefixes prefixes = intfnetworkUuid != null
798 ? VpnUtil.getPrefixToInterface(dpnId, interfaceName, prefix, intfnetworkUuid ,networkType,
799 segmentationId, prefixCue) :
800 VpnUtil.getPrefixToInterface(dpnId, interfaceName, prefix, prefixCue);
801 writeOperTxn.merge(VpnUtil.getPrefixToInterfaceIdentifier(
802 vpnUtil.getVpnId(vpnName), prefix), prefixes, true);
803 final Uuid subnetId = nextHop.getSubnetId();
805 gatewayIp = nextHop.getSubnetGatewayIp();
806 if (gatewayIp == null) {
807 Optional<String> gatewayIpOptional = vpnUtil.getVpnSubnetGatewayIp(subnetId);
808 if (gatewayIpOptional.isPresent()) {
809 gatewayIp = gatewayIpOptional.get();
813 if (gatewayIp != null) {
814 gwMac = getMacAddressForSubnetIp(vpnName, interfaceName, gatewayIp);
815 if (gwMac.isPresent()) {
816 // A valid mac-address is available for this subnet-gateway-ip
817 // Use this for programming ARP_RESPONDER table here. And save this
818 // info into vpnInterface operational, so it can used in VrfEntryProcessor
819 // to populate L3_GW_MAC_TABLE there.
820 arpResponderHandler.addArpResponderFlow(dpnId, lportTag, interfaceName,
821 gatewayIp, gwMac.get());
822 vpnInterfaceSubnetGwMacAddress = gwMac.get();
824 // A valid mac-address is not available for this subnet-gateway-ip
825 // Use the connected-mac-address to configure ARP_RESPONDER Table.
826 // Save this connected-mac-address as gateway-mac-address for the
827 // VrfEntryProcessor to use this later to populate the L3_GW_MAC_TABLE.
828 gwMac = InterfaceUtils.getMacAddressFromInterfaceState(interfaceState);
829 if (gwMac.isPresent()) {
830 vpnUtil.setupGwMacIfExternalVpn(dpnId, interfaceName, vpnId, writeInvTxn,
831 NwConstants.ADD_FLOW, gwMac.get());
832 arpResponderHandler.addArpResponderFlow(dpnId, lportTag, interfaceName,
833 gatewayIp, gwMac.get());
835 LOG.error("processVpnInterfaceAdjacencies: Gateway MAC for subnet ID {} could not be "
836 + "obtained, cannot create ARP responder flow for interface name {}, vpnName {}, "
838 subnetId, interfaceName, vpnName, gatewayIp);
842 LOG.warn("processVpnInterfaceAdjacencies: Gateway IP for subnet ID {} could not be obtained, "
843 + "cannot create ARP responder flow for interface name {}, vpnName {}",
844 subnetId, interfaceName, vpnName);
845 gwMac = InterfaceUtils.getMacAddressFromInterfaceState(interfaceState);
847 LOG.info("processVpnInterfaceAdjacencies: Added prefix {} to interface {} with nextHops {} on dpn {}"
848 + " for vpn {}", prefix, interfaceName, nhList, dpnId, vpnName);
850 //Extra route adjacency
851 String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
852 String vpnPrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
853 // FIXME: separate this out somehow?
854 final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnPrefixKey);
857 java.util.Optional<String> rdToAllocate = vpnUtil
858 .allocateRdForExtraRouteAndUpdateUsedRdsMap(vpnId, null, prefix, vpnName,
859 nextHop.getNextHopIpList().get(0), dpnId);
860 if (rdToAllocate.isPresent()) {
861 rd = rdToAllocate.get();
862 LOG.info("processVpnInterfaceAdjacencies: The rd {} is allocated for the extraroute {}",
865 LOG.error("processVpnInterfaceAdjacencies: No rds to allocate extraroute {}", prefix);
871 LOG.info("processVpnInterfaceAdjacencies: Added prefix {} and nextHopList {} as extra-route for vpn{}"
872 + " interface {} on dpn {}", nextHop.getIpAddress(), nextHop.getNextHopIpList(), vpnName,
873 interfaceName, dpnId);
875 // Please note that primary adjacency will use a subnet-gateway-mac-address that
876 // can be different from the gateway-mac-address within the VRFEntry as the
877 // gateway-mac-address is a superset.
878 RouteOrigin origin = VpnUtil.getRouteOrigin(nextHop.getAdjacencyType());
879 L3vpnInput input = new L3vpnInput().setNextHop(nextHop).setRd(rd).setVpnName(vpnName)
880 .setInterfaceName(interfaceName).setNextHopIp(nextHopIp).setPrimaryRd(primaryRd)
881 .setSubnetGatewayMacAddress(vpnInterfaceSubnetGwMacAddress).setRouteOrigin(origin);
882 Adjacency operationalAdjacency = null;
884 operationalAdjacency = registeredPopulator.createOperationalAdjacency(input);
885 } catch (NullPointerException e) {
886 LOG.error("processVpnInterfaceAdjacencies: failed to create operational adjacency: input: {}, {}",
887 input, e.getMessage());
890 if (nextHop.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
891 vpnManager.addExtraRoute(vpnName, nextHop.getIpAddress(), nextHop.getNextHopIpList().get(0), rd,
892 vpnName, l3vni, origin, interfaceName, operationalAdjacency, encapType, prefixListForRefreshFib,
895 value.add(operationalAdjacency);
898 AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(value);
899 addVpnInterfaceToOperational(vpnName, interfaceName, dpnId, aug, lportTag,
900 gwMac.isPresent() ? gwMac.get() : null, gatewayIp, writeOperTxn);
902 L3vpnInput input = new L3vpnInput().setNextHopIp(nextHopIp).setL3vni(l3vni.longValue()).setPrimaryRd(primaryRd)
903 .setGatewayMac(gwMac.orElse(null)).setInterfaceName(interfaceName)
904 .setVpnName(vpnName).setDpnId(dpnId).setEncapType(encapType);
906 for (Adjacency nextHop : aug.getAdjacency()) {
907 // Adjacencies other than primary Adjacencies are handled in the addExtraRoute call above.
908 if (nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
909 RouteOrigin origin = VpnUtil.getRouteOrigin(nextHop.getAdjacencyType());
910 input.setNextHop(nextHop).setRd(nextHop.getVrfId()).setRouteOrigin(origin);
911 registeredPopulator.populateFib(input, writeConfigTxn);
916 private void addVpnInterfaceToOperational(String vpnName, String interfaceName, Uint64 dpnId, AdjacenciesOp aug,
917 long lportTag, String gwMac, String gwIp,
918 TypedWriteTransaction<Operational> writeOperTxn) {
919 VpnInterfaceOpDataEntry opInterface =
920 VpnUtil.getVpnInterfaceOpDataEntry(interfaceName, vpnName, aug, dpnId, lportTag, gwMac, gwIp);
921 InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId = VpnUtil
922 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
923 writeOperTxn.put(interfaceId, opInterface, CREATE_MISSING_PARENTS);
924 LOG.info("addVpnInterfaceToOperational: Added VPN Interface {} on dpn {} vpn {} to operational datastore",
925 interfaceName, dpnId, vpnName);
928 // TODO Clean up the exception handling
929 @SuppressWarnings("checkstyle:IllegalCatch")
930 public void updateVpnInterfaceOnTepAdd(VpnInterfaceOpDataEntry vpnInterface,
931 StateTunnelList stateTunnelList,
932 TypedWriteTransaction<Configuration> writeConfigTxn,
933 TypedWriteTransaction<Operational> writeOperTxn) {
935 String srcTepIp = stateTunnelList.getSrcInfo().getTepIp().stringValue();
936 Uint64 srcDpnId = Uint64.valueOf(stateTunnelList.getSrcInfo().getTepDeviceId()).intern();
937 AdjacenciesOp adjacencies = vpnInterface.augmentation(AdjacenciesOp.class);
938 List<Adjacency> adjList =
939 adjacencies != null && adjacencies.getAdjacency() != null ? adjacencies.getAdjacency() : emptyList();
940 if (adjList.isEmpty()) {
941 LOG.trace("updateVpnInterfaceOnTepAdd: Adjacencies are empty for vpnInterface {} on dpn {}",
942 vpnInterface, srcDpnId);
945 String prefix = null;
946 List<Adjacency> value = new ArrayList<>();
947 boolean isFibNextHopAddReqd = false;
948 String vpnName = vpnInterface.getVpnInstanceName();
949 Uint32 vpnId = vpnUtil.getVpnId(vpnName);
950 String primaryRd = vpnUtil.getPrimaryRd(vpnName);
951 LOG.info("updateVpnInterfaceOnTepAdd: AdjacencyList for interface {} on dpn {} vpn {} is {}",
952 vpnInterface.getName(), vpnInterface.getDpnId(),
953 vpnInterface.getVpnInstanceName(), adjList);
954 for (Adjacency adj : adjList) {
955 String rd = adj.getVrfId();
956 rd = rd != null ? rd : vpnName;
957 prefix = adj.getIpAddress();
958 Uint32 label = adj.getLabel();
959 List<String> nhList = Collections.singletonList(srcTepIp);
960 List<String> nextHopList = adj.getNextHopIpList();
961 // If TEP is added , update the nexthop of primary adjacency.
962 // Secondary adj nexthop is already pointing to primary adj IP address.
963 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
964 value.add(new AdjacencyBuilder(adj).setNextHopIpList(nhList).build());
965 if (nextHopList != null && !nextHopList.isEmpty()) {
966 /* everything right already */
968 isFibNextHopAddReqd = true;
971 Optional<VrfEntry> vrfEntryOptional = FibHelper.getVrfEntry(dataBroker, primaryRd, prefix);
972 if (!vrfEntryOptional.isPresent()) {
975 nhList = FibHelper.getNextHopListFromRoutePaths(vrfEntryOptional.get());
976 if (!nhList.contains(srcTepIp)) {
977 nhList.add(srcTepIp);
978 isFibNextHopAddReqd = true;
983 if (isFibNextHopAddReqd) {
984 updateLabelMapper(label, nhList);
985 LOG.info("updateVpnInterfaceOnTepAdd: Updated label mapper : label {} dpn {} prefix {} nexthoplist {}"
986 + " vpn {} vpnid {} rd {} interface {}", label, srcDpnId , prefix, nhList,
987 vpnInterface.getVpnInstanceName(), vpnId, rd, vpnInterface.getName());
988 // Update the VRF entry with nextHop
989 fibManager.updateRoutePathForFibEntry(primaryRd, prefix, srcTepIp, label, true,
992 //Get the list of VPN's importing this route(prefix) .
993 // Then update the VRF entry with nhList
994 List<VpnInstanceOpDataEntry> vpnsToImportRoute = vpnUtil.getVpnsImportingMyRoute(vpnName);
995 for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
996 String vpnRd = vpn.getVrfId();
998 fibManager.updateRoutePathForFibEntry(vpnRd, prefix, srcTepIp, label, true,
1000 LOG.info("updateVpnInterfaceOnTepAdd: Exported route with rd {} prefix {} nhList {} label {}"
1001 + " interface {} dpn {} from vpn {} to VPN {} vpnRd {}", rd, prefix, nhList, label,
1002 vpnInterface.getName(), srcDpnId, vpnName,
1003 vpn.getVpnInstanceName(), vpnRd);
1006 // Advertise the prefix to BGP only for external vpn
1007 // since there is a nexthop change.
1009 if (!rd.equalsIgnoreCase(vpnName)) {
1010 bgpManager.advertisePrefix(rd, null /*macAddress*/, prefix, nhList,
1011 VrfEntry.EncapType.Mplsgre, label, Uint32.ZERO /*evi*/, Uint32.ZERO /*l2vni*/,
1012 null /*gatewayMacAddress*/);
1014 LOG.info("updateVpnInterfaceOnTepAdd: Advertised rd {} prefix {} nhList {} label {}"
1015 + " for interface {} on dpn {} vpn {}", rd, prefix, nhList, label, vpnInterface.getName(),
1017 } catch (Exception ex) {
1018 LOG.error("updateVpnInterfaceOnTepAdd: Exception when advertising prefix {} nh {} label {}"
1019 + " on rd {} for interface {} on dpn {} vpn {}", prefix, nhList, label, rd,
1020 vpnInterface.getName(), srcDpnId, vpnName, ex);
1024 AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(value);
1025 VpnInterfaceOpDataEntry opInterface = new VpnInterfaceOpDataEntryBuilder(vpnInterface)
1026 .withKey(new VpnInterfaceOpDataEntryKey(vpnInterface.getName(), vpnName))
1027 .addAugmentation(AdjacenciesOp.class, aug).build();
1028 InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId =
1029 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterface.getName(), vpnName);
1030 writeOperTxn.put(interfaceId, opInterface, CREATE_MISSING_PARENTS);
1031 LOG.info("updateVpnInterfaceOnTepAdd: interface {} updated successully on tep add on dpn {} vpn {}",
1032 vpnInterface.getName(), srcDpnId, vpnName);
1036 // TODO Clean up the exception handling
1037 @SuppressWarnings("checkstyle:IllegalCatch")
1038 public void updateVpnInterfaceOnTepDelete(VpnInterfaceOpDataEntry vpnInterface,
1039 StateTunnelList stateTunnelList,
1040 TypedWriteTransaction<Configuration> writeConfigTxn,
1041 TypedWriteTransaction<Operational> writeOperTxn) {
1043 AdjacenciesOp adjacencies = vpnInterface.augmentation(AdjacenciesOp.class);
1044 List<Adjacency> adjList = adjacencies != null ? adjacencies.getAdjacency() : new ArrayList<>();
1045 String prefix = null;
1046 boolean isNextHopRemoveReqd = false;
1047 String srcTepIp = stateTunnelList.getSrcInfo().getTepIp().stringValue();
1048 Uint64 srcDpnId = Uint64.valueOf(stateTunnelList.getSrcInfo().getTepDeviceId()).intern();
1049 String vpnName = vpnInterface.getVpnInstanceName();
1050 Uint32 vpnId = vpnUtil.getVpnId(vpnName);
1051 String primaryRd = vpnUtil.getVpnRd(vpnName);
1052 if (adjList != null) {
1053 List<Adjacency> value = new ArrayList<>();
1054 LOG.info("updateVpnInterfaceOnTepDelete: AdjacencyList for interface {} on dpn {} vpn {} is {}",
1055 vpnInterface.getName(), vpnInterface.getDpnId(),
1056 vpnInterface.getVpnInstanceName(), adjList);
1057 for (Adjacency adj : adjList) {
1058 List<String> nhList = new ArrayList<>();
1059 String rd = adj.getVrfId();
1060 rd = rd != null ? rd : vpnName;
1061 prefix = adj.getIpAddress();
1062 List<String> nextHopList = adj.getNextHopIpList();
1063 Uint32 label = adj.getLabel();
1064 if (nextHopList != null && !nextHopList.isEmpty()) {
1065 isNextHopRemoveReqd = true;
1067 // If TEP is deleted , remove the nexthop from primary adjacency.
1068 // Secondary adj nexthop will continue to point to primary adj IP address.
1069 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
1070 value.add(new AdjacencyBuilder(adj).setNextHopIpList(nhList).build());
1072 Optional<VrfEntry> vrfEntryOptional = FibHelper.getVrfEntry(dataBroker, primaryRd, prefix);
1073 if (!vrfEntryOptional.isPresent()) {
1076 nhList = FibHelper.getNextHopListFromRoutePaths(vrfEntryOptional.get());
1077 if (nhList.contains(srcTepIp)) {
1078 nhList.remove(srcTepIp);
1079 isNextHopRemoveReqd = true;
1084 if (isNextHopRemoveReqd) {
1085 updateLabelMapper(label, nhList);
1086 LOG.info("updateVpnInterfaceOnTepDelete: Updated label mapper : label {} dpn {} prefix {}"
1087 + " nexthoplist {} vpn {} vpnid {} rd {} interface {}", label, srcDpnId,
1088 prefix, nhList, vpnName,
1089 vpnId, rd, vpnInterface.getName());
1090 // Update the VRF entry with removed nextHop
1091 fibManager.updateRoutePathForFibEntry(primaryRd, prefix, srcTepIp, label, false,
1094 //Get the list of VPN's importing this route(prefix) .
1095 // Then update the VRF entry with nhList
1096 List<VpnInstanceOpDataEntry> vpnsToImportRoute = vpnUtil.getVpnsImportingMyRoute(vpnName);
1097 for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
1098 String vpnRd = vpn.getVrfId();
1099 if (vpnRd != null) {
1100 fibManager.updateRoutePathForFibEntry(vpnRd, prefix, srcTepIp, label, false,
1102 LOG.info("updateVpnInterfaceOnTepDelete: Exported route with rd {} prefix {} nhList {}"
1103 + " label {} interface {} dpn {} from vpn {} to VPN {} vpnRd {}", rd, prefix,
1104 nhList, label, vpnInterface.getName(), srcDpnId,
1106 vpn.getVpnInstanceName(), vpnRd);
1110 // Withdraw prefix from BGP only for external vpn.
1112 if (!rd.equalsIgnoreCase(vpnName)) {
1113 bgpManager.withdrawPrefix(rd, prefix);
1115 LOG.info("updateVpnInterfaceOnTepDelete: Withdrawn rd {} prefix {} nhList {} label {}"
1116 + " for interface {} on dpn {} vpn {}", rd, prefix, nhList, label,
1117 vpnInterface.getName(), srcDpnId,
1119 } catch (Exception ex) {
1120 LOG.error("updateVpnInterfaceOnTepDelete: Exception when withdrawing prefix {} nh {} label {}"
1121 + " on rd {} for interface {} on dpn {} vpn {}", prefix, nhList, label, rd,
1122 vpnInterface.getName(), srcDpnId, vpnName, ex);
1126 AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(value);
1127 VpnInterfaceOpDataEntry opInterface = new VpnInterfaceOpDataEntryBuilder(vpnInterface)
1128 .withKey(new VpnInterfaceOpDataEntryKey(vpnInterface.getName(), vpnName))
1129 .addAugmentation(AdjacenciesOp.class, aug).build();
1130 InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId =
1131 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterface.getName(), vpnName);
1132 writeOperTxn.put(interfaceId, opInterface, CREATE_MISSING_PARENTS);
1133 LOG.info("updateVpnInterfaceOnTepDelete: interface {} updated successully on tep delete on dpn {} vpn {}",
1134 vpnInterface.getName(), srcDpnId, vpnName);
1138 @SuppressWarnings("checkstyle:IllegalCatch")
1139 private List<VpnInstanceOpDataEntry> getVpnsExportingMyRoute(final String vpnName) {
1140 List<VpnInstanceOpDataEntry> vpnsToExportRoute = new ArrayList<>();
1141 final VpnInstanceOpDataEntry vpnInstanceOpDataEntry;
1142 String vpnRd = vpnUtil.getVpnRd(vpnName);
1144 VpnInstanceOpDataEntry opDataEntry = vpnUtil.getVpnInstanceOpData(vpnRd);
1145 if (opDataEntry == null) {
1146 LOG.error("getVpnsExportingMyRoute: Null vpn instance op data for vpn {} rd {}"
1147 + " when check for vpns exporting the routes", vpnName, vpnRd);
1148 return vpnsToExportRoute;
1150 vpnInstanceOpDataEntry = opDataEntry;
1151 } catch (Exception re) {
1152 LOG.error("getVpnsExportingMyRoute: DSexception when retrieving vpn instance op data for vpn {} rd {}"
1153 + " to check for vpns exporting the routes", vpnName, vpnRd, re);
1154 return vpnsToExportRoute;
1156 Predicate<VpnInstanceOpDataEntry> excludeVpn = input -> {
1157 if (input.getVpnInstanceName() == null) {
1158 LOG.error("getVpnsExportingMyRoute.excludeVpn: Received vpn instance with rd {} without a name",
1162 return !input.getVpnInstanceName().equals(vpnName);
1165 Predicate<VpnInstanceOpDataEntry> matchRTs = input -> {
1166 Iterable<String> commonRTs =
1167 VpnUtil.intersection(VpnUtil.getRts(vpnInstanceOpDataEntry, VpnTarget.VrfRTType.ImportExtcommunity),
1168 VpnUtil.getRts(input, VpnTarget.VrfRTType.ExportExtcommunity));
1169 return Iterators.size(commonRTs.iterator()) > 0;
1173 vpnUtil.getAllVpnInstanceOpData().stream().filter(excludeVpn).filter(matchRTs).collect(
1174 Collectors.toList());
1175 return vpnsToExportRoute;
1178 // TODO Clean up the exception handling
1179 @SuppressWarnings("checkstyle:IllegalCatch")
1180 void handleVpnsExportingRoutes(String vpnName, String vpnRd) {
1181 List<VpnInstanceOpDataEntry> vpnsToExportRoute = getVpnsExportingMyRoute(vpnName);
1182 for (VpnInstanceOpDataEntry vpn : vpnsToExportRoute) {
1183 List<VrfEntry> vrfEntries = vpnUtil.getAllVrfEntries(vpn.getVrfId());
1184 if (vrfEntries != null) {
1185 ListenableFutures.addErrorLogging(
1186 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
1187 for (VrfEntry vrfEntry : vrfEntries) {
1189 if (!FibHelper.isControllerManagedNonInterVpnLinkRoute(
1190 RouteOrigin.value(vrfEntry.getOrigin()))) {
1191 LOG.info("handleVpnsExportingRoutes: vrfEntry with rd {} prefix {}"
1192 + " is not a controller managed non intervpn link route. Ignoring.",
1193 vpn.getVrfId(), vrfEntry.getDestPrefix());
1196 String prefix = vrfEntry.getDestPrefix();
1197 String gwMac = vrfEntry.getGatewayMacAddress();
1198 vrfEntry.nonnullRoutePaths().forEach(routePath -> {
1199 String nh = routePath.getNexthopAddress();
1200 Uint32 label = routePath.getLabel();
1201 if (FibHelper.isControllerManagedVpnInterfaceRoute(RouteOrigin.value(
1202 vrfEntry.getOrigin()))) {
1204 "handleVpnsExportingRoutesImporting: Importing fib entry rd {}"
1205 + " prefix {} nexthop {} label {} to vpn {} vpnRd {}",
1206 vpn.getVrfId(), prefix, nh, label, vpnName, vpnRd);
1207 fibManager.addOrUpdateFibEntry(vpnRd, null /*macAddress*/, prefix,
1208 Collections.singletonList(nh), VrfEntry.EncapType.Mplsgre, label,
1209 Uint32.ZERO /*l3vni*/, gwMac, vpn.getVrfId(), RouteOrigin.SELF_IMPORTED,
1212 LOG.info("handleVpnsExportingRoutes: Importing subnet route fib entry"
1213 + " rd {} prefix {} nexthop {} label {} to vpn {} vpnRd {}",
1214 vpn.getVrfId(), prefix, nh, label, vpnName, vpnRd);
1215 SubnetRoute route = vrfEntry.augmentation(SubnetRoute.class);
1216 importSubnetRouteForNewVpn(vpnRd, prefix, nh, label, route, vpn.getVrfId(),
1220 } catch (RuntimeException e) {
1221 LOG.error("getNextHopAddressList: Exception occurred while importing route with rd {}"
1222 + " prefix {} routePaths {} to vpn {} vpnRd {}", vpn.getVrfId(),
1223 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(), vpnName, vpnRd);
1226 }), LOG, "Error handing VPN exporting routes");
1228 LOG.info("getNextHopAddressList: No vrf entries to import from vpn {} with rd {} to vpn {} with rd {}",
1229 vpn.getVpnInstanceName(), vpn.getVrfId(), vpnName, vpnRd);
1235 public void remove(InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
1236 LOG.trace("Received VpnInterface remove event: vpnInterface={}", vpnInterface);
1237 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class);
1238 final String interfaceName = key.getName();
1239 for (VpnInstanceNames vpnInterfaceVpnInstance : vpnInterface.nonnullVpnInstanceNames()) {
1240 String vpnName = vpnInterfaceVpnInstance.getVpnName();
1241 removeVpnInterfaceCall(identifier, vpnInterface, vpnName, interfaceName);
1245 private void removeVpnInterfaceCall(final InstanceIdentifier<VpnInterface> identifier,
1246 final VpnInterface vpnInterface, final String vpnName,
1247 final String interfaceName) {
1248 if (Boolean.TRUE.equals(vpnInterface.isRouterInterface())) {
1249 jobCoordinator.enqueueJob("VPNINTERFACE-" + vpnInterface.getName(), () -> {
1250 ListenableFuture<Void> future =
1251 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
1252 deleteFibEntryForRouterInterface(vpnInterface, confTx, vpnName);
1253 LOG.info("remove: Router interface {} for vpn {}", interfaceName, vpnName);
1255 ListenableFutures.addErrorLogging(future, LOG, "Error removing call for interface {} on VPN {}",
1256 vpnInterface.getName(), vpnName);
1257 return Collections.singletonList(future);
1258 }, DJC_MAX_RETRIES);
1260 Interface interfaceState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker, interfaceName);
1261 removeVpnInterfaceFromVpn(identifier, vpnInterface, vpnName, interfaceName, interfaceState);
1265 @SuppressFBWarnings("DLS_DEAD_LOCAL_STORE")
1266 private void removeVpnInterfaceFromVpn(final InstanceIdentifier<VpnInterface> identifier,
1267 final VpnInterface vpnInterface, final String vpnName,
1268 final String interfaceName, final Interface interfaceState) {
1269 LOG.info("remove: VPN Interface remove event - intfName {} vpn {} dpn {}" ,vpnInterface.getName(),
1270 vpnName, vpnInterface.getDpnId());
1271 removeInterfaceFromUnprocessedList(identifier, vpnInterface);
1272 jobCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName,
1274 List<ListenableFuture<Void>> futures = new ArrayList<>(3);
1275 ListenableFuture<Void> configFuture = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1276 writeConfigTxn -> futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
1277 writeOperTxn -> futures.add(
1278 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, writeInvTxn -> {
1279 LOG.info("remove: - intfName {} onto vpnName {} running config-driven",
1280 interfaceName, vpnName);
1283 String gwMacAddress;
1284 InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId =
1285 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
1286 Optional<VpnInterfaceOpDataEntry> optVpnInterface;
1288 optVpnInterface = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1289 LogicalDatastoreType.OPERATIONAL, interfaceId);
1290 } catch (InterruptedException | ExecutionException e) {
1291 LOG.error("remove: Failed to read data store for interface {} vpn {}",
1292 interfaceName, vpnName);
1295 if (interfaceState != null) {
1297 dpId = InterfaceUtils.getDpIdFromInterface(interfaceState);
1298 } catch (NumberFormatException | IllegalStateException e) {
1299 LOG.error("remove: Unable to retrieve dpnId from interface operational"
1300 + " data store for interface {} on dpn {} for vpn {} Fetching"
1301 + " from vpn interface op data store. ", interfaceName,
1302 vpnInterface.getDpnId(), vpnName, e);
1305 ifIndex = interfaceState.getIfIndex();
1306 gwMacAddress = interfaceState.getPhysAddress().getValue();
1308 LOG.info("remove: Interface state not available for {}. Trying to fetch data"
1309 + " from vpn interface op.", interfaceName);
1310 if (optVpnInterface.isPresent()) {
1311 VpnInterfaceOpDataEntry vpnOpInterface = optVpnInterface.get();
1312 dpId = vpnOpInterface.getDpnId();
1313 ifIndex = vpnOpInterface.getLportTag().intValue();
1314 gwMacAddress = vpnOpInterface.getGatewayMacAddress();
1316 LOG.error("remove: Handling removal of VPN interface {} for vpn {} skipped"
1317 + " as interfaceState and vpn interface op is not"
1318 + " available", interfaceName, vpnName);
1322 processVpnInterfaceDown(dpId, interfaceName, ifIndex, gwMacAddress,
1323 optVpnInterface.isPresent() ? optVpnInterface.get() : null, false,
1324 writeConfigTxn, writeOperTxn, writeInvTxn);
1326 "remove: Removal of vpn interface {} on dpn {} for vpn {} processed "
1328 interfaceName, vpnInterface.getDpnId(), vpnName);
1330 futures.add(configFuture);
1331 Futures.addCallback(configFuture, new PostVpnInterfaceWorker(
1332 interfaceName, false, "Config"), MoreExecutors.directExecutor());
1334 }, DJC_MAX_RETRIES);
1337 protected void processVpnInterfaceDown(Uint64 dpId,
1338 String interfaceName,
1341 VpnInterfaceOpDataEntry vpnOpInterface,
1342 boolean isInterfaceStateDown,
1343 TypedWriteTransaction<Configuration> writeConfigTxn,
1344 TypedWriteTransaction<Operational> writeOperTxn,
1345 TypedReadWriteTransaction<Configuration> writeInvTxn)
1346 throws ExecutionException, InterruptedException {
1347 if (vpnOpInterface == null) {
1348 LOG.error("processVpnInterfaceDown: Unable to process delete/down for interface {} on dpn {}"
1349 + " as it is not available in operational data store", interfaceName, dpId);
1352 final String vpnName = vpnOpInterface.getVpnInstanceName();
1353 InstanceIdentifier<VpnInterfaceOpDataEntry> identifier = VpnUtil.getVpnInterfaceOpDataEntryIdentifier(
1354 interfaceName, vpnName);
1355 if (!isInterfaceStateDown) {
1356 final Uint32 vpnId = vpnUtil.getVpnId(vpnName);
1357 vpnUtil.scheduleVpnInterfaceForRemoval(interfaceName, dpId, vpnName, null);
1358 final boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(vpnName);
1359 removeAdjacenciesFromVpn(dpId, lportTag, interfaceName, vpnName,
1360 vpnId, gwMac, writeConfigTxn, writeOperTxn, writeInvTxn);
1361 if (interfaceManager.isExternalInterface(interfaceName)) {
1362 processExternalVpnInterface(interfaceName, vpnName, dpId, lportTag,
1363 NwConstants.DEL_FLOW);
1365 if (!isBgpVpnInternetVpn) {
1366 vpnUtil.unbindService(interfaceName, isInterfaceStateDown);
1368 LOG.info("processVpnInterfaceDown: Unbound vpn service from interface {} on dpn {} for vpn {}"
1369 + " successful", interfaceName, dpId, vpnName);
1371 // Interface is retained in the DPN, but its Link Down.
1372 // Only withdraw the prefixes for this interface from BGP
1373 withdrawAdjacenciesForVpnFromBgp(identifier, vpnName, interfaceName, writeConfigTxn, writeOperTxn);
1377 private void removeAdjacenciesFromVpn(final Uint64 dpnId, final int lportTag, final String interfaceName,
1378 final String vpnName, final Uint32 vpnId, String gwMac,
1379 TypedWriteTransaction<Configuration> writeConfigTxn,
1380 TypedWriteTransaction<Operational> writeOperTxn,
1381 TypedReadWriteTransaction<Configuration> writeInvTxn)
1382 throws ExecutionException, InterruptedException {
1385 InstanceIdentifier<VpnInterfaceOpDataEntry> identifier = VpnUtil
1386 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
1387 Optional<VpnInterfaceOpDataEntry> vpnInterfaceOpDataEnteryOptional =
1388 SingleTransactionDataBroker.syncReadOptional(dataBroker,
1389 LogicalDatastoreType.OPERATIONAL, identifier);
1390 boolean isNonPrimaryAdjIp = false;
1391 String primaryRd = vpnUtil.getVpnRd(vpnName);
1392 LOG.info("removeAdjacenciesFromVpn: For interface {} on dpn {} RD recovered for vpn {} as rd {}",
1393 interfaceName, dpnId, vpnName, primaryRd);
1394 if (!vpnInterfaceOpDataEnteryOptional.isPresent()) {
1395 LOG.error("removeAdjacenciesFromVpn: VpnInterfaceOpDataEntry-Oper DS is absent for Interface {} "
1396 + "on vpn {} dpn {}", interfaceName, vpnName, dpnId);
1399 AdjacenciesOp adjacencies = vpnInterfaceOpDataEnteryOptional.get().augmentation(AdjacenciesOp.class);
1401 if (adjacencies != null && !adjacencies.getAdjacency().isEmpty()) {
1402 List<Adjacency> nextHops = adjacencies.getAdjacency();
1403 LOG.info("removeAdjacenciesFromVpn: NextHops for interface {} on dpn {} for vpn {} are {}",
1404 interfaceName, dpnId, vpnName, nextHops);
1405 for (Adjacency nextHop : nextHops) {
1406 if (nextHop.isPhysNetworkFunc()) {
1407 LOG.info("removeAdjacenciesFromVpn: Removing PNF FIB entry rd {} prefix {}",
1408 nextHop.getSubnetId().getValue(), nextHop.getIpAddress());
1409 fibManager.removeFibEntry(nextHop.getSubnetId().getValue(), nextHop.getIpAddress(),
1410 null, null/*writeCfgTxn*/);
1412 String rd = nextHop.getVrfId();
1413 List<String> nhList;
1414 if (nextHop.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
1415 nhList = getNextHopForNonPrimaryAdjacency(nextHop, vpnName, dpnId, interfaceName);
1416 isNonPrimaryAdjIp = Boolean.TRUE;
1418 // This is a primary adjacency
1419 nhList = nextHop.getNextHopIpList() != null ? nextHop.getNextHopIpList()
1421 removeGwMacAndArpResponderFlows(nextHop, vpnId, dpnId, lportTag, gwMac,
1422 vpnInterfaceOpDataEnteryOptional.get().getGatewayIpAddress(),
1423 interfaceName, writeInvTxn);
1424 isNonPrimaryAdjIp = Boolean.FALSE;
1426 if (!nhList.isEmpty()) {
1427 if (Objects.equals(primaryRd, vpnName)) {
1428 //this is an internal vpn - the rd is assigned to the vpn instance name;
1429 //remove from FIB directly
1430 nhList.forEach(removeAdjacencyFromInternalVpn(nextHop, vpnName,
1431 interfaceName, dpnId, writeConfigTxn, writeOperTxn));
1433 removeAdjacencyFromBgpvpn(nextHop, nhList, vpnName, primaryRd, dpnId, rd,
1434 interfaceName, isNonPrimaryAdjIp, writeConfigTxn, writeOperTxn);
1437 LOG.error("removeAdjacenciesFromVpn: nextHop empty for ip {} rd {} adjacencyType {}"
1438 + " interface {}", nextHop.getIpAddress(), rd,
1439 nextHop.getAdjacencyType().toString(), interfaceName);
1440 bgpManager.withdrawPrefixIfPresent(rd, nextHop.getIpAddress());
1441 fibManager.removeFibEntry(primaryRd, nextHop.getIpAddress(), null, writeConfigTxn);
1444 String ip = nextHop.getIpAddress().split("/")[0];
1445 LearntVpnVipToPort vpnVipToPort = vpnUtil.getLearntVpnVipToPort(vpnName, ip);
1446 if (vpnVipToPort != null && vpnVipToPort.getPortName().equals(interfaceName)) {
1447 vpnUtil.removeLearntVpnVipToPort(vpnName, ip, null);
1448 LOG.info("removeAdjacenciesFromVpn: VpnInterfaceManager removed LearntVpnVipToPort entry"
1449 + " for Interface {} ip {} on dpn {} for vpn {}",
1450 vpnVipToPort.getPortName(), ip, dpnId, vpnName);
1452 // Remove the MIP-IP from VpnPortIpToPort.
1453 if (isNonPrimaryAdjIp) {
1454 VpnPortipToPort persistedIp = vpnUtil.getVpnPortipToPort(vpnName, ip);
1455 if (persistedIp != null && persistedIp.isLearntIp()
1456 && persistedIp.getPortName().equals(interfaceName)) {
1457 VpnUtil.removeVpnPortFixedIpToPort(dataBroker, vpnName, ip, null);
1459 "removeAdjacenciesFromVpn: Learnt-IP: {} interface {} of vpn {} removed "
1460 + "from VpnPortipToPort",
1461 persistedIp.getPortFixedip(), persistedIp.getPortName(), vpnName);
1464 VpnPortipToPort vpnPortipToPort = vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnName, ip);
1465 if (vpnPortipToPort != null) {
1466 VpnUtil.removeVpnPortFixedIpToPort(dataBroker, vpnName, ip, null);
1467 LOG.info("removeAdjacenciesFromVpn: VpnInterfaceManager removed vpnPortipToPort entry for "
1468 + "Interface {} ip {} on dpn {} for vpn {}",
1469 vpnPortipToPort.getPortName(), ip, dpnId, vpnName);
1473 // this vpn interface has no more adjacency left, so clean up the vpn interface from Operational DS
1474 LOG.info("removeAdjacenciesFromVpn: Vpn Interface {} on vpn {} dpn {} has no adjacencies."
1475 + " Removing it.", interfaceName, vpnName, dpnId);
1476 writeOperTxn.delete(identifier);
1478 } catch (InterruptedException | ExecutionException e) {
1479 LOG.error("removeAdjacenciesFromVpn: Failed to read data store for interface {} dpn {} vpn {}",
1480 interfaceName, dpnId, vpnName);
1484 private Consumer<String> removeAdjacencyFromInternalVpn(Adjacency nextHop, String vpnName,
1485 String interfaceName, Uint64 dpnId,
1486 TypedWriteTransaction<Configuration> writeConfigTxn,
1487 TypedWriteTransaction<Operational> writeOperTx) {
1489 String primaryRd = vpnUtil.getVpnRd(vpnName);
1490 String prefix = nextHop.getIpAddress();
1491 String vpnNamePrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
1492 LOG.info("remove adjacencies for nexthop {} vpnName {} interfaceName {} dpnId {}",
1493 nextHop, vpnName, interfaceName, dpnId);
1494 // FIXME: separate this out somehow?
1495 final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnNamePrefixKey);
1498 if (vpnUtil.removeOrUpdateDSForExtraRoute(vpnName, primaryRd, dpnId.toString(), interfaceName,
1499 prefix, nextHop.getNextHopIpList().get(0), nh, writeOperTx)) {
1500 //If extra-route is present behind at least one VM, then do not remove or update
1501 //fib entry for route-path representing that CSS nexthop, just update vpntoextraroute and
1502 //prefixtointerface DS
1505 fibManager.removeOrUpdateFibEntry(vpnName, nextHop.getIpAddress(), nh,
1510 LOG.info("removeAdjacenciesFromVpn: removed/updated FIB with rd {} prefix {}"
1511 + " nexthop {} for interface {} on dpn {} for internal vpn {}",
1512 vpnName, nextHop.getIpAddress(), nh, interfaceName, dpnId, vpnName);
1516 private void removeAdjacencyFromBgpvpn(Adjacency nextHop, List<String> nhList, String vpnName, String primaryRd,
1517 Uint64 dpnId, String rd, String interfaceName, boolean isNonPrimaryAdjIp,
1518 TypedWriteTransaction<Configuration> writeConfigTxn,
1519 TypedWriteTransaction<Operational> writeOperTx) {
1520 List<VpnInstanceOpDataEntry> vpnsToImportRoute =
1521 vpnUtil.getVpnsImportingMyRoute(vpnName);
1522 nhList.forEach((nh) -> {
1523 //IRT: remove routes from other vpns importing it
1524 if (isNonPrimaryAdjIp) {
1525 removeLearntPrefixFromBGP(rd, nextHop.getIpAddress(), nh, writeConfigTxn);
1527 vpnManager.removePrefixFromBGP(vpnName, primaryRd, rd, interfaceName, nextHop.getIpAddress(),
1528 nextHop.getNextHopIpList().get(0), nh, dpnId, writeConfigTxn, writeOperTx);
1530 for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
1531 String vpnRd = vpn.getVrfId();
1532 if (vpnRd != null) {
1533 fibManager.removeOrUpdateFibEntry(vpnRd,
1534 nextHop.getIpAddress(), nh, writeConfigTxn);
1535 LOG.info("removeAdjacenciesFromVpn: Removed Exported route with rd {}"
1536 + " prefix {} nextHop {} from VPN {} parentVpn {}"
1537 + " for interface {} on dpn {}", vpnRd, nextHop.getIpAddress(), nh,
1538 vpn.getVpnInstanceName(), vpnName, interfaceName, dpnId);
1544 @SuppressWarnings("checkstyle:IllegalCatch")
1545 private void removeLearntPrefixFromBGP(String rd, String prefix, String nextHop,
1546 TypedWriteTransaction<Configuration> writeConfigTxn) {
1548 if (!fibManager.checkFibEntryExist(dataBroker, rd, prefix, nextHop)) {
1549 LOG.info("removeLearntPrefixFromBGP: IP {} with nexthop {} rd {} is already removed.Ignoring this"
1550 + " operation", prefix, nextHop, rd);
1553 LOG.info("removeLearntPrefixFromBGP: VPN WITHDRAW: Removing Fib Entry rd {} prefix {} nexthop {}",
1554 rd, prefix, nextHop);
1555 fibManager.removeOrUpdateFibEntry(rd, prefix, nextHop, writeConfigTxn);
1556 bgpManager.withdrawPrefix(rd, prefix); // TODO: Might be needed to include nextHop here
1557 LOG.info("removeLearntPrefixFromBGP: VPN WITHDRAW: Removed Fib Entry rd {} prefix {} nexthop {}",
1558 rd, prefix, nextHop);
1559 } catch (Exception e) {
1560 LOG.error("removeLearntPrefixFromBGP: Delete prefix {} rd {} nextHop {} failed", prefix, rd, nextHop, e);
1564 private void removeGwMacAndArpResponderFlows(Adjacency nextHop, Uint32 vpnId, Uint64 dpnId,
1565 int lportTag, String gwMac, String gwIp, String interfaceName,
1566 TypedReadWriteTransaction<Configuration> writeInvTxn)
1567 throws ExecutionException, InterruptedException {
1568 final Uuid subnetId = nextHop.getSubnetId();
1569 if (nextHop.getSubnetGatewayMacAddress() == null) {
1570 // A valid mac-address was not available for this subnet-gateway-ip
1571 // So a connected-mac-address was used for this subnet and we need
1572 // to remove the flows for the same here from the L3_GW_MAC_TABLE.
1573 vpnUtil.setupGwMacIfExternalVpn(dpnId, interfaceName, vpnId, writeInvTxn, NwConstants.DEL_FLOW, gwMac);
1575 arpResponderHandler.removeArpResponderFlow(dpnId, lportTag, interfaceName, gwIp,
1579 private List<String> getNextHopForNonPrimaryAdjacency(Adjacency nextHop, String vpnName, Uint64 dpnId,
1580 String interfaceName) {
1581 // This is either an extra-route (or) a learned IP via subnet-route
1582 List<String> nhList = null;
1583 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
1584 if (nextHopIp == null || nextHopIp.isEmpty()) {
1585 LOG.error("removeAdjacenciesFromVpn: Unable to obtain nextHopIp for"
1586 + " extra-route/learned-route in rd {} prefix {} interface {} on dpn {}"
1587 + " for vpn {}", nextHop.getVrfId(), nextHop.getIpAddress(), interfaceName, dpnId,
1589 nhList = emptyList();
1591 nhList = Collections.singletonList(nextHopIp);
1596 private Optional<String> getMacAddressForSubnetIp(String vpnName, String ifName, String ipAddress) {
1597 VpnPortipToPort gwPort = vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnName, ipAddress);
1598 //Check if a router gateway interface is available for the subnet gw is so then use Router interface
1599 // else use connected interface
1600 if (gwPort != null && gwPort.isSubnetIp()) {
1601 LOG.info("getGatewayMacAddressForSubnetIp: Retrieved gw Mac as {} for ip {} interface {} vpn {}",
1602 gwPort.getMacAddress(), ipAddress, ifName, vpnName);
1603 return Optional.of(gwPort.getMacAddress());
1605 return Optional.empty();
1609 public void update(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface original,
1610 final VpnInterface update) {
1611 LOG.trace("Received VpnInterface update event: original={}, update={}", original, update);
1612 LOG.info("update: VPN Interface update event - intfName {} on dpn {} oldVpn {} newVpn {}", update.getName(),
1613 update.getDpnId(), original.getVpnInstanceNames(), update.getVpnInstanceNames());
1614 if (original.equals(update)) {
1615 LOG.info("update: original {} update {} are same. No update required.", original, update);
1618 final String vpnInterfaceName = update.getName();
1619 final Uint64 dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
1620 LOG.info("VPN Interface update event - intfName {}", vpnInterfaceName);
1621 //handles switching between <internal VPN - external VPN>
1622 jobCoordinator.enqueueJob("VPNINTERFACE-" + vpnInterfaceName, () -> {
1623 List<ListenableFuture<Void>> futures = new ArrayList<>();
1624 if (handleVpnInstanceUpdateForVpnInterface(identifier, original, update, futures)) {
1625 LOG.info("update: handled Instance update for VPNInterface {} on dpn {} from oldVpn(s) {} "
1626 + "to newVpn(s) {}",
1627 original.getName(), dpnId,
1628 VpnHelper.getVpnInterfaceVpnInstanceNamesString(original.getVpnInstanceNames()),
1629 VpnHelper.getVpnInterfaceVpnInstanceNamesString(update.getVpnInstanceNames()));
1632 updateVpnInstanceAdjChange(original, update, vpnInterfaceName, futures);
1637 private boolean handleVpnInstanceUpdateForVpnInterface(InstanceIdentifier<VpnInterface> identifier,
1638 VpnInterface original, VpnInterface update,
1639 List<ListenableFuture<Void>> futures) {
1640 boolean isVpnInstanceUpdate = false;
1641 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class);
1642 final String interfaceName = key.getName();
1643 List<String> oldVpnList = VpnUtil.getVpnListForVpnInterface(original);
1644 List<String> oldVpnListCopy = new ArrayList<>();
1645 oldVpnListCopy.addAll(oldVpnList);
1646 List<String> newVpnList = VpnUtil.getVpnListForVpnInterface(update);
1647 List<String> newVpnListCopy = new ArrayList<>();
1648 newVpnListCopy.addAll(newVpnList);
1650 oldVpnList.removeAll(newVpnList);
1651 newVpnList.removeAll(oldVpnListCopy);
1652 //This block will execute only on if there is a change in the VPN Instance.
1653 if (!oldVpnList.isEmpty() || !newVpnList.isEmpty()) {
1655 * Internet BGP-VPN Instance update with single router:
1656 * ====================================================
1657 * In this case single VPN Interface will be part of maximum 2 VPN Instance only.
1658 * 1st VPN Instance : router VPN or external BGP-VPN.
1659 * 2nd VPN Instance : Internet BGP-VPN(router-gw update/delete) for public network access.
1661 * VPN Instance UPDATE:
1662 * oldVpnList = 0 and newVpnList = 1 (Internet BGP-VPN)
1663 * oldVpnList = 1 and newVpnList = 0 (Internet BGP-VPN)
1665 * External BGP-VPN Instance update with single router:
1666 * ====================================================
1667 * In this case single VPN interface will be part of maximum 1 VPN Instance only.
1669 * Updated VPN Instance will be always either internal router VPN to
1670 * external BGP-VPN or external BGP-VPN to internal router VPN swap.
1672 * VPN Instance UPDATE:
1673 * oldVpnList = 1 and newVpnList = 1 (router VPN to Ext-BGPVPN)
1674 * oldVpnList = 1 and newVpnList = 1 (Ext-BGPVPN to router VPN)
1676 * Dual Router VPN Instance Update:
1677 * ================================
1678 * In this case single VPN interface will be part of maximum 3 VPN Instance only.
1680 * 1st VPN Instance : router VPN or external BGP-VPN-1.
1681 * 2nd VPN Instance : router VPN or external BGP-VPN-2.
1682 * 3rd VPN Instance : Internet BGP-VPN(router-gw update/delete) for public network access.
1684 * Dual Router --> Associated with common external BGP-VPN Instance.
1685 * 1st router and 2nd router are getting associated with single External BGP-VPN
1686 * 1) add 1st router to external bgpvpn --> oldVpnList=1, newVpnList=1;
1687 * 2) add 2nd router to the same external bgpvpn --> oldVpnList=1, newVpnList=0
1688 * In this case, we need to call removeVpnInterfaceCall() followed by addVpnInterfaceCall()
1692 isVpnInstanceUpdate = true;
1693 if (VpnUtil.isDualRouterVpnUpdate(oldVpnListCopy, newVpnListCopy)) {
1694 if ((oldVpnListCopy.size() == 2 || oldVpnListCopy.size() == 3)
1695 && oldVpnList.size() == 1 && newVpnList.isEmpty()) {
1696 //Identify the external BGP-VPN Instance and pass that value as newVpnList
1697 List<String> externalBgpVpnList = new ArrayList<>();
1698 for (String newVpnName : newVpnListCopy) {
1699 String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
1700 VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(primaryRd);
1701 if (vpnInstanceOpDataEntry.getBgpvpnType() == VpnInstanceOpDataEntry
1702 .BgpvpnType.BGPVPNExternal) {
1703 externalBgpVpnList.add(newVpnName);
1707 //This call will execute removeVpnInterfaceCall() followed by addVpnInterfaceCall()
1708 updateVpnInstanceChange(identifier, interfaceName, original, update, oldVpnList,
1709 externalBgpVpnList, oldVpnListCopy, futures);
1711 } else if ((oldVpnListCopy.size() == 2 || oldVpnListCopy.size() == 3)
1712 && oldVpnList.isEmpty() && newVpnList.size() == 1) {
1713 //Identify the router VPN Instance and pass that value as oldVpnList
1714 List<String> routerVpnList = new ArrayList<>();
1715 for (String newVpnName : newVpnListCopy) {
1716 String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
1717 VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(primaryRd);
1718 if (vpnInstanceOpDataEntry.getBgpvpnType() == VpnInstanceOpDataEntry
1720 routerVpnList.add(newVpnName);
1724 //This call will execute removeVpnInterfaceCall() followed by addVpnInterfaceCall()
1725 updateVpnInstanceChange(identifier, interfaceName, original, update, routerVpnList,
1726 newVpnList, oldVpnListCopy, futures);
1729 //Handle remaining use cases.
1730 updateVpnInstanceChange(identifier, interfaceName, original, update, oldVpnList, newVpnList,
1731 oldVpnListCopy, futures);
1734 updateVpnInstanceChange(identifier, interfaceName, original, update, oldVpnList, newVpnList,
1735 oldVpnListCopy, futures);
1738 return isVpnInstanceUpdate;
1741 private void updateVpnInstanceChange(InstanceIdentifier<VpnInterface> identifier, String interfaceName,
1742 VpnInterface original, VpnInterface update, List<String> oldVpnList,
1743 List<String> newVpnList, List<String> oldVpnListCopy,
1744 List<ListenableFuture<Void>> futures) {
1745 final Adjacencies origAdjs = original.augmentation(Adjacencies.class);
1746 final List<Adjacency> oldAdjs = origAdjs != null && origAdjs.getAdjacency() != null
1747 ? origAdjs.getAdjacency() : new ArrayList<>();
1748 final Adjacencies updateAdjs = update.augmentation(Adjacencies.class);
1749 final List<Adjacency> newAdjs = updateAdjs != null && updateAdjs.getAdjacency() != null
1750 ? updateAdjs.getAdjacency() : new ArrayList<>();
1752 boolean isOldVpnRemoveCallExecuted = false;
1753 for (String oldVpnName : oldVpnList) {
1754 LOG.info("updateVpnInstanceChange: VPN Interface update event - intfName {} "
1755 + "remove from vpnName {} ", interfaceName, oldVpnName);
1756 removeVpnInterfaceCall(identifier, original, oldVpnName, interfaceName);
1757 LOG.info("updateVpnInstanceChange: Processed Remove for update on VPNInterface"
1758 + " {} upon VPN update from old vpn {} to newVpn(s) {}", interfaceName, oldVpnName,
1760 isOldVpnRemoveCallExecuted = true;
1762 //Wait for previous interface bindings to be removed
1763 if (isOldVpnRemoveCallExecuted && !newVpnList.isEmpty()) {
1766 } catch (InterruptedException e) {
1767 LOG.error("updateVpnInstanceChange: InterruptedException caught for interface {}", interfaceName, e);
1770 for (String newVpnName : newVpnList) {
1771 String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
1772 if (!vpnUtil.isVpnPendingDelete(primaryRd)) {
1773 LOG.info("updateVpnInstanceChange: VPN Interface update event - intfName {} "
1774 + "onto vpnName {} ", interfaceName, newVpnName);
1775 addVpnInterfaceCall(identifier, update, oldAdjs, newAdjs, newVpnName);
1776 LOG.info("updateVpnInstanceChange: Processed Add for update on VPNInterface {}"
1777 + "from oldVpn(s) {} to newVpn {} ",
1778 interfaceName, oldVpnListCopy, newVpnName);
1779 /* This block will execute only if V6 subnet is associated with internet BGP-VPN.
1781 * In Dual stack network, first V4 subnet only attached to router and router is associated
1782 * with internet BGP-VPN(router-gw). At this point VPN interface is having only router vpn instance.
1783 * Later V6 subnet is added to router, at this point existing VPN interface will get updated
1784 * with Internet BGP-VPN instance(Note: Internet BGP-VPN Instance update in vpn interface
1785 * is applicable for only on V6 subnet is added to router). newVpnList = Contains only Internet
1786 * BGP-VPN Instance. So we required V6 primary adjacency info needs to be populated onto
1787 * router VPN as well as Internet BGP-VPN.
1789 * addVpnInterfaceCall() --> It will create V6 Adj onto Internet BGP-VPN only.
1790 * updateVpnInstanceAdjChange() --> This method call is needed for second primary V6 Adj
1791 * update in existing router VPN instance.
1793 if (vpnUtil.isBgpVpnInternet(newVpnName)) {
1794 LOG.info("updateVpnInstanceChange: VPN Interface {} with new Adjacency {} in existing "
1795 + "VPN instance {}", interfaceName, newAdjs, original.getVpnInstanceNames());
1796 updateVpnInstanceAdjChange(original, update, interfaceName, futures);
1799 LOG.info("updateVpnInstanceChange: failed to Add for update on VPNInterface {} from oldVpn(s) {} to "
1800 + "newVpn {} as the new vpn does not exist in oper DS or it is in PENDING_DELETE state",
1801 interfaceName, oldVpnListCopy, newVpnName);
1806 // TODO Clean up the exception handling
1807 @SuppressWarnings("checkstyle:IllegalCatch")
1808 private List<ListenableFuture<Void>> updateVpnInstanceAdjChange(VpnInterface original, VpnInterface update,
1809 String vpnInterfaceName,
1810 List<ListenableFuture<Void>> futures) {
1811 final Adjacencies origAdjs = original.augmentation(Adjacencies.class);
1812 final List<Adjacency> oldAdjs = origAdjs != null && origAdjs.getAdjacency()
1813 != null ? origAdjs.getAdjacency() : new ArrayList<>();
1814 final Adjacencies updateAdjs = update.augmentation(Adjacencies.class);
1815 final List<Adjacency> newAdjs = updateAdjs != null && updateAdjs.getAdjacency()
1816 != null ? updateAdjs.getAdjacency() : new ArrayList<>();
1818 final Uint64 dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
1819 for (VpnInstanceNames vpnInterfaceVpnInstance : update.nonnullVpnInstanceNames()) {
1820 String newVpnName = vpnInterfaceVpnInstance.getVpnName();
1821 List<Adjacency> copyNewAdjs = new ArrayList<>(newAdjs);
1822 List<Adjacency> copyOldAdjs = new ArrayList<>(oldAdjs);
1823 String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
1824 if (!vpnUtil.isVpnPendingDelete(primaryRd)) {
1825 // TODO Deal with sequencing — the config tx must only submitted if the oper tx goes in
1826 //set of prefix used as entry in prefix-to-interface datastore
1827 // is prerequisite for refresh Fib to avoid race condition leading to missing remote next hop
1828 // in bucket actions on bgp-vpn delete
1829 Set<String> prefixListForRefreshFib = new HashSet<>();
1830 ListenableFuture<Void> configTxFuture = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
1831 confTx -> futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL,
1833 InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier =
1834 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterfaceName, newVpnName);
1835 LOG.info("VPN Interface update event-intfName {} onto vpnName {} running config-driven",
1836 update.getName(), newVpnName);
1837 //handle both addition and removal of adjacencies
1838 // currently, new adjacency may be an extra route
1839 boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(newVpnName);
1840 if (!oldAdjs.equals(newAdjs)) {
1841 for (Adjacency adj : copyNewAdjs) {
1842 if (copyOldAdjs.contains(adj)) {
1843 copyOldAdjs.remove(adj);
1845 // add new adjacency
1846 if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
1848 addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adj,
1849 dpnId, operTx, confTx, confTx, prefixListForRefreshFib);
1850 } catch (RuntimeException e) {
1851 LOG.error("Failed to add adjacency {} to vpn interface {} with"
1852 + " dpnId {}", adj, vpnInterfaceName, dpnId, e);
1855 LOG.info("update: new Adjacency {} with nextHop {} label {} subnet {} "
1856 + " added to vpn interface {} on vpn {} dpnId {}",
1857 adj.getIpAddress(), adj.getNextHopIpList(), adj.getLabel(),
1858 adj.getSubnetId(), update.getName(), newVpnName, dpnId);
1861 for (Adjacency adj : copyOldAdjs) {
1862 if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
1863 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency
1864 && !adj.isPhysNetworkFunc()) {
1865 delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId, operTx,
1868 String vpnRd = vpnUtil.getVpnRd(newVpnName);
1869 LOG.debug("update: remove prefix {} from the FIB and BGP entry "
1870 + "for the Vpn-Rd {} ", adj.getIpAddress(), vpnRd);
1872 fibManager.removeFibEntry(vpnRd, adj.getIpAddress(), null, confTx);
1873 if (vpnRd != null && !vpnRd.equalsIgnoreCase(newVpnName)) {
1874 bgpManager.withdrawPrefix(vpnRd, adj.getIpAddress());
1877 delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId,
1881 LOG.info("update: Adjacency {} with nextHop {} label {} subnet {} removed from"
1882 + " vpn interface {} on vpn {}", adj.getIpAddress(), adj.getNextHopIpList(),
1883 adj.getLabel(), adj.getSubnetId(), update.getName(), newVpnName);
1887 Futures.addCallback(configTxFuture, new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
1888 MoreExecutors.directExecutor());
1889 futures.add(configTxFuture);
1890 for (ListenableFuture<Void> future : futures) {
1891 ListenableFutures.addErrorLogging(future, LOG, "update: failed for interface {} on vpn {}",
1892 update.getName(), update.getVpnInstanceNames());
1895 LOG.error("update: Ignoring update of vpnInterface {}, as newVpnInstance {} with primaryRd {}"
1896 + " is already marked for deletion", vpnInterfaceName, newVpnName, primaryRd);
1902 private void updateLabelMapper(Uint32 label, List<String> nextHopIpList) {
1903 final String labelStr = Preconditions.checkNotNull(label, "updateLabelMapper: label cannot be null or empty!")
1905 // FIXME: separate this out somehow?
1906 final ReentrantLock lock = JvmGlobalLocks.getLockForString(labelStr);
1909 InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
1910 .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build();
1911 Optional<LabelRouteInfo> opResult = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1912 LogicalDatastoreType.OPERATIONAL, lriIid);
1913 if (opResult.isPresent()) {
1914 LabelRouteInfo labelRouteInfo =
1915 new LabelRouteInfoBuilder(opResult.get()).setNextHopIpList(nextHopIpList).build();
1916 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid,
1917 labelRouteInfo, VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
1919 LOG.info("updateLabelMapper: Updated label rotue info for label {} with nextHopList {}", label,
1921 } catch (InterruptedException | ExecutionException e) {
1922 LOG.error("updateLabelMapper: Failed to read data store for label {} nexthopList {}", label,
1924 } catch (TransactionCommitFailedException e) {
1925 LOG.error("updateLabelMapper: Failed to commit to data store for label {} nexthopList {}", label,
1932 public synchronized void importSubnetRouteForNewVpn(String rd, String prefix, String nextHop, Uint32 label,
1933 SubnetRoute route, String parentVpnRd, TypedWriteTransaction<Configuration> writeConfigTxn) {
1935 RouteOrigin origin = RouteOrigin.SELF_IMPORTED;
1936 VrfEntry vrfEntry = FibHelper.getVrfEntryBuilder(prefix, label, nextHop, origin, parentVpnRd)
1937 .addAugmentation(SubnetRoute.class, route).build();
1938 List<VrfEntry> vrfEntryList = Collections.singletonList(vrfEntry);
1939 InstanceIdentifierBuilder<VrfTables> idBuilder =
1940 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1941 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
1942 VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).setVrfEntry(vrfEntryList).build();
1943 if (writeConfigTxn != null) {
1944 writeConfigTxn.merge(vrfTableId, vrfTableNew, CREATE_MISSING_PARENTS);
1946 vpnUtil.syncUpdate(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
1948 LOG.info("SUBNETROUTE: importSubnetRouteForNewVpn: Created vrfEntry for rd {} prefix {} nexthop {} label {}"
1949 + " and elantag {}", rd, prefix, nextHop, label, route.getElantag());
1952 protected void addNewAdjToVpnInterface(InstanceIdentifier<VpnInterfaceOpDataEntry> identifier, String primaryRd,
1953 Adjacency adj, Uint64 dpnId,
1954 TypedWriteTransaction<Operational> writeOperTxn,
1955 TypedWriteTransaction<Configuration> writeConfigTxn,
1956 TypedReadWriteTransaction<Configuration> writeInvTxn,
1957 Set<String> prefixListForRefreshFib)
1958 throws ExecutionException, InterruptedException {
1959 String interfaceName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getName();
1960 String configVpnName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getVpnInstanceName();
1962 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker
1963 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, identifier);
1964 if (optVpnInterface.isPresent()) {
1965 VpnInterfaceOpDataEntry currVpnIntf = optVpnInterface.get();
1966 String prefix = VpnUtil.getIpPrefix(adj.getIpAddress());
1967 String vpnName = currVpnIntf.getVpnInstanceName();
1968 VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(primaryRd);
1969 InstanceIdentifier<AdjacenciesOp> adjPath = identifier.augmentation(AdjacenciesOp.class);
1970 Optional<AdjacenciesOp> optAdjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1971 LogicalDatastoreType.OPERATIONAL, adjPath);
1972 boolean isL3VpnOverVxLan = VpnUtil.isL3VpnOverVxLan(vpnInstanceOpData.getL3vni());
1973 VrfEntry.EncapType encapType = VpnUtil.getEncapType(isL3VpnOverVxLan);
1974 Uint32 l3vni = vpnInstanceOpData.getL3vni() == null ? Uint32.ZERO : vpnInstanceOpData.getL3vni();
1975 VpnPopulator populator = L3vpnRegistry.getRegisteredPopulator(encapType);
1976 List<Adjacency> adjacencies = new ArrayList<>();
1977 if (optAdjacencies.isPresent() && optAdjacencies.get().getAdjacency() != null) {
1978 adjacencies.addAll(optAdjacencies.get().getAdjacency());
1980 Uint32 vpnId = vpnUtil.getVpnId(vpnName);
1981 L3vpnInput input = new L3vpnInput().setNextHop(adj).setVpnName(vpnName)
1982 .setInterfaceName(currVpnIntf.getName()).setPrimaryRd(primaryRd).setRd(primaryRd);
1983 Adjacency operationalAdjacency = null;
1984 //Handling dual stack neutron port primary adjacency
1985 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency && !adj.isPhysNetworkFunc()) {
1986 LOG.trace("addNewAdjToVpnInterface: Adding prefix {} to existing interface {} for vpn {}", prefix,
1987 currVpnIntf.getName(), vpnName);
1988 Interface interfaceState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker,
1989 currVpnIntf.getName());
1990 if (interfaceState != null) {
1991 processVpnInterfaceAdjacencies(dpnId, currVpnIntf.getLportTag().intValue(), vpnName, primaryRd,
1992 currVpnIntf.getName(), vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState,
1993 prefixListForRefreshFib);
1996 if (adj.getNextHopIpList() != null && !adj.getNextHopIpList().isEmpty()
1997 && adj.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
1998 RouteOrigin origin = adj.getAdjacencyType() == AdjacencyType.LearntIp ? RouteOrigin.DYNAMIC
1999 : RouteOrigin.STATIC;
2000 String nh = adj.getNextHopIpList().get(0);
2001 String vpnPrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
2002 // FIXME: separate out to somehow?
2003 final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnPrefixKey);
2006 java.util.Optional<String> rdToAllocate = vpnUtil.allocateRdForExtraRouteAndUpdateUsedRdsMap(
2007 vpnId, null, prefix, vpnName, nh, dpnId);
2008 if (rdToAllocate.isPresent()) {
2009 input.setRd(rdToAllocate.get());
2010 operationalAdjacency = populator.createOperationalAdjacency(input);
2011 int label = operationalAdjacency.getLabel().intValue();
2012 vpnManager.addExtraRoute(vpnName, adj.getIpAddress(), nh, rdToAllocate.get(),
2013 currVpnIntf.getVpnInstanceName(), l3vni, origin,
2014 currVpnIntf.getName(), operationalAdjacency, encapType,
2015 prefixListForRefreshFib, writeConfigTxn);
2016 LOG.info("addNewAdjToVpnInterface: Added extra route ip {} nh {} rd {} vpnname {} label {}"
2017 + " Interface {} on dpn {}", adj.getIpAddress(), nh, rdToAllocate.get(),
2018 vpnName, label, currVpnIntf.getName(), dpnId);
2020 LOG.error("addNewAdjToVpnInterface: No rds to allocate extraroute vpn {} prefix {}",
2024 // iRT/eRT use case Will be handled in a new patchset for L3VPN Over VxLAN.
2025 // Keeping the MPLS check for now.
2026 if (encapType.equals(VrfEntryBase.EncapType.Mplsgre)) {
2027 final Adjacency opAdjacency = new AdjacencyBuilder(operationalAdjacency).build();
2028 List<VpnInstanceOpDataEntry> vpnsToImportRoute =
2029 vpnUtil.getVpnsImportingMyRoute(vpnName);
2030 vpnsToImportRoute.forEach(vpn -> {
2031 if (vpn.getVrfId() != null) {
2032 vpnUtil.allocateRdForExtraRouteAndUpdateUsedRdsMap(vpn.getVpnId(),
2034 vpnUtil.getVpnName(vpn.getVpnId()), nh, dpnId)
2036 rds -> vpnManager.addExtraRoute(
2037 vpnUtil.getVpnName(vpn.getVpnId()), adj.getIpAddress(),
2038 nh, rds, currVpnIntf.getVpnInstanceName(), l3vni,
2039 RouteOrigin.SELF_IMPORTED, currVpnIntf.getName(), opAdjacency,
2040 encapType, prefixListForRefreshFib, writeConfigTxn));
2047 } else if (adj.isPhysNetworkFunc()) { // PNF adjacency.
2048 LOG.trace("addNewAdjToVpnInterface: Adding prefix {} to interface {} for vpn {}", prefix,
2049 currVpnIntf.getName(), vpnName);
2051 InstanceIdentifier<VpnInterface> vpnIfaceConfigidentifier = VpnUtil
2052 .getVpnInterfaceIdentifier(currVpnIntf.getName());
2053 Optional<VpnInterface> vpnIntefaceConfig = SingleTransactionDataBroker.syncReadOptional(dataBroker,
2054 LogicalDatastoreType.CONFIGURATION, vpnIfaceConfigidentifier);
2055 Prefixes pnfPrefix = VpnUtil.getPrefixToInterface(Uint64.ZERO, currVpnIntf.getName(), prefix,
2056 Prefixes.PrefixCue.PhysNetFunc);
2057 if (vpnIntefaceConfig.isPresent()) {
2058 pnfPrefix = VpnUtil.getPrefixToInterface(Uint64.ZERO, currVpnIntf.getName(), prefix,
2059 vpnIntefaceConfig.get().getNetworkId(), vpnIntefaceConfig.get().getNetworkType(),
2060 vpnIntefaceConfig.get().getSegmentationId().toJava(), Prefixes.PrefixCue.PhysNetFunc);
2063 String parentVpnRd = getParentVpnRdForExternalSubnet(adj);
2066 VpnUtil.getPrefixToInterfaceIdentifier(vpnUtil.getVpnId(adj.getSubnetId().getValue()),
2067 prefix), pnfPrefix, true);
2069 fibManager.addOrUpdateFibEntry(adj.getSubnetId().getValue(), adj.getMacAddress(),
2070 adj.getIpAddress(), emptyList(), null /* EncapType */, Uint32.ZERO /* label */,
2071 Uint32.ZERO /*l3vni*/, null /* gw-mac */, parentVpnRd,
2072 RouteOrigin.LOCAL, writeConfigTxn);
2074 input.setRd(adj.getVrfId());
2076 if (operationalAdjacency == null) {
2077 operationalAdjacency = populator.createOperationalAdjacency(input);
2079 adjacencies.add(operationalAdjacency);
2080 AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(adjacencies);
2081 VpnInterfaceOpDataEntry newVpnIntf =
2082 VpnUtil.getVpnInterfaceOpDataEntry(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(),
2083 aug, dpnId, currVpnIntf.getLportTag().toJava(),
2084 currVpnIntf.getGatewayMacAddress(), currVpnIntf.getGatewayIpAddress());
2085 writeOperTxn.merge(identifier, newVpnIntf, CREATE_MISSING_PARENTS);
2087 } catch (InterruptedException | ExecutionException e) {
2088 LOG.error("addNewAdjToVpnInterface: Failed to read data store for interface {} dpn {} vpn {} rd {} ip "
2089 + "{}", interfaceName, dpnId, configVpnName, primaryRd, adj.getIpAddress());
2094 private String getParentVpnRdForExternalSubnet(Adjacency adj) {
2095 Subnets subnets = vpnUtil.getExternalSubnet(adj.getSubnetId());
2096 return subnets != null ? subnets.getExternalNetworkId().getValue() : null;
2099 protected void delAdjFromVpnInterface(InstanceIdentifier<VpnInterfaceOpDataEntry> identifier, Adjacency adj,
2100 Uint64 dpnId, TypedWriteTransaction<Operational> writeOperTxn,
2101 TypedWriteTransaction<Configuration> writeConfigTxn) {
2102 String interfaceName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getName();
2103 String vpnName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getVpnInstanceName();
2105 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker.syncReadOptional(
2106 dataBroker, LogicalDatastoreType.OPERATIONAL, identifier);
2107 if (optVpnInterface.isPresent()) {
2108 VpnInterfaceOpDataEntry currVpnIntf = optVpnInterface.get();
2109 InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
2110 Optional<AdjacenciesOp> optAdjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
2111 LogicalDatastoreType.OPERATIONAL, path);
2112 if (optAdjacencies.isPresent()) {
2113 List<Adjacency> adjacencies = optAdjacencies.get().getAdjacency();
2115 if (adjacencies != null && !adjacencies.isEmpty()) {
2116 LOG.trace("delAdjFromVpnInterface: Adjacencies are {}", adjacencies);
2117 for (Adjacency adjacency : adjacencies) {
2118 if (Objects.equals(adjacency.getIpAddress(), adj.getIpAddress())) {
2119 String rd = adjacency.getVrfId();
2120 if (adj.getNextHopIpList() != null) {
2121 for (String nh : adj.getNextHopIpList()) {
2122 deleteExtraRouteFromCurrentAndImportingVpns(
2123 currVpnIntf.getVpnInstanceName(), adj.getIpAddress(), nh, rd,
2124 currVpnIntf.getName(), writeConfigTxn, writeOperTxn);
2126 } else if (adj.isPhysNetworkFunc()) {
2127 LOG.info("delAdjFromVpnInterface: deleting PNF adjacency prefix {} subnet {}",
2128 adj.getIpAddress(), adj.getSubnetId());
2129 fibManager.removeFibEntry(adj.getSubnetId().getValue(), adj.getIpAddress(),
2130 null, writeConfigTxn);
2137 LOG.info("delAdjFromVpnInterface: Removed adj {} on dpn {} rd {}", adj.getIpAddress(),
2138 dpnId, adj.getVrfId());
2140 LOG.error("delAdjFromVpnInterface: Cannnot DEL adjacency, since operational interface is "
2141 + "unavailable dpnId {} adjIP {} rd {}", dpnId, adj.getIpAddress(), adj.getVrfId());
2144 } catch (InterruptedException | ExecutionException e) {
2145 LOG.error("delAdjFromVpnInterface: Failed to read data store for ip {} interface {} dpn {} vpn {}",
2146 adj.getIpAddress(), interfaceName, dpnId, vpnName);
2150 private void deleteExtraRouteFromCurrentAndImportingVpns(String vpnName, String destination, String nextHop,
2151 String rd, String intfName, TypedWriteTransaction<Configuration> writeConfigTxn,
2152 TypedWriteTransaction<Operational> writeOperTx) {
2153 LOG.info("removing extra-route {} for nexthop {} in VPN {} intfName {} rd {}",
2154 destination, nextHop, vpnName, intfName, rd);
2155 vpnManager.delExtraRoute(vpnName, destination, nextHop, rd, vpnName, intfName, writeConfigTxn, writeOperTx);
2156 List<VpnInstanceOpDataEntry> vpnsToImportRoute = vpnUtil.getVpnsImportingMyRoute(vpnName);
2157 for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
2158 String vpnRd = vpn.getVrfId();
2159 if (vpnRd != null) {
2160 LOG.info("deleting extra-route {} for nexthop {} in VPN {} intfName {} vpnRd {}",
2161 destination, nextHop, vpnName, intfName, vpnRd);
2162 vpnManager.delExtraRoute(vpnName, destination, nextHop, vpnRd, vpnName, intfName, writeConfigTxn,
2168 InstanceIdentifier<DpnVpninterfacesList> getRouterDpnId(String routerName, Uint64 dpnId) {
2169 return InstanceIdentifier.builder(NeutronRouterDpns.class)
2170 .child(RouterDpnList.class, new RouterDpnListKey(routerName))
2171 .child(DpnVpninterfacesList.class, new DpnVpninterfacesListKey(dpnId)).build();
2174 InstanceIdentifier<RouterDpnList> getRouterId(String routerName) {
2175 return InstanceIdentifier.builder(NeutronRouterDpns.class)
2176 .child(RouterDpnList.class, new RouterDpnListKey(routerName)).build();
2179 protected void createFibEntryForRouterInterface(String primaryRd, VpnInterface vpnInterface, String interfaceName,
2180 TypedWriteTransaction<Configuration> writeConfigTxn, String vpnName) {
2181 if (vpnInterface == null) {
2184 List<Adjacency> adjs = vpnUtil.getAdjacenciesForVpnInterfaceFromConfig(interfaceName);
2186 LOG.error("createFibEntryForRouterInterface: VPN Interface {} of router addition failed as adjacencies for"
2187 + " this vpn interface could not be obtained. vpn {}", interfaceName, vpnName);
2190 for (Adjacency adj : adjs) {
2191 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
2192 String primaryInterfaceIp = adj.getIpAddress();
2193 String macAddress = adj.getMacAddress();
2194 String prefix = VpnUtil.getIpPrefix(primaryInterfaceIp);
2196 Uint32 label = vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME,
2197 VpnUtil.getNextHopLabelKey(primaryRd, prefix));
2198 if (label.longValue() == VpnConstants.INVALID_LABEL) {
2200 "createFibEntryForRouterInterface: Unable to retrieve label for vpn pool {}, "
2201 + "vpninterface {}, vpn {}, rd {}",
2202 VpnConstants.VPN_IDPOOL_NAME, interfaceName, vpnName, primaryRd);
2205 RouterInterface routerInt = new RouterInterfaceBuilder().setUuid(vpnName)
2206 .setIpAddress(primaryInterfaceIp).setMacAddress(macAddress).build();
2207 fibManager.addFibEntryForRouterInterface(primaryRd, prefix,
2208 routerInt, label, writeConfigTxn);
2209 LOG.info("createFibEntryForRouterInterface: Router interface {} for vpn {} rd {} prefix {} label {}"
2210 + " macAddress {} processed successfully;", interfaceName, vpnName, primaryRd, prefix, label,
2213 LOG.error("createFibEntryForRouterInterface: VPN Interface {} of router addition failed as primary"
2214 + " adjacency for this vpn interface could not be obtained. rd {} vpnName {}",
2215 interfaceName, primaryRd, vpnName);
2220 protected void deleteFibEntryForRouterInterface(VpnInterface vpnInterface,
2221 TypedWriteTransaction<Configuration> writeConfigTxn, String vpnName) {
2222 Adjacencies adjs = vpnInterface.augmentation(Adjacencies.class);
2223 String rd = vpnUtil.getVpnRd(vpnName);
2225 List<Adjacency> adjsList = adjs.nonnullAdjacency();
2226 for (Adjacency adj : adjsList) {
2227 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
2228 String primaryInterfaceIp = adj.getIpAddress();
2229 String prefix = VpnUtil.getIpPrefix(primaryInterfaceIp);
2230 fibManager.removeFibEntry(rd, prefix, null, writeConfigTxn);
2231 LOG.info("deleteFibEntryForRouterInterface: FIB for router interface {} deleted for vpn {} rd {}"
2232 + " prefix {}", vpnInterface.getName(), vpnName, rd, prefix);
2236 LOG.error("deleteFibEntryForRouterInterface: Adjacencies for vpninterface {} is null, rd: {}",
2237 vpnInterface.getName(), rd);
2241 private void processSavedInterface(UnprocessedVpnInterfaceData intefaceData, String vpnName) {
2242 final VpnInterfaceKey key = intefaceData.identifier.firstKeyOf(VpnInterface.class);
2243 final String interfaceName = key.getName();
2244 InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier = VpnUtil
2245 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
2246 addVpnInterfaceToVpn(vpnInterfaceOpIdentifier, intefaceData.vpnInterface, null, null,
2247 intefaceData.identifier, vpnName);
2250 private void addToUnprocessedVpnInterfaces(InstanceIdentifier<VpnInterface> identifier,
2251 VpnInterface vpnInterface, String vpnName) {
2252 ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces = unprocessedVpnInterfaces
2254 if (vpnInterfaces == null) {
2255 vpnInterfaces = new ConcurrentLinkedQueue<>();
2257 vpnInterfaces.add(new UnprocessedVpnInterfaceData(identifier, vpnInterface));
2258 unprocessedVpnInterfaces.put(vpnName, vpnInterfaces);
2259 LOG.info("addToUnprocessedVpnInterfaces: Saved unhandled vpn interface {} in vpn instance {}",
2260 vpnInterface.getName(), vpnName);
2263 public boolean isVpnInstanceReady(String vpnInstanceName) {
2264 String vpnRd = vpnUtil.getVpnRd(vpnInstanceName);
2265 if (vpnRd == null) {
2268 VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(vpnRd);
2270 return vpnInstanceOpDataEntry != null;
2273 public void processSavedInterfaces(String vpnInstanceName, boolean hasVpnInstanceCreatedSuccessfully) {
2274 // FIXME: separate out to somehow?
2275 final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnInstanceName);
2278 ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces =
2279 unprocessedVpnInterfaces.get(vpnInstanceName);
2280 if (vpnInterfaces != null) {
2281 while (!vpnInterfaces.isEmpty()) {
2282 UnprocessedVpnInterfaceData savedInterface = vpnInterfaces.poll();
2283 if (hasVpnInstanceCreatedSuccessfully) {
2284 processSavedInterface(savedInterface, vpnInstanceName);
2285 LOG.info("processSavedInterfaces: Handle saved vpn interfaces {} in vpn instance {}",
2286 savedInterface.vpnInterface.getName(), vpnInstanceName);
2288 LOG.error("processSavedInterfaces: Cannot process vpn interface {} in vpn instance {}",
2289 savedInterface.vpnInterface.getName(), vpnInstanceName);
2293 LOG.info("processSavedInterfaces: No interfaces in queue for VPN {}", vpnInstanceName);
2300 private void removeInterfaceFromUnprocessedList(InstanceIdentifier<VpnInterface> identifier,
2301 VpnInterface vpnInterface) {
2302 // FIXME: use VpnInstanceNamesKey perhaps? What about nulls?
2303 final String firstVpnName = VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface);
2304 final ReentrantLock lock = JvmGlobalLocks.getLockForString(firstVpnName);
2307 ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces =
2308 unprocessedVpnInterfaces.get(firstVpnName);
2309 if (vpnInterfaces != null) {
2310 if (vpnInterfaces.remove(new UnprocessedVpnInterfaceData(identifier, vpnInterface))) {
2311 LOG.info("removeInterfaceFromUnprocessedList: Removed vpn interface {} in vpn instance {} from "
2312 + "unprocessed list", vpnInterface.getName(), firstVpnName);
2315 LOG.info("removeInterfaceFromUnprocessedList: No interfaces in queue for VPN {}", firstVpnName);
2322 public void vpnInstanceIsReady(String vpnInstanceName) {
2323 processSavedInterfaces(vpnInstanceName, true);
2326 public void vpnInstanceFailed(String vpnInstanceName) {
2327 processSavedInterfaces(vpnInstanceName, false);
2330 private static class UnprocessedVpnInterfaceData {
2331 InstanceIdentifier<VpnInterface> identifier;
2332 VpnInterface vpnInterface;
2334 UnprocessedVpnInterfaceData(InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
2335 this.identifier = identifier;
2336 this.vpnInterface = vpnInterface;
2340 public int hashCode() {
2341 final int prime = 31;
2343 result = prime * result + (identifier == null ? 0 : identifier.hashCode());
2344 result = prime * result + (vpnInterface == null ? 0 : vpnInterface.hashCode());
2349 public boolean equals(Object obj) {
2356 if (getClass() != obj.getClass()) {
2359 UnprocessedVpnInterfaceData other = (UnprocessedVpnInterfaceData) obj;
2360 if (identifier == null) {
2361 if (other.identifier != null) {
2364 } else if (!identifier.equals(other.identifier)) {
2367 if (vpnInterface == null) {
2368 if (other.vpnInterface != null) {
2371 } else if (!vpnInterface.equals(other.vpnInterface)) {
2378 public void updateVpnInterfacesForUnProcessAdjancencies(String vpnName) {
2379 String primaryRd = vpnUtil.getVpnRd(vpnName);
2380 VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(primaryRd);
2381 if (vpnInstanceOpData == null) {
2384 List<VpnToDpnList> vpnToDpnLists = vpnInstanceOpData.getVpnToDpnList();
2385 if (vpnToDpnLists == null || vpnToDpnLists.isEmpty()) {
2388 LOG.debug("Update the VpnInterfaces for Unprocessed Adjancencies for vpnName:{}", vpnName);
2389 vpnToDpnLists.forEach(vpnToDpnList -> {
2390 if (vpnToDpnList.getVpnInterfaces() == null) {
2393 vpnToDpnList.getVpnInterfaces().forEach(vpnInterface -> {
2395 InstanceIdentifier<VpnInterfaceOpDataEntry> existingVpnInterfaceId =
2396 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterface.getInterfaceName(), vpnName);
2397 Optional<VpnInterfaceOpDataEntry> vpnInterfaceOptional = SingleTransactionDataBroker
2398 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, existingVpnInterfaceId);
2399 if (!vpnInterfaceOptional.isPresent()) {
2402 List<Adjacency> configVpnAdjacencies = vpnUtil.getAdjacenciesForVpnInterfaceFromConfig(
2403 vpnInterface.getInterfaceName());
2404 if (configVpnAdjacencies == null) {
2405 LOG.debug("There is no adjacency available for vpnInterface:{}", vpnInterface);
2408 List<Adjacency> operationVpnAdjacencies = vpnInterfaceOptional.get()
2409 .augmentation(AdjacenciesOp.class).nonnullAdjacency();
2410 // Due to insufficient rds, some of the extra route wont get processed when it is added.
2411 // The unprocessed adjacencies will be present in config vpn interface DS but will be missing
2412 // in operational DS. These unprocessed adjacencies will be handled below.
2413 // To obtain unprocessed adjacencies, filtering is done by which the missing adjacencies in
2414 // operational DS are retrieved which is used to call addNewAdjToVpnInterface method.
2415 configVpnAdjacencies.stream()
2416 .filter(adjacency -> operationVpnAdjacencies.stream()
2417 .noneMatch(operationalAdjacency ->
2418 Objects.equals(operationalAdjacency.getIpAddress(), adjacency.getIpAddress())))
2419 .forEach(adjacency -> {
2420 LOG.debug("Processing the vpnInterface{} for the Ajacency:{}", vpnInterface, adjacency);
2421 jobCoordinator.enqueueJob("VPNINTERFACE-" + vpnInterface.getInterfaceName(),
2423 // TODO Deal with sequencing — the config tx must only submitted
2424 // if the oper tx goes in
2425 if (vpnUtil.isAdjacencyEligibleToVpn(adjacency, vpnName)) {
2426 List<ListenableFuture<Void>> futures = new ArrayList<>();
2428 txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
2429 //set of prefix used, as entry in prefix-to-interface datastore
2430 // is prerequisite for refresh Fib to avoid race condition leading
2431 // to missing remote next hop in bucket actions on bgp-vpn delete
2432 Set<String> prefixListForRefreshFib = new HashSet<>();
2433 ListenableFuture<Void> configTxFuture =
2434 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
2435 confTx -> addNewAdjToVpnInterface(existingVpnInterfaceId,
2436 primaryRd, adjacency,
2437 vpnInterfaceOptional.get().getDpnId(),
2438 operTx, confTx, confTx, prefixListForRefreshFib));
2439 Futures.addCallback(configTxFuture,
2440 new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
2441 MoreExecutors.directExecutor());
2442 futures.add(configTxFuture);
2450 } catch (InterruptedException | ExecutionException e) {
2451 LOG.error("updateVpnInterfacesForUnProcessAdjancencies: Failed to read data store for vpn {} rd {}",
2452 vpnName, primaryRd);
2458 private class PostVpnInterfaceWorker implements FutureCallback<Void> {
2459 private final String interfaceName;
2460 private final boolean add;
2461 private final String txnDestination;
2463 PostVpnInterfaceWorker(String interfaceName, boolean add, String transactionDest) {
2464 this.interfaceName = interfaceName;
2466 this.txnDestination = transactionDest;
2470 public void onSuccess(Void voidObj) {
2472 LOG.debug("VpnInterfaceManager: VrfEntries for {} stored into destination {} successfully",
2473 interfaceName, txnDestination);
2475 LOG.debug("VpnInterfaceManager: VrfEntries for {} removed successfully", interfaceName);
2480 public void onFailure(Throwable throwable) {
2482 LOG.error("VpnInterfaceManager: VrfEntries for {} failed to store into destination {}",
2483 interfaceName, txnDestination, throwable);
2485 LOG.error("VpnInterfaceManager: VrfEntries for {} removal failed", interfaceName, throwable);
2486 vpnUtil.unsetScheduledToRemoveForVpnInterface(interfaceName);
2491 private class VpnInterfaceCallBackHandler implements FutureCallback<Void> {
2492 private final String primaryRd;
2493 private final Set<String> prefixListForRefreshFib;
2495 VpnInterfaceCallBackHandler(String primaryRd, Set<String> prefixListForRefreshFib) {
2496 this.primaryRd = primaryRd;
2497 this.prefixListForRefreshFib = prefixListForRefreshFib;
2501 public void onSuccess(Void voidObj) {
2502 prefixListForRefreshFib.forEach(prefix -> {
2503 fibManager.refreshVrfEntry(primaryRd, prefix);
2508 public void onFailure(Throwable throwable) {
2509 LOG.debug("write Tx config operation failed", throwable);