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.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
12 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
13 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
14 import static org.opendaylight.netvirt.vpnmanager.VpnUtil.requireNonNullElse;
16 import com.google.common.base.Optional;
17 import com.google.common.base.Preconditions;
18 import com.google.common.collect.Iterators;
19 import com.google.common.util.concurrent.FutureCallback;
20 import com.google.common.util.concurrent.Futures;
21 import com.google.common.util.concurrent.ListenableFuture;
22 import com.google.common.util.concurrent.MoreExecutors;
23 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
24 import java.math.BigInteger;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.HashSet;
28 import java.util.List;
30 import java.util.Objects;
32 import java.util.concurrent.ConcurrentHashMap;
33 import java.util.concurrent.ConcurrentLinkedQueue;
34 import java.util.concurrent.ExecutionException;
35 import java.util.function.Consumer;
36 import java.util.function.Predicate;
37 import java.util.stream.Collectors;
38 import javax.annotation.Nullable;
39 import javax.annotation.PostConstruct;
40 import javax.annotation.PreDestroy;
41 import javax.inject.Inject;
42 import javax.inject.Singleton;
43 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
44 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
45 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
46 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
47 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
48 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
49 import org.opendaylight.genius.infra.Datastore.Configuration;
50 import org.opendaylight.genius.infra.Datastore.Operational;
51 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
52 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
53 import org.opendaylight.genius.infra.TransactionAdapter;
54 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
55 import org.opendaylight.genius.infra.TypedWriteTransaction;
56 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
57 import org.opendaylight.genius.mdsalutil.NWUtil;
58 import org.opendaylight.genius.mdsalutil.NwConstants;
59 import org.opendaylight.genius.mdsalutil.cache.InstanceIdDataObjectCache;
60 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
61 import org.opendaylight.infrautils.caches.CacheProvider;
62 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
63 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
64 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
65 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
66 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
67 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
68 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
69 import org.opendaylight.netvirt.vpnmanager.api.InterfaceUtils;
70 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
71 import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderHandler;
72 import org.opendaylight.netvirt.vpnmanager.populator.input.L3vpnInput;
73 import org.opendaylight.netvirt.vpnmanager.populator.intfc.VpnPopulator;
74 import org.opendaylight.netvirt.vpnmanager.populator.registry.L3vpnRegistry;
75 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
76 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
77 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
78 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames;
79 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
80 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterfaceBuilder;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.VrfEntryBase;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesBuilder;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.AdjacencyType;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListKey;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntryBuilder;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntryKey;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTarget;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes.NetworkType;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
121 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
122 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
123 import org.slf4j.Logger;
124 import org.slf4j.LoggerFactory;
127 public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInterface, VpnInterfaceManager> {
129 private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
130 private static final short DJC_MAX_RETRIES = 3;
132 private final DataBroker dataBroker;
133 private final ManagedNewTransactionRunner txRunner;
134 private final IBgpManager bgpManager;
135 private final IFibManager fibManager;
136 private final IMdsalApiManager mdsalManager;
137 private final IdManagerService idManager;
138 private final OdlInterfaceRpcService ifaceMgrRpcService;
139 private final VpnFootprintService vpnFootprintService;
140 private final IInterfaceManager interfaceManager;
141 private final IVpnManager vpnManager;
142 private final ArpResponderHandler arpResponderHandler;
143 private final JobCoordinator jobCoordinator;
144 private final VpnUtil vpnUtil;
146 private final ConcurrentHashMap<String, Runnable> vpnIntfMap = new ConcurrentHashMap<>();
148 private final Map<String, ConcurrentLinkedQueue<UnprocessedVpnInterfaceData>> unprocessedVpnInterfaces =
149 new ConcurrentHashMap<>();
151 private final InstanceIdDataObjectCache<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryCache;
154 public VpnInterfaceManager(final DataBroker dataBroker,
155 final IBgpManager bgpManager,
156 final IdManagerService idManager,
157 final IMdsalApiManager mdsalManager,
158 final IFibManager fibManager,
159 final OdlInterfaceRpcService ifaceMgrRpcService,
160 final VpnFootprintService vpnFootprintService,
161 final IInterfaceManager interfaceManager,
162 final IVpnManager vpnManager,
163 final ArpResponderHandler arpResponderHandler,
164 final JobCoordinator jobCoordinator,
165 final CacheProvider cacheProvider,
166 final VpnUtil vpnUtil) {
167 super(VpnInterface.class, VpnInterfaceManager.class);
169 this.dataBroker = dataBroker;
170 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
171 this.bgpManager = bgpManager;
172 this.idManager = idManager;
173 this.mdsalManager = mdsalManager;
174 this.fibManager = fibManager;
175 this.ifaceMgrRpcService = ifaceMgrRpcService;
176 this.vpnFootprintService = vpnFootprintService;
177 this.interfaceManager = interfaceManager;
178 this.vpnManager = vpnManager;
179 this.arpResponderHandler = arpResponderHandler;
180 this.jobCoordinator = jobCoordinator;
181 this.vpnUtil = vpnUtil;
183 vpnInstanceOpDataEntryCache = new InstanceIdDataObjectCache<>(VpnInstanceOpDataEntry.class, dataBroker,
184 LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(
185 VpnInstanceOpData.class).child(VpnInstanceOpDataEntry.class).build(), cacheProvider);
188 public Runnable isNotifyTaskQueued(String intfName) {
189 return vpnIntfMap.remove(intfName);
193 public void start() {
194 LOG.info("{} start", getClass().getSimpleName());
195 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
200 public void close() {
202 vpnInstanceOpDataEntryCache.close();
206 protected InstanceIdentifier<VpnInterface> getWildCardPath() {
207 return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class);
211 protected VpnInterfaceManager getDataTreeChangeListener() {
212 return VpnInterfaceManager.this;
216 public void add(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface) {
217 LOG.trace("Received VpnInterface add event: vpnInterface={}", vpnInterface);
218 LOG.info("add: intfName {} onto vpnName {}", vpnInterface.getName(),
219 VpnHelper.getVpnInterfaceVpnInstanceNamesString(vpnInterface.getVpnInstanceNames()));
220 addVpnInterface(identifier, vpnInterface, null, null);
223 private boolean canHandleNewVpnInterface(final InstanceIdentifier<VpnInterface> identifier,
224 final VpnInterface vpnInterface, String vpnName) {
225 synchronized (vpnName.intern()) {
226 if (isVpnInstanceReady(vpnName)) {
229 addToUnprocessedVpnInterfaces(identifier, vpnInterface, vpnName);
234 // TODO Clean up the exception handling
235 @SuppressWarnings("checkstyle:IllegalCatch")
236 private void addVpnInterface(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface,
237 final @Nullable List<Adjacency> oldAdjs, final @Nullable List<Adjacency> newAdjs) {
238 for (VpnInstanceNames vpnInterfaceVpnInstance : requireNonNullElse(vpnInterface.getVpnInstanceNames(),
239 Collections.<VpnInstanceNames>emptyList())) {
240 String vpnName = vpnInterfaceVpnInstance.getVpnName();
241 addVpnInterfaceCall(identifier, vpnInterface, oldAdjs, newAdjs, vpnName);
245 private void addVpnInterfaceCall(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface,
246 final List<Adjacency> oldAdjs, final List<Adjacency> newAdjs, String vpnName) {
247 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class);
248 final String interfaceName = key.getName();
250 if (!canHandleNewVpnInterface(identifier, vpnInterface, vpnName)) {
251 LOG.error("add: VpnInstance {} for vpnInterface {} not ready, holding on ",
252 vpnName, vpnInterface.getName());
255 InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier = VpnUtil
256 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
257 List<Adjacency> copyOldAdjs = null;
258 if (oldAdjs != null) {
259 copyOldAdjs = new ArrayList<>();
260 copyOldAdjs.addAll(oldAdjs);
262 List<Adjacency> copyNewAdjs = null;
263 if (newAdjs != null) {
264 copyNewAdjs = new ArrayList<>();
265 copyNewAdjs.addAll(newAdjs);
267 addVpnInterfaceToVpn(vpnInterfaceOpIdentifier, vpnInterface, copyOldAdjs, copyNewAdjs, identifier, vpnName);
270 private void addVpnInterfaceToVpn(final InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier,
271 final VpnInterface vpnInterface, final @Nullable List<Adjacency> oldAdjs,
272 final @Nullable List<Adjacency> newAdjs,
273 final InstanceIdentifier<VpnInterface> identifier, String vpnName) {
274 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class);
275 final String interfaceName = key.getName();
276 String primaryRd = vpnUtil.getPrimaryRd(vpnName);
277 if (!vpnUtil.isVpnPendingDelete(primaryRd)) {
278 Interface interfaceState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker, interfaceName);
279 boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(vpnName);
280 if (interfaceState != null) {
282 final BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(interfaceState);
283 final int ifIndex = interfaceState.getIfIndex();
284 jobCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName, () -> {
285 // TODO Deal with sequencing — the config tx must only submitted if the oper tx goes in
286 // (the inventory tx goes in last)
287 List<ListenableFuture<Void>> futures = new ArrayList<>();
288 //set of prefix used, as entry in prefix-to-interface datastore
289 // is prerequisite for refresh Fib to avoid race condition leading to
290 // missing remote next hop in bucket actions on bgp-vpn delete
291 Set<String> prefixListForRefreshFib = new HashSet<>();
292 ListenableFuture<Void> confFuture =
293 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
294 confTx -> futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
295 operTx -> futures.add(
296 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, invTx -> {
298 "addVpnInterface: VPN Interface add event - intfName {} vpnName {}"
300 vpnInterface.getName(), vpnName, vpnInterface.getDpnId());
301 processVpnInterfaceUp(dpnId, vpnInterface, primaryRd, ifIndex, false,
302 confTx, operTx, invTx, interfaceState, vpnName,
303 prefixListForRefreshFib);
304 if (oldAdjs != null && !oldAdjs.equals(newAdjs)) {
305 LOG.info("addVpnInterface: Adjacency changed upon VPNInterface {}"
306 + " Update for swapping VPN {} case.", interfaceName, vpnName);
307 if (newAdjs != null) {
308 for (Adjacency adj : newAdjs) {
309 if (oldAdjs.contains(adj)) {
312 if (!isBgpVpnInternetVpn
313 || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
314 addNewAdjToVpnInterface(vpnInterfaceOpIdentifier,
315 primaryRd, adj, dpnId, operTx, confTx, invTx,
316 prefixListForRefreshFib);
321 for (Adjacency adj : oldAdjs) {
322 if (!isBgpVpnInternetVpn
323 || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
324 delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId,
330 Futures.addCallback(confFuture,
331 new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
332 MoreExecutors.directExecutor());
333 futures.add(confFuture);
334 Futures.addCallback(confFuture, new PostVpnInterfaceWorker(interfaceName, true, "Config"),
335 MoreExecutors.directExecutor());
336 LOG.info("addVpnInterface: Addition of interface {} in VPN {} on dpn {}"
337 + " processed successfully", interfaceName, vpnName, dpnId);
340 } catch (NumberFormatException | IllegalStateException e) {
341 LOG.error("addVpnInterface: Unable to retrieve dpnId from interface operational data store for "
342 + "interface {}. Interface addition on vpn {} failed", interfaceName,
346 } else if (Boolean.TRUE.equals(vpnInterface.isRouterInterface())) {
347 jobCoordinator.enqueueJob("VPNINTERFACE-" + vpnInterface.getName(),
349 ListenableFuture<Void> future =
350 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
351 createFibEntryForRouterInterface(primaryRd, vpnInterface, interfaceName,
353 LOG.info("addVpnInterface: Router interface {} for vpn {} on dpn {}", interfaceName,
354 vpnName, vpnInterface.getDpnId());
356 ListenableFutures.addErrorLogging(future, LOG,
357 "Error creating FIB entry for interface {} on VPN {}", vpnInterface.getName(), vpnName);
358 return Collections.singletonList(future);
361 LOG.info("addVpnInterface: Handling addition of VPN interface {} on vpn {} skipped as interfaceState"
362 + " is not available", interfaceName, vpnName);
365 LOG.error("addVpnInterface: Handling addition of VPN interface {} on vpn {} dpn {} skipped"
366 + " as vpn is pending delete", interfaceName, vpnName,
367 vpnInterface.getDpnId());
371 // "Unconditional wait" and "Wait not in loop" wrt the VpnNotifyTask below - suppressing the FB violation -
372 // see comments below.
373 @SuppressFBWarnings({"UW_UNCOND_WAIT", "WA_NOT_IN_LOOP"})
374 protected void processVpnInterfaceUp(final BigInteger dpId, VpnInterface vpnInterface, final String primaryRd,
375 final int lportTag, boolean isInterfaceUp,
376 TypedWriteTransaction<Configuration> writeConfigTxn,
377 TypedWriteTransaction<Operational> writeOperTxn,
378 TypedReadWriteTransaction<Configuration> writeInvTxn,
379 Interface interfaceState, final String vpnName,
380 Set<String> prefixListForRefreshFib) throws ExecutionException, InterruptedException {
381 final String interfaceName = vpnInterface.getName();
382 Optional<VpnInterfaceOpDataEntry> optOpVpnInterface = vpnUtil.getVpnInterfaceOpDataEntry(interfaceName,
384 VpnInterfaceOpDataEntry opVpnInterface = optOpVpnInterface.isPresent() ? optOpVpnInterface.get() : null;
385 boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(vpnName);
386 if (!isInterfaceUp) {
387 LOG.info("processVpnInterfaceUp: Binding vpn service to interface {} onto dpn {} for vpn {}",
388 interfaceName, dpId, vpnName);
389 long vpnId = vpnUtil.getVpnId(vpnName);
390 if (vpnId == VpnConstants.INVALID_ID) {
391 LOG.warn("processVpnInterfaceUp: VpnInstance to VPNId mapping not available for VpnName {}"
392 + " processing vpninterface {} on dpn {}, bailing out now.", vpnName, interfaceName,
397 boolean waitForVpnInterfaceOpRemoval = false;
398 if (opVpnInterface != null) {
399 String opVpnName = opVpnInterface.getVpnInstanceName();
400 String primaryInterfaceIp = null;
401 if (Objects.equals(opVpnName, vpnName)) {
402 // Please check if the primary VRF Entry does not exist for VPNInterface
403 // If so, we have to process ADD, as this might be a DPN Restart with Remove and Add triggered
405 // However, if the primary VRF Entry for this VPNInterface exists, please continue bailing out !
406 List<Adjacency> adjs = vpnUtil.getAdjacenciesForVpnInterfaceFromConfig(interfaceName);
408 LOG.error("processVpnInterfaceUp: VPN Interface {} on dpn {} for vpn {} failed as adjacencies"
409 + " for this vpn interface could not be obtained", interfaceName, dpId,
413 for (Adjacency adj : adjs) {
414 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
415 primaryInterfaceIp = adj.getIpAddress();
419 if (primaryInterfaceIp == null) {
420 LOG.error("processVpnInterfaceUp: VPN Interface {} addition on dpn {} for vpn {} failed"
421 + " as primary adjacency for this vpn interface could not be obtained", interfaceName,
425 // Get the rd of the vpn instance
426 VrfEntry vrf = vpnUtil.getVrfEntry(primaryRd, primaryInterfaceIp);
428 LOG.error("processVpnInterfaceUp: VPN Interface {} on dpn {} for vpn {} already provisioned ,"
429 + " bailing out from here.", interfaceName, dpId, vpnName);
432 waitForVpnInterfaceOpRemoval = true;
434 LOG.error("processVpnInterfaceUp: vpn interface {} to go to configured vpn {} on dpn {},"
435 + " but in operational vpn {}", interfaceName, vpnName, dpId, opVpnName);
438 if (!waitForVpnInterfaceOpRemoval) {
439 // Add the VPNInterface and quit
440 vpnFootprintService.updateVpnToDpnMapping(dpId, vpnName, primaryRd, interfaceName,
441 null/*ipAddressSourceValuePair*/,
443 processVpnInterfaceAdjacencies(dpId, lportTag, vpnName, primaryRd, interfaceName,
444 vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState, prefixListForRefreshFib);
445 if (!isBgpVpnInternetVpn) {
446 vpnUtil.bindService(vpnName, interfaceName, false /*isTunnelInterface*/);
448 LOG.info("processVpnInterfaceUp: Plumbed vpn interface {} onto dpn {} for vpn {}", interfaceName,
450 if (interfaceManager.isExternalInterface(interfaceName)) {
451 processExternalVpnInterface(interfaceName, vpnName, dpId, lportTag,
452 NwConstants.ADD_FLOW);
457 // FIB didn't get a chance yet to clean up this VPNInterface
458 // Let us give it a chance here !
459 LOG.info("processVpnInterfaceUp: Trying to add VPN Interface {} on dpn {} for vpn {},"
460 + " but waiting for FIB to clean up! ", interfaceName, dpId, vpnName);
462 Runnable notifyTask = new VpnNotifyTask();
463 synchronized (notifyTask) {
464 // Per FB's "Unconditional wait" violation, the code should really verify that the condition it
465 // intends to wait for is not already satisfied before calling wait. However the VpnNotifyTask is
466 // published here while holding the lock on it so this path will hit the wait before notify can be
468 vpnIntfMap.put(interfaceName, notifyTask);
470 notifyTask.wait(VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS);
471 } catch (InterruptedException e) {
476 vpnIntfMap.remove(interfaceName);
479 if (opVpnInterface != null) {
480 LOG.warn("processVpnInterfaceUp: VPN Interface {} removal on dpn {} for vpn {}"
481 + " by FIB did not complete on time," + " bailing addition ...", interfaceName,
483 vpnUtil.unsetScheduledToRemoveForVpnInterface(interfaceName);
486 // VPNInterface got removed, proceed with Add
487 LOG.info("processVpnInterfaceUp: Continuing to plumb vpn interface {} onto dpn {} for vpn {}",
488 interfaceName, dpId, vpnName);
489 vpnFootprintService.updateVpnToDpnMapping(dpId, vpnName, primaryRd, interfaceName,
490 null/*ipAddressSourceValuePair*/,
492 processVpnInterfaceAdjacencies(dpId, lportTag, vpnName, primaryRd, interfaceName,
493 vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState, prefixListForRefreshFib);
494 if (!isBgpVpnInternetVpn) {
495 vpnUtil.bindService(vpnName, interfaceName, false/*isTunnelInterface*/);
497 LOG.info("processVpnInterfaceUp: Plumbed vpn interface {} onto dpn {} for vpn {} after waiting for"
498 + " FIB to clean up", interfaceName, dpId, vpnName);
499 if (interfaceManager.isExternalInterface(interfaceName)) {
500 processExternalVpnInterface(interfaceName, vpnName, dpId,
501 lportTag, NwConstants.ADD_FLOW);
505 // Interface is retained in the DPN, but its Link Up.
506 // Advertise prefixes again for this interface to BGP
507 InstanceIdentifier<VpnInterface> identifier =
508 VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName());
509 InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier =
510 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
511 advertiseAdjacenciesForVpnToBgp(primaryRd, dpId, vpnInterfaceOpIdentifier, vpnName, interfaceName);
512 // Perform similar operation as interface add event for extraroutes.
513 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
514 Optional<Adjacencies> optAdjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
515 LogicalDatastoreType.CONFIGURATION, path);
516 if (!optAdjacencies.isPresent()) {
517 LOG.trace("No config adjacencies present for vpninterface {}", vpnInterface);
520 List<Adjacency> adjacencies = requireNonNullElse(optAdjacencies.get().getAdjacency(), emptyList());
521 for (Adjacency adjacency : adjacencies) {
522 if (adjacency.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
525 // if BGPVPN Internet, filter only IPv6 Adjacencies
526 if (isBgpVpnInternetVpn && !vpnUtil.isAdjacencyEligibleToVpnInternet(adjacency)) {
529 addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adjacency,
530 dpId, writeOperTxn, writeConfigTxn, writeInvTxn, prefixListForRefreshFib);
532 } catch (ReadFailedException e) {
533 LOG.error("processVpnInterfaceUp: Failed to read data store for interface {} vpn {} rd {} dpn {}",
534 interfaceName, vpnName, primaryRd, dpId);
539 private void processExternalVpnInterface(String interfaceName, String vpnName, BigInteger dpId,
540 int lportTag, int addOrRemove) {
543 // vpn instance of ext-net interface is the network-id
544 extNetworkId = new Uuid(vpnName);
545 } catch (IllegalArgumentException e) {
546 LOG.error("processExternalVpnInterface: VPN instance {} is not Uuid. Processing external vpn interface {}"
547 + " on dpn {} failed", vpnName, interfaceName, dpId);
551 List<Uuid> routerIds = vpnUtil.getExternalNetworkRouterIds(extNetworkId);
552 if (routerIds == null || routerIds.isEmpty()) {
553 LOG.info("processExternalVpnInterface: No router is associated with {}."
554 + " Bailing out of processing external vpn interface {} on dpn {} for vpn {}",
555 extNetworkId.getValue(), interfaceName, dpId, vpnName);
559 LOG.info("processExternalVpnInterface: Router-ids {} associated with exernal vpn-interface {} on dpn {}"
560 + " for vpn {}", routerIds, interfaceName, dpId, vpnName);
561 for (Uuid routerId : routerIds) {
562 String routerName = routerId.getValue();
563 BigInteger primarySwitch = vpnUtil.getPrimarySwitchForRouter(routerName);
564 if (Objects.equals(primarySwitch, dpId)) {
565 Routers router = vpnUtil.getExternalRouter(routerName);
566 if (router != null) {
567 if (addOrRemove == NwConstants.ADD_FLOW) {
568 vpnManager.addArpResponderFlowsToExternalNetworkIps(routerName,
569 VpnUtil.getIpsListFromExternalIps(router.getExternalIps()), router.getExtGwMacAddress(),
570 dpId, interfaceName, lportTag);
572 vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerName,
573 VpnUtil.getIpsListFromExternalIps(router.getExternalIps()),
574 dpId, interfaceName, lportTag);
577 LOG.error("processExternalVpnInterface: No external-router found for router-id {}. Bailing out of"
578 + " processing external vpn-interface {} on dpn {} for vpn {}", routerName,
579 interfaceName, dpId, vpnName);
585 // TODO Clean up the exception handling
586 @SuppressWarnings("checkstyle:IllegalCatch")
587 private void advertiseAdjacenciesForVpnToBgp(final String rd, BigInteger dpnId,
588 final InstanceIdentifier<VpnInterfaceOpDataEntry> identifier,
589 String vpnName, String interfaceName) {
591 LOG.error("advertiseAdjacenciesForVpnFromBgp: Unable to recover rd for interface {} on dpn {} in vpn {}",
592 interfaceName, dpnId, vpnName);
595 if (rd.equals(vpnName)) {
596 LOG.info("advertiseAdjacenciesForVpnFromBgp: Ignoring BGP advertisement for interface {} on dpn {}"
597 + " as it is in internal vpn{} with rd {}", interfaceName, dpnId, vpnName, rd);
601 LOG.info("advertiseAdjacenciesForVpnToBgp: Advertising interface {} on dpn {} in vpn {} with rd {} ",
602 interfaceName, dpnId, vpnName, rd);
604 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
605 if (nextHopIp == null) {
606 LOG.error("advertiseAdjacenciesForVpnToBgp: NextHop for interface {} on dpn {} is null,"
607 + " returning from advertising route with rd {} vpn {} to bgp", interfaceName, dpnId,
614 InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
615 Optional<AdjacenciesOp> adjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
616 LogicalDatastoreType.OPERATIONAL, path);
617 if (adjacencies.isPresent()) {
618 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
619 if (nextHops != null && !nextHops.isEmpty()) {
620 LOG.debug("advertiseAdjacenciesForVpnToBgp: NextHops are {} for interface {} on dpn {} for vpn {}"
621 + " rd {}", nextHops, interfaceName, dpnId, vpnName, rd);
622 VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(rd);
623 long l3vni = vpnInstanceOpData.getL3vni();
624 VrfEntry.EncapType encapType = VpnUtil.isL3VpnOverVxLan(l3vni)
625 ? VrfEntry.EncapType.Vxlan : VrfEntry.EncapType.Mplsgre;
626 for (Adjacency nextHop : nextHops) {
627 if (nextHop.getAdjacencyType() == AdjacencyType.ExtraRoute) {
630 String gatewayMac = null;
632 if (VpnUtil.isL3VpnOverVxLan(l3vni)) {
633 final VpnPortipToPort gwPort = vpnUtil.getNeutronPortFromVpnPortFixedIp(
634 vpnInstanceOpData.getVpnInstanceName(), nextHop.getIpAddress());
635 gatewayMac = arpResponderHandler.getGatewayMacAddressForInterface(gwPort, interfaceName)
638 label = nextHop.getLabel();
641 LOG.info("VPN ADVERTISE: advertiseAdjacenciesForVpnToBgp: Adding Fib Entry rd {} prefix {}"
642 + " nexthop {} label {}", rd, nextHop.getIpAddress(), nextHopIp, label);
643 bgpManager.advertisePrefix(rd, nextHop.getMacAddress(), nextHop.getIpAddress(), nextHopIp,
644 encapType, (int)label, l3vni, 0 /*l2vni*/,
646 LOG.info("VPN ADVERTISE: advertiseAdjacenciesForVpnToBgp: Added Fib Entry rd {} prefix {}"
647 + " nexthop {} label {} for interface {} on dpn {} for vpn {}", rd,
648 nextHop.getIpAddress(), nextHopIp, label, interfaceName, dpnId, vpnName);
649 } catch (Exception e) {
650 LOG.error("advertiseAdjacenciesForVpnToBgp: Failed to advertise prefix {} in vpn {}"
651 + " with rd {} for interface {} on dpn {}", nextHop.getIpAddress(), vpnName, rd,
652 interfaceName, dpnId, e);
657 } catch (ReadFailedException e) {
658 LOG.error("advertiseAdjacenciesForVpnToBgp: Failed to read data store for interface {} dpn {} nexthop {}"
659 + "vpn {} rd {}", interfaceName, dpnId, nextHopIp, vpnName, rd);
663 // TODO Clean up the exception handling
664 @SuppressWarnings("checkstyle:IllegalCatch")
665 private void withdrawAdjacenciesForVpnFromBgp(final InstanceIdentifier<VpnInterfaceOpDataEntry> identifier,
666 String vpnName, String interfaceName, TypedWriteTransaction<Configuration> writeConfigTxn,
667 TypedWriteTransaction<Operational> writeOperTx) {
669 InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
670 String rd = vpnUtil.getVpnRd(interfaceName);
672 LOG.error("withdrawAdjacenciesForVpnFromBgp: Unable to recover rd for interface {} in vpn {}",
673 interfaceName, vpnName);
676 if (rd.equals(vpnName)) {
678 "withdrawAdjacenciesForVpnFromBgp: Ignoring BGP withdrawal for interface {} as it is in "
679 + "internal vpn{} with rd {}", interfaceName, vpnName, rd);
683 LOG.info("withdrawAdjacenciesForVpnFromBgp: For interface {} in vpn {} with rd {}", interfaceName,
685 Optional<AdjacenciesOp> adjacencies = Optional.absent();
687 adjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
689 } catch (ReadFailedException e) {
690 LOG.error("withdrawAdjacenciesForVpnFromBgp: Failed to read data store for interface {} vpn {}",
691 interfaceName, vpnName);
693 if (adjacencies.isPresent()) {
694 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
696 if (nextHops != null && !nextHops.isEmpty()) {
697 LOG.trace("withdrawAdjacenciesForVpnFromBgp: NextHops are {} for interface {} in vpn {} rd {}",
698 nextHops, interfaceName, vpnName, rd);
699 for (Adjacency nextHop : nextHops) {
701 if (nextHop.getAdjacencyType() != AdjacencyType.ExtraRoute) {
702 LOG.info("VPN WITHDRAW: withdrawAdjacenciesForVpnFromBgp: Removing Fib Entry rd {}"
703 + " prefix {} for interface {} in vpn {}", rd, nextHop.getIpAddress(),
704 interfaceName, vpnName);
705 bgpManager.withdrawPrefix(rd, nextHop.getIpAddress());
706 LOG.info("VPN WITHDRAW: withdrawAdjacenciesForVpnFromBgp: Removed Fib Entry rd {}"
707 + " prefix {} for interface {} in vpn {}", rd, nextHop.getIpAddress(),
708 interfaceName, vpnName);
710 // Perform similar operation as interface delete event for extraroutes.
711 String allocatedRd = nextHop.getVrfId();
712 for (String nh : requireNonNullElse(nextHop.getNextHopIpList(),
713 Collections.<String>emptyList())) {
714 deleteExtraRouteFromCurrentAndImportingVpns(
715 vpnName, nextHop.getIpAddress(), nh, allocatedRd, interfaceName, writeConfigTxn,
719 } catch (Exception e) {
720 LOG.error("withdrawAdjacenciesForVpnFromBgp: Failed to withdraw prefix {} in vpn {} with rd {}"
721 + " for interface {} ", nextHop.getIpAddress(), vpnName, rd, interfaceName, e);
728 @SuppressWarnings("checkstyle:IllegalCatch")
729 protected void processVpnInterfaceAdjacencies(BigInteger dpnId, final int lportTag, String vpnName,
730 String primaryRd, String interfaceName, final long vpnId,
731 TypedWriteTransaction<Configuration> writeConfigTxn,
732 TypedWriteTransaction<Operational> writeOperTxn,
733 TypedReadWriteTransaction<Configuration> writeInvTxn,
734 Interface interfaceState, Set<String> prefixListForRefreshFib)
735 throws ExecutionException, InterruptedException {
736 InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
738 Optional<VpnInterface> vpnInteface = Optional.absent();
740 vpnInteface = SingleTransactionDataBroker.syncReadOptional(dataBroker,
741 LogicalDatastoreType.CONFIGURATION, identifier);
742 } catch (ReadFailedException e) {
743 LOG.error("processVpnInterfaceAdjacencies: Failed to read data store for interface {} vpn {} rd {}"
744 + "dpn {}", interfaceName, vpnName, primaryRd, dpnId);
746 Uuid intfnetworkUuid = null;
747 NetworkType networkType = null;
748 Long segmentationId = Long.valueOf(-1);
749 Adjacencies adjacencies = null;
750 if (vpnInteface.isPresent()) {
751 intfnetworkUuid = vpnInteface.get().getNetworkId();
752 networkType = vpnInteface.get().getNetworkType();
753 segmentationId = vpnInteface.get().getSegmentationId();
754 adjacencies = vpnInteface.get().augmentation(Adjacencies.class);
755 if (adjacencies == null) {
756 addVpnInterfaceToOperational(vpnName, interfaceName, dpnId, null/*adjacencies*/, lportTag,
757 null/*gwMac*/, writeOperTxn);
761 // Get the rd of the vpn instance
762 String nextHopIp = null;
764 nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
765 } catch (Exception e) {
766 LOG.error("processVpnInterfaceAdjacencies: Unable to retrieve endpoint ip address for "
767 + "dpnId {} for vpnInterface {} vpnName {}", dpnId, interfaceName, vpnName);
769 List<String> nhList = new ArrayList<>();
770 if (nextHopIp != null) {
771 nhList.add(nextHopIp);
772 LOG.debug("processVpnInterfaceAdjacencies: NextHop for interface {} on dpn {} in vpn {} is {}",
773 interfaceName, dpnId, vpnName, nhList);
775 Optional<String> gwMac = Optional.absent();
776 String vpnInterfaceSubnetGwMacAddress = null;
777 VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(primaryRd);
778 Long l3vni = vpnInstanceOpData.getL3vni();
779 boolean isL3VpnOverVxLan = VpnUtil.isL3VpnOverVxLan(l3vni);
780 VrfEntry.EncapType encapType = isL3VpnOverVxLan ? VrfEntry.EncapType.Vxlan : VrfEntry.EncapType.Mplsgre;
781 VpnPopulator registeredPopulator = L3vpnRegistry.getRegisteredPopulator(encapType);
782 List<Adjacency> nextHops = (adjacencies != null) ? adjacencies.getAdjacency() : emptyList();
783 List<Adjacency> value = new ArrayList<>();
784 for (Adjacency nextHop : nextHops) {
785 String rd = primaryRd;
786 String nexthopIpValue = nextHop.getIpAddress().split("/")[0];
787 if (vpnInstanceOpData.getBgpvpnType() == VpnInstanceOpDataEntry.BgpvpnType.BGPVPNInternet
788 && NWUtil.isIpv4Address(nexthopIpValue)) {
789 String prefix = nextHop.getIpAddress() == null ? "null" :
790 VpnUtil.getIpPrefix(nextHop.getIpAddress());
791 LOG.debug("processVpnInterfaceAdjacencies: UnsupportedOperation : Not Adding prefix {} to interface {}"
792 + " as InternetVpn has an IPV4 address {}", prefix, interfaceName, vpnName);
795 if (nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
796 String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
797 Prefixes.PrefixCue prefixCue = nextHop.isPhysNetworkFunc()
798 ? Prefixes.PrefixCue.PhysNetFunc : Prefixes.PrefixCue.None;
799 LOG.debug("processVpnInterfaceAdjacencies: Adding prefix {} to interface {} with nextHops {} on dpn {}"
800 + " for vpn {}", prefix, interfaceName, nhList, dpnId, vpnName);
802 Prefixes prefixes = (intfnetworkUuid != null)
803 ? VpnUtil.getPrefixToInterface(dpnId, interfaceName, prefix, intfnetworkUuid ,networkType,
804 segmentationId, prefixCue) :
805 VpnUtil.getPrefixToInterface(dpnId, interfaceName, prefix, prefixCue);
806 writeOperTxn.merge(VpnUtil.getPrefixToInterfaceIdentifier(
807 vpnUtil.getVpnId(vpnName), prefix), prefixes, true);
808 final Uuid subnetId = nextHop.getSubnetId();
810 String gatewayIp = nextHop.getSubnetGatewayIp();
811 if (gatewayIp == null) {
812 Optional<String> gatewayIpOptional = vpnUtil.getVpnSubnetGatewayIp(subnetId);
813 if (gatewayIpOptional.isPresent()) {
814 gatewayIp = gatewayIpOptional.get();
818 if (gatewayIp != null) {
819 gwMac = getMacAddressForSubnetIp(vpnName, interfaceName, gatewayIp);
820 if (gwMac.isPresent()) {
821 // A valid mac-address is available for this subnet-gateway-ip
822 // Use this for programming ARP_RESPONDER table here. And save this
823 // info into vpnInterface operational, so it can used in VrfEntryProcessor
824 // to populate L3_GW_MAC_TABLE there.
825 arpResponderHandler.addArpResponderFlow(dpnId, lportTag, interfaceName,
826 gatewayIp, gwMac.get());
827 vpnInterfaceSubnetGwMacAddress = gwMac.get();
829 // A valid mac-address is not available for this subnet-gateway-ip
830 // Use the connected-mac-address to configure ARP_RESPONDER Table.
831 // Save this connected-mac-address as gateway-mac-address for the
832 // VrfEntryProcessor to use this later to populate the L3_GW_MAC_TABLE.
833 gwMac = InterfaceUtils.getMacAddressFromInterfaceState(interfaceState);
834 if (gwMac.isPresent()) {
835 vpnUtil.setupGwMacIfExternalVpn(dpnId, interfaceName, vpnId, writeInvTxn,
836 NwConstants.ADD_FLOW, gwMac.get());
837 arpResponderHandler.addArpResponderFlow(dpnId, lportTag, interfaceName,
838 gatewayIp, gwMac.get());
840 LOG.error("processVpnInterfaceAdjacencies: Gateway MAC for subnet ID {} could not be "
841 + "obtained, cannot create ARP responder flow for interface name {}, vpnName {}, "
843 subnetId, interfaceName, vpnName, gatewayIp);
847 LOG.warn("processVpnInterfaceAdjacencies: Gateway IP for subnet ID {} could not be obtained, "
848 + "cannot create ARP responder flow for interface name {}, vpnName {}",
849 subnetId, interfaceName, vpnName);
850 gwMac = InterfaceUtils.getMacAddressFromInterfaceState(interfaceState);
852 LOG.info("processVpnInterfaceAdjacencies: Added prefix {} to interface {} with nextHops {} on dpn {}"
853 + " for vpn {}", prefix, interfaceName, nhList, dpnId, vpnName);
855 //Extra route adjacency
856 String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
857 String vpnPrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
858 synchronized (vpnPrefixKey.intern()) {
859 java.util.Optional<String> rdToAllocate = vpnUtil
860 .allocateRdForExtraRouteAndUpdateUsedRdsMap(vpnId, null, prefix, vpnName,
861 nextHop.getNextHopIpList().get(0), dpnId);
862 if (rdToAllocate.isPresent()) {
863 rd = rdToAllocate.get();
864 LOG.info("processVpnInterfaceAdjacencies: The rd {} is allocated for the extraroute {}",
867 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 = nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency ? RouteOrigin.LOCAL
879 : RouteOrigin.STATIC;
880 L3vpnInput input = new L3vpnInput().setNextHop(nextHop).setRd(rd).setVpnName(vpnName)
881 .setInterfaceName(interfaceName).setNextHopIp(nextHopIp).setPrimaryRd(primaryRd)
882 .setSubnetGatewayMacAddress(vpnInterfaceSubnetGwMacAddress).setRouteOrigin(origin);
883 Adjacency operationalAdjacency = null;
885 operationalAdjacency = registeredPopulator.createOperationalAdjacency(input);
886 } catch (NullPointerException e) {
887 LOG.error("processVpnInterfaceAdjacencies: failed to create operational adjacency: input: {}, {}",
888 input, e.getMessage());
891 if (nextHop.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
892 vpnManager.addExtraRoute(vpnName, nextHop.getIpAddress(), nextHop.getNextHopIpList().get(0), rd,
893 vpnName, l3vni, origin, interfaceName, operationalAdjacency, encapType, prefixListForRefreshFib,
896 value.add(operationalAdjacency);
899 AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(value);
900 addVpnInterfaceToOperational(vpnName, interfaceName, dpnId, aug, lportTag,
901 gwMac.isPresent() ? gwMac.get() : null, writeOperTxn);
903 L3vpnInput input = new L3vpnInput().setNextHopIp(nextHopIp).setL3vni(l3vni).setPrimaryRd(primaryRd)
904 .setGatewayMac(gwMac.orNull()).setInterfaceName(interfaceName)
905 .setVpnName(vpnName).setDpnId(dpnId).setEncapType(encapType);
907 for (Adjacency nextHop : aug.getAdjacency()) {
908 // Adjacencies other than primary Adjacencies are handled in the addExtraRoute call above.
909 if (nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
910 RouteOrigin origin = nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency ? RouteOrigin.LOCAL
911 : RouteOrigin.STATIC;
912 input.setNextHop(nextHop).setRd(nextHop.getVrfId()).setRouteOrigin(origin);
913 registeredPopulator.populateFib(input, writeConfigTxn);
918 private void addVpnInterfaceToOperational(String vpnName, String interfaceName, BigInteger dpnId, AdjacenciesOp aug,
919 long lportTag, String gwMac,
920 TypedWriteTransaction<Operational> writeOperTxn) {
921 VpnInterfaceOpDataEntry opInterface =
922 VpnUtil.getVpnInterfaceOpDataEntry(interfaceName, vpnName, aug, dpnId, lportTag, gwMac);
923 InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId = VpnUtil
924 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
925 writeOperTxn.put(interfaceId, opInterface, CREATE_MISSING_PARENTS);
926 LOG.info("addVpnInterfaceToOperational: Added VPN Interface {} on dpn {} vpn {} to operational datastore",
927 interfaceName, dpnId, vpnName);
930 // TODO Clean up the exception handling
931 @SuppressWarnings("checkstyle:IllegalCatch")
932 public void updateVpnInterfaceOnTepAdd(VpnInterfaceOpDataEntry vpnInterface,
933 StateTunnelList stateTunnelList,
934 TypedWriteTransaction<Configuration> writeConfigTxn,
935 TypedWriteTransaction<Operational> writeOperTxn) {
937 String srcTepIp = stateTunnelList.getSrcInfo().getTepIp().stringValue();
938 BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
939 AdjacenciesOp adjacencies = vpnInterface.augmentation(AdjacenciesOp.class);
940 List<Adjacency> adjList =
941 adjacencies != null && adjacencies.getAdjacency() != null ? adjacencies.getAdjacency() : emptyList();
942 if (adjList.isEmpty()) {
943 LOG.trace("updateVpnInterfaceOnTepAdd: Adjacencies are empty for vpnInterface {} on dpn {}",
944 vpnInterface, srcDpnId);
947 String prefix = null;
949 List<Adjacency> value = new ArrayList<>();
950 boolean isNextHopAddReqd = false;
951 String vpnName = vpnInterface.getVpnInstanceName();
952 long vpnId = vpnUtil.getVpnId(vpnName);
953 String primaryRd = vpnUtil.getPrimaryRd(vpnName);
954 LOG.info("updateVpnInterfaceOnTepAdd: AdjacencyList for interface {} on dpn {} vpn {} is {}",
955 vpnInterface.getName(), vpnInterface.getDpnId(),
956 vpnInterface.getVpnInstanceName(), adjList);
957 for (Adjacency adj : adjList) {
958 String rd = adj.getVrfId();
959 rd = rd != null ? rd : vpnName;
960 prefix = adj.getIpAddress();
961 label = adj.getLabel();
962 List<String> nhList = Collections.singletonList(srcTepIp);
963 List<String> nextHopList = adj.getNextHopIpList();
964 // If TEP is added , update the nexthop of primary adjacency.
965 // Secondary adj nexthop is already pointing to primary adj IP address.
966 if (nextHopList == null || nextHopList.isEmpty()) {
967 isNextHopAddReqd = true;
970 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
971 value.add(new AdjacencyBuilder(adj).setNextHopIpList(nhList).build());
973 Optional<VrfEntry> vrfEntryOptional = FibHelper.getVrfEntry(dataBroker, primaryRd, prefix);
974 if (!vrfEntryOptional.isPresent()) {
977 nhList = FibHelper.getNextHopListFromRoutePaths(vrfEntryOptional.get());
978 if (!nhList.contains(srcTepIp)) {
979 nhList.add(srcTepIp);
980 isNextHopAddReqd = true;
985 if (isNextHopAddReqd) {
986 updateLabelMapper(label, nhList);
987 LOG.info("updateVpnInterfaceOnTepAdd: Updated label mapper : label {} dpn {} prefix {} nexthoplist {}"
988 + " vpn {} vpnid {} rd {} interface {}", label, srcDpnId , prefix, nhList,
989 vpnInterface.getVpnInstanceName(), vpnId, rd, vpnInterface.getName());
990 // Update the VRF entry with nextHop
991 fibManager.updateRoutePathForFibEntry(primaryRd, prefix, srcTepIp,
992 label, true, TransactionAdapter.toWriteTransaction(writeConfigTxn));
994 //Get the list of VPN's importing this route(prefix) .
995 // Then update the VRF entry with nhList
996 List<VpnInstanceOpDataEntry> vpnsToImportRoute = vpnUtil.getVpnsImportingMyRoute(vpnName);
997 for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
998 String vpnRd = vpn.getVrfId();
1000 fibManager.updateRoutePathForFibEntry(vpnRd, prefix,
1001 srcTepIp, label, true, TransactionAdapter.toWriteTransaction(writeConfigTxn));
1002 LOG.info("updateVpnInterfaceOnTepAdd: Exported route with rd {} prefix {} nhList {} label {}"
1003 + " interface {} dpn {} from vpn {} to VPN {} vpnRd {}", rd, prefix, nhList, label,
1004 vpnInterface.getName(), srcDpnId, vpnName,
1005 vpn.getVpnInstanceName(), vpnRd);
1008 // Advertise the prefix to BGP only for external vpn
1009 // since there is a nexthop change.
1011 if (!rd.equalsIgnoreCase(vpnName)) {
1012 bgpManager.advertisePrefix(rd, null /*macAddress*/, prefix, nhList,
1013 VrfEntry.EncapType.Mplsgre, (int)label, 0 /*evi*/, 0 /*l2vni*/,
1014 null /*gatewayMacAddress*/);
1016 LOG.info("updateVpnInterfaceOnTepAdd: Advertised rd {} prefix {} nhList {} label {}"
1017 + " for interface {} on dpn {} vpn {}", rd, prefix, nhList, label, vpnInterface.getName(),
1019 } catch (Exception ex) {
1020 LOG.error("updateVpnInterfaceOnTepAdd: Exception when advertising prefix {} nh {} label {}"
1021 + " on rd {} for interface {} on dpn {} vpn {}", prefix, nhList, label, rd,
1022 vpnInterface.getName(), srcDpnId, vpnName, ex);
1026 AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(value);
1027 VpnInterfaceOpDataEntry opInterface = new VpnInterfaceOpDataEntryBuilder(vpnInterface)
1028 .withKey(new VpnInterfaceOpDataEntryKey(vpnInterface.getName(), vpnName))
1029 .addAugmentation(AdjacenciesOp.class, aug).build();
1030 InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId =
1031 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterface.getName(), vpnName);
1032 writeOperTxn.put(interfaceId, opInterface, CREATE_MISSING_PARENTS);
1033 LOG.info("updateVpnInterfaceOnTepAdd: interface {} updated successully on tep add on dpn {} vpn {}",
1034 vpnInterface.getName(), srcDpnId, vpnName);
1038 // TODO Clean up the exception handling
1039 @SuppressWarnings("checkstyle:IllegalCatch")
1040 public void updateVpnInterfaceOnTepDelete(VpnInterfaceOpDataEntry vpnInterface,
1041 StateTunnelList stateTunnelList,
1042 TypedWriteTransaction<Configuration> writeConfigTxn,
1043 TypedWriteTransaction<Operational> writeOperTxn) {
1045 AdjacenciesOp adjacencies = vpnInterface.augmentation(AdjacenciesOp.class);
1046 List<Adjacency> adjList = adjacencies != null ? adjacencies.getAdjacency() : new ArrayList<>();
1047 String prefix = null;
1049 boolean isNextHopRemoveReqd = false;
1050 String srcTepIp = stateTunnelList.getSrcInfo().getTepIp().stringValue();
1051 BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
1052 String vpnName = vpnInterface.getVpnInstanceName();
1053 long vpnId = vpnUtil.getVpnId(vpnName);
1054 String primaryRd = vpnUtil.getVpnRd(vpnName);
1055 if (adjList != null) {
1056 List<Adjacency> value = new ArrayList<>();
1057 LOG.info("updateVpnInterfaceOnTepDelete: AdjacencyList for interface {} on dpn {} vpn {} is {}",
1058 vpnInterface.getName(), vpnInterface.getDpnId(),
1059 vpnInterface.getVpnInstanceName(), adjList);
1060 for (Adjacency adj : adjList) {
1061 List<String> nhList = new ArrayList<>();
1062 String rd = adj.getVrfId();
1063 rd = rd != null ? rd : vpnName;
1064 prefix = adj.getIpAddress();
1065 List<String> nextHopList = adj.getNextHopIpList();
1066 label = adj.getLabel();
1067 if (nextHopList != null && !nextHopList.isEmpty()) {
1068 isNextHopRemoveReqd = true;
1070 // If TEP is deleted , remove the nexthop from primary adjacency.
1071 // Secondary adj nexthop will continue to point to primary adj IP address.
1072 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
1073 value.add(new AdjacencyBuilder(adj).setNextHopIpList(nhList).build());
1075 Optional<VrfEntry> vrfEntryOptional = FibHelper.getVrfEntry(dataBroker, primaryRd, prefix);
1076 if (!vrfEntryOptional.isPresent()) {
1079 nhList = FibHelper.getNextHopListFromRoutePaths(vrfEntryOptional.get());
1080 if (nhList.contains(srcTepIp)) {
1081 nhList.remove(srcTepIp);
1082 isNextHopRemoveReqd = true;
1087 if (isNextHopRemoveReqd) {
1088 updateLabelMapper(label, nhList);
1089 LOG.info("updateVpnInterfaceOnTepDelete: Updated label mapper : label {} dpn {} prefix {}"
1090 + " nexthoplist {} vpn {} vpnid {} rd {} interface {}", label, srcDpnId,
1091 prefix, nhList, vpnName,
1092 vpnId, rd, vpnInterface.getName());
1093 // Update the VRF entry with removed nextHop
1094 fibManager.updateRoutePathForFibEntry(primaryRd, prefix, srcTepIp,
1095 label, false, TransactionAdapter.toWriteTransaction(writeConfigTxn));
1097 //Get the list of VPN's importing this route(prefix) .
1098 // Then update the VRF entry with nhList
1099 List<VpnInstanceOpDataEntry> vpnsToImportRoute = vpnUtil.getVpnsImportingMyRoute(vpnName);
1100 for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
1101 String vpnRd = vpn.getVrfId();
1102 if (vpnRd != null) {
1103 fibManager.updateRoutePathForFibEntry(vpnRd, prefix,
1104 srcTepIp, label, false, TransactionAdapter.toWriteTransaction(writeConfigTxn));
1105 LOG.info("updateVpnInterfaceOnTepDelete: Exported route with rd {} prefix {} nhList {}"
1106 + " label {} interface {} dpn {} from vpn {} to VPN {} vpnRd {}", rd, prefix,
1107 nhList, label, vpnInterface.getName(), srcDpnId,
1109 vpn.getVpnInstanceName(), vpnRd);
1113 // Withdraw prefix from BGP only for external vpn.
1115 if (!rd.equalsIgnoreCase(vpnName)) {
1116 bgpManager.withdrawPrefix(rd, prefix);
1118 LOG.info("updateVpnInterfaceOnTepDelete: Withdrawn rd {} prefix {} nhList {} label {}"
1119 + " for interface {} on dpn {} vpn {}", rd, prefix, nhList, label,
1120 vpnInterface.getName(), srcDpnId,
1122 } catch (Exception ex) {
1123 LOG.error("updateVpnInterfaceOnTepDelete: Exception when withdrawing prefix {} nh {} label {}"
1124 + " on rd {} for interface {} on dpn {} vpn {}", prefix, nhList, label, rd,
1125 vpnInterface.getName(), srcDpnId, vpnName, ex);
1129 AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(value);
1130 VpnInterfaceOpDataEntry opInterface = new VpnInterfaceOpDataEntryBuilder(vpnInterface)
1131 .withKey(new VpnInterfaceOpDataEntryKey(vpnInterface.getName(), vpnName))
1132 .addAugmentation(AdjacenciesOp.class, aug).build();
1133 InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId =
1134 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterface.getName(), vpnName);
1135 writeOperTxn.put(interfaceId, opInterface, CREATE_MISSING_PARENTS);
1136 LOG.info("updateVpnInterfaceOnTepDelete: interface {} updated successully on tep delete on dpn {} vpn {}",
1137 vpnInterface.getName(), srcDpnId, vpnName);
1141 private List<VpnInstanceOpDataEntry> getVpnsExportingMyRoute(final String vpnName) {
1142 List<VpnInstanceOpDataEntry> vpnsToExportRoute = new ArrayList<>();
1144 String vpnRd = vpnUtil.getVpnRd(vpnName);
1145 final VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(vpnRd);
1146 if (vpnInstanceOpDataEntry == null) {
1147 LOG.debug("getVpnsExportingMyRoute: Could not retrieve vpn instance op data for {}"
1148 + " to check for vpns exporting the routes", vpnName);
1149 return vpnsToExportRoute;
1152 Predicate<VpnInstanceOpDataEntry> excludeVpn = input -> {
1153 if (input.getVpnInstanceName() == null) {
1154 LOG.error("getVpnsExportingMyRoute.excludeVpn: Received vpn instance with rd {} without a name",
1158 return !input.getVpnInstanceName().equals(vpnName);
1161 Predicate<VpnInstanceOpDataEntry> matchRTs = input -> {
1162 Iterable<String> commonRTs =
1163 VpnUtil.intersection(VpnUtil.getRts(vpnInstanceOpDataEntry, VpnTarget.VrfRTType.ImportExtcommunity),
1164 VpnUtil.getRts(input, VpnTarget.VrfRTType.ExportExtcommunity));
1165 return Iterators.size(commonRTs.iterator()) > 0;
1169 vpnUtil.getAllVpnInstanceOpData().stream().filter(excludeVpn).filter(matchRTs).collect(
1170 Collectors.toList());
1171 return vpnsToExportRoute;
1174 // TODO Clean up the exception handling
1175 @SuppressWarnings("checkstyle:IllegalCatch")
1176 void handleVpnsExportingRoutes(String vpnName, String vpnRd) {
1177 List<VpnInstanceOpDataEntry> vpnsToExportRoute = getVpnsExportingMyRoute(vpnName);
1178 for (VpnInstanceOpDataEntry vpn : vpnsToExportRoute) {
1179 List<VrfEntry> vrfEntries = vpnUtil.getAllVrfEntries(vpn.getVrfId());
1180 if (vrfEntries != null) {
1181 ListenableFutures.addErrorLogging(
1182 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
1183 for (VrfEntry vrfEntry : vrfEntries) {
1185 if (!FibHelper.isControllerManagedNonInterVpnLinkRoute(
1186 RouteOrigin.value(vrfEntry.getOrigin()))) {
1187 LOG.info("handleVpnsExportingRoutes: vrfEntry with rd {} prefix {}"
1188 + " is not a controller managed non intervpn link route. Ignoring.",
1189 vpn.getVrfId(), vrfEntry.getDestPrefix());
1192 String prefix = vrfEntry.getDestPrefix();
1193 String gwMac = vrfEntry.getGatewayMacAddress();
1194 requireNonNullElse(vrfEntry.getRoutePaths(),
1195 Collections.<RoutePaths>emptyList()).forEach(routePath -> {
1196 String nh = routePath.getNexthopAddress();
1197 int label = routePath.getLabel().intValue();
1198 if (FibHelper.isControllerManagedVpnInterfaceRoute(RouteOrigin.value(
1199 vrfEntry.getOrigin()))) {
1201 "handleVpnsExportingRoutesImporting: Importing fib entry rd {}"
1202 + " prefix {} nexthop {} label {} to vpn {} vpnRd {}",
1203 vpn.getVrfId(), prefix, nh, label, vpnName, vpnRd);
1204 fibManager.addOrUpdateFibEntry(vpnRd, null /*macAddress*/, prefix,
1205 Collections.singletonList(nh), VrfEntry.EncapType.Mplsgre, label,
1206 0 /*l3vni*/, gwMac, vpn.getVrfId(), RouteOrigin.SELF_IMPORTED,
1209 LOG.info("handleVpnsExportingRoutes: Importing subnet route fib entry"
1210 + " rd {} prefix {} nexthop {} label {} to vpn {} vpnRd {}",
1211 vpn.getVrfId(), prefix, nh, label, vpnName, vpnRd);
1212 SubnetRoute route = vrfEntry.augmentation(SubnetRoute.class);
1213 importSubnetRouteForNewVpn(vpnRd, prefix, nh, label, route, vpn.getVrfId(),
1217 } catch (RuntimeException e) {
1218 LOG.error("getNextHopAddressList: Exception occurred while importing route with rd {}"
1219 + " prefix {} routePaths {} to vpn {} vpnRd {}", vpn.getVrfId(),
1220 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(), vpnName, vpnRd);
1223 }), LOG, "Error handing VPN exporting routes");
1225 LOG.info("getNextHopAddressList: No vrf entries to import from vpn {} with rd {} to vpn {} with rd {}",
1226 vpn.getVpnInstanceName(), vpn.getVrfId(), vpnName, vpnRd);
1232 public void remove(InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
1233 LOG.trace("Received VpnInterface remove event: vpnInterface={}", vpnInterface);
1234 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class);
1235 final String interfaceName = key.getName();
1236 for (VpnInstanceNames vpnInterfaceVpnInstance : requireNonNullElse(vpnInterface.getVpnInstanceNames(),
1237 Collections.<VpnInstanceNames>emptyList())) {
1238 String vpnName = vpnInterfaceVpnInstance.getVpnName();
1239 removeVpnInterfaceCall(identifier, vpnInterface, vpnName, interfaceName);
1243 private void removeVpnInterfaceCall(final InstanceIdentifier<VpnInterface> identifier,
1244 final VpnInterface vpnInterface, final String vpnName,
1245 final String interfaceName) {
1246 if (Boolean.TRUE.equals(vpnInterface.isRouterInterface())) {
1247 jobCoordinator.enqueueJob("VPNINTERFACE-" + vpnInterface.getName(), () -> {
1248 ListenableFuture<Void> future =
1249 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
1250 deleteFibEntryForRouterInterface(vpnInterface, confTx, vpnName);
1251 LOG.info("remove: Router interface {} for vpn {}", interfaceName, vpnName);
1253 ListenableFutures.addErrorLogging(future, LOG, "Error removing call for interface {} on VPN {}",
1254 vpnInterface.getName(), vpnName);
1255 return Collections.singletonList(future);
1256 }, DJC_MAX_RETRIES);
1258 Interface interfaceState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker, interfaceName);
1259 removeVpnInterfaceFromVpn(identifier, vpnInterface, vpnName, interfaceName, interfaceState);
1263 @SuppressFBWarnings("DLS_DEAD_LOCAL_STORE")
1264 private void removeVpnInterfaceFromVpn(final InstanceIdentifier<VpnInterface> identifier,
1265 final VpnInterface vpnInterface, final String vpnName,
1266 final String interfaceName, final Interface interfaceState) {
1267 LOG.info("remove: VPN Interface remove event - intfName {} vpn {} dpn {}" ,vpnInterface.getName(),
1268 vpnName, vpnInterface.getDpnId());
1269 removeInterfaceFromUnprocessedList(identifier, vpnInterface);
1270 jobCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName,
1272 List<ListenableFuture<Void>> futures = new ArrayList<>(3);
1273 ListenableFuture<Void> configFuture = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1274 writeConfigTxn -> futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
1275 writeOperTxn -> futures.add(
1276 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, writeInvTxn -> {
1277 LOG.info("remove: - intfName {} onto vpnName {} running config-driven",
1278 interfaceName, vpnName);
1281 String gwMacAddress;
1282 InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId =
1283 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
1284 Optional<VpnInterfaceOpDataEntry> optVpnInterface;
1286 optVpnInterface = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1287 LogicalDatastoreType.OPERATIONAL, interfaceId);
1288 } catch (ReadFailedException e) {
1289 LOG.error("remove: Failed to read data store for interface {} vpn {}",
1290 interfaceName, vpnName);
1293 if (interfaceState != null) {
1295 dpId = InterfaceUtils.getDpIdFromInterface(interfaceState);
1296 } catch (NumberFormatException | IllegalStateException e) {
1297 LOG.error("remove: Unable to retrieve dpnId from interface operational"
1298 + " data store for interface {} on dpn {} for vpn {} Fetching"
1299 + " from vpn interface op data store. ", interfaceName,
1300 vpnInterface.getDpnId(), vpnName, e);
1301 dpId = BigInteger.ZERO;
1303 ifIndex = interfaceState.getIfIndex();
1304 gwMacAddress = interfaceState.getPhysAddress().getValue();
1306 LOG.info("remove: Interface state not available for {}. Trying to fetch data"
1307 + " from vpn interface op.", interfaceName);
1308 if (optVpnInterface.isPresent()) {
1309 VpnInterfaceOpDataEntry vpnOpInterface = optVpnInterface.get();
1310 dpId = vpnOpInterface.getDpnId();
1311 ifIndex = vpnOpInterface.getLportTag().intValue();
1312 gwMacAddress = vpnOpInterface.getGatewayMacAddress();
1314 LOG.error("remove: Handling removal of VPN interface {} for vpn {} skipped"
1315 + " as interfaceState and vpn interface op is not"
1316 + " available", interfaceName, vpnName);
1320 processVpnInterfaceDown(dpId, interfaceName, ifIndex, gwMacAddress,
1321 optVpnInterface.isPresent() ? optVpnInterface.get() : null, false,
1322 writeConfigTxn, writeOperTxn, writeInvTxn);
1324 "remove: Removal of vpn interface {} on dpn {} for vpn {} processed "
1326 interfaceName, vpnInterface.getDpnId(), vpnName);
1328 futures.add(configFuture);
1329 Futures.addCallback(configFuture, new PostVpnInterfaceWorker(interfaceName, false, "Config"));
1331 }, DJC_MAX_RETRIES);
1334 protected void processVpnInterfaceDown(BigInteger dpId,
1335 String interfaceName,
1338 VpnInterfaceOpDataEntry vpnOpInterface,
1339 boolean isInterfaceStateDown,
1340 TypedWriteTransaction<Configuration> writeConfigTxn,
1341 TypedWriteTransaction<Operational> writeOperTxn,
1342 TypedReadWriteTransaction<Configuration> writeInvTxn)
1343 throws ExecutionException, InterruptedException {
1344 if (vpnOpInterface == null) {
1345 LOG.error("processVpnInterfaceDown: Unable to process delete/down for interface {} on dpn {}"
1346 + " as it is not available in operational data store", interfaceName, dpId);
1349 final String vpnName = vpnOpInterface.getVpnInstanceName();
1350 InstanceIdentifier<VpnInterfaceOpDataEntry> identifier = VpnUtil.getVpnInterfaceOpDataEntryIdentifier(
1351 interfaceName, vpnName);
1352 if (!isInterfaceStateDown) {
1353 final long vpnId = vpnUtil.getVpnId(vpnName);
1354 vpnUtil.scheduleVpnInterfaceForRemoval(interfaceName, dpId, vpnName, null);
1355 final boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(vpnName);
1356 removeAdjacenciesFromVpn(dpId, lportTag, interfaceName, vpnName,
1357 vpnId, gwMac, writeConfigTxn, writeOperTxn, writeInvTxn);
1358 if (interfaceManager.isExternalInterface(interfaceName)) {
1359 processExternalVpnInterface(interfaceName, vpnName, dpId, lportTag,
1360 NwConstants.DEL_FLOW);
1362 if (!isBgpVpnInternetVpn) {
1363 vpnUtil.unbindService(interfaceName, isInterfaceStateDown);
1365 LOG.info("processVpnInterfaceDown: Unbound vpn service from interface {} on dpn {} for vpn {}"
1366 + " successful", interfaceName, dpId, vpnName);
1368 // Interface is retained in the DPN, but its Link Down.
1369 // Only withdraw the prefixes for this interface from BGP
1370 withdrawAdjacenciesForVpnFromBgp(identifier, vpnName, interfaceName, writeConfigTxn, writeOperTxn);
1374 private void removeAdjacenciesFromVpn(final BigInteger dpnId, final int lportTag, final String interfaceName,
1375 final String vpnName, final long vpnId, String gwMac,
1376 TypedWriteTransaction<Configuration> writeConfigTxn,
1377 TypedWriteTransaction<Operational> writeOperTxn,
1378 TypedReadWriteTransaction<Configuration> writeInvTxn)
1379 throws ExecutionException, InterruptedException {
1382 InstanceIdentifier<VpnInterfaceOpDataEntry> identifier = VpnUtil
1383 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
1384 InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
1385 Optional<AdjacenciesOp> adjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1386 LogicalDatastoreType.OPERATIONAL, path);
1387 boolean isNonPrimaryAdjIp = Boolean.FALSE;
1388 String primaryRd = vpnUtil.getVpnRd(vpnName);
1389 LOG.info("removeAdjacenciesFromVpn: For interface {} on dpn {} RD recovered for vpn {} as rd {}",
1390 interfaceName, dpnId, vpnName, primaryRd);
1391 if (adjacencies.isPresent() && adjacencies.get().getAdjacency() != null
1392 && !adjacencies.get().getAdjacency().isEmpty()) {
1393 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
1394 LOG.info("removeAdjacenciesFromVpn: NextHops for interface {} on dpn {} for vpn {} are {}",
1395 interfaceName, dpnId, vpnName, nextHops);
1396 for (Adjacency nextHop : nextHops) {
1397 if (nextHop.isPhysNetworkFunc()) {
1398 LOG.info("removeAdjacenciesFromVpn: Removing PNF FIB entry rd {} prefix {}",
1399 nextHop.getSubnetId().getValue(), nextHop.getIpAddress());
1400 fibManager.removeFibEntry(nextHop.getSubnetId().getValue(), nextHop.getIpAddress(),
1401 null/*writeCfgTxn*/);
1403 String rd = nextHop.getVrfId();
1404 List<String> nhList;
1405 if (nextHop.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
1406 nhList = getNextHopForNonPrimaryAdjacency(nextHop, vpnName, dpnId, interfaceName);
1407 isNonPrimaryAdjIp = Boolean.TRUE;
1409 // This is a primary adjacency
1410 nhList = nextHop.getNextHopIpList() != null ? nextHop.getNextHopIpList()
1412 removeGwMacAndArpResponderFlows(nextHop, vpnId, dpnId, lportTag, gwMac,
1413 interfaceName, writeInvTxn);
1415 if (!nhList.isEmpty()) {
1416 if (Objects.equals(primaryRd, vpnName)) {
1417 //this is an internal vpn - the rd is assigned to the vpn instance name;
1418 //remove from FIB directly
1419 nhList.forEach(removeAdjacencyFromInternalVpn(nextHop, vpnName,
1420 interfaceName, dpnId, writeConfigTxn, writeOperTxn));
1422 removeAdjacencyFromBgpvpn(nextHop, nhList, vpnName, primaryRd, dpnId, rd,
1423 interfaceName, writeConfigTxn, writeOperTxn);
1426 LOG.error("removeAdjacenciesFromVpn: nextHop empty for ip {} rd {} adjacencyType {}"
1427 + " interface {}", nextHop.getIpAddress(), rd,
1428 nextHop.getAdjacencyType().toString(), interfaceName);
1429 bgpManager.withdrawPrefixIfPresent(rd, nextHop.getIpAddress());
1430 fibManager.removeFibEntry(primaryRd, nextHop.getIpAddress(), writeConfigTxn);
1433 String ip = nextHop.getIpAddress().split("/")[0];
1434 LearntVpnVipToPort vpnVipToPort = vpnUtil.getLearntVpnVipToPort(vpnName, ip);
1435 if (vpnVipToPort != null && vpnVipToPort.getPortName().equals(interfaceName)) {
1436 vpnUtil.removeLearntVpnVipToPort(vpnName, ip, null);
1437 LOG.info("removeAdjacenciesFromVpn: VpnInterfaceManager removed LearntVpnVipToPort entry"
1438 + " for Interface {} ip {} on dpn {} for vpn {}",
1439 vpnVipToPort.getPortName(), ip, dpnId, vpnName);
1441 // Remove the MIP-IP from VpnPortIpToPort.
1442 if (isNonPrimaryAdjIp) {
1443 VpnPortipToPort persistedIp = vpnUtil.getVpnPortipToPort(vpnName, ip);
1444 if (persistedIp != null && persistedIp.isLearntIp()
1445 && persistedIp.getPortName().equals(interfaceName)) {
1446 VpnUtil.removeVpnPortFixedIpToPort(dataBroker, vpnName, ip, null);
1448 "removeAdjacenciesFromVpn: Learnt-IP: {} interface {} of vpn {} removed "
1449 + "from VpnPortipToPort",
1450 persistedIp.getPortFixedip(), persistedIp.getPortName(), vpnName);
1453 VpnPortipToPort vpnPortipToPort = vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnName, ip);
1454 if (vpnPortipToPort != null) {
1455 VpnUtil.removeVpnPortFixedIpToPort(dataBroker, vpnName, ip, null);
1456 LOG.info("removeAdjacenciesFromVpn: VpnInterfaceManager removed vpnPortipToPort entry for "
1457 + "Interface {} ip {} on dpn {} for vpn {}",
1458 vpnPortipToPort.getPortName(), ip, dpnId, vpnName);
1462 // this vpn interface has no more adjacency left, so clean up the vpn interface from Operational DS
1463 LOG.info("removeAdjacenciesFromVpn: Vpn Interface {} on vpn {} dpn {} has no adjacencies."
1464 + " Removing it.", interfaceName, vpnName, dpnId);
1465 writeOperTxn.delete(identifier);
1467 } catch (ReadFailedException e) {
1468 LOG.error("removeAdjacenciesFromVpn: Failed to read data store for interface {} dpn {} vpn {}",
1469 interfaceName, dpnId, vpnName);
1473 private Consumer<String> removeAdjacencyFromInternalVpn(Adjacency nextHop, String vpnName,
1474 String interfaceName, BigInteger dpnId,
1475 TypedWriteTransaction<Configuration> writeConfigTxn,
1476 TypedWriteTransaction<Operational> writeOperTx) {
1478 String primaryRd = vpnUtil.getVpnRd(vpnName);
1479 String prefix = nextHop.getIpAddress();
1480 String vpnNamePrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
1481 LOG.info("remove adjacencies for nexthop {} vpnName {} interfaceName {} dpnId {}",
1482 nextHop, vpnName, interfaceName, dpnId);
1483 synchronized (vpnNamePrefixKey.intern()) {
1484 if (vpnUtil.removeOrUpdateDSForExtraRoute(vpnName, primaryRd, dpnId.toString(), interfaceName,
1485 prefix, nextHop.getNextHopIpList().get(0), nh, writeOperTx)) {
1486 //If extra-route is present behind at least one VM, then do not remove or update
1487 //fib entry for route-path representing that CSS nexthop, just update vpntoextraroute and
1488 //prefixtointerface DS
1491 fibManager.removeOrUpdateFibEntry(vpnName, nextHop.getIpAddress(), nh,
1494 LOG.info("removeAdjacenciesFromVpn: removed/updated FIB with rd {} prefix {}"
1495 + " nexthop {} for interface {} on dpn {} for internal vpn {}",
1496 vpnName, nextHop.getIpAddress(), nh, interfaceName, dpnId, vpnName);
1500 private void removeAdjacencyFromBgpvpn(Adjacency nextHop, List<String> nhList, String vpnName, String primaryRd,
1501 BigInteger dpnId, String rd, String interfaceName,
1502 TypedWriteTransaction<Configuration> writeConfigTxn,
1503 TypedWriteTransaction<Operational> writeOperTx) {
1504 List<VpnInstanceOpDataEntry> vpnsToImportRoute =
1505 vpnUtil.getVpnsImportingMyRoute(vpnName);
1506 nhList.forEach((nh) -> {
1507 //IRT: remove routes from other vpns importing it
1508 vpnManager.removePrefixFromBGP(vpnName, primaryRd, rd, interfaceName, nextHop.getIpAddress(),
1509 nextHop.getNextHopIpList().get(0), nh, dpnId, writeConfigTxn, writeOperTx);
1510 for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
1511 String vpnRd = vpn.getVrfId();
1512 if (vpnRd != null) {
1513 fibManager.removeOrUpdateFibEntry(vpnRd,
1514 nextHop.getIpAddress(), nh, writeConfigTxn);
1515 LOG.info("removeAdjacenciesFromVpn: Removed Exported route with rd {}"
1516 + " prefix {} nextHop {} from VPN {} parentVpn {}"
1517 + " for interface {} on dpn {}", vpnRd, nextHop.getIpAddress(), nh,
1518 vpn.getVpnInstanceName(), vpnName, interfaceName, dpnId);
1524 private void removeGwMacAndArpResponderFlows(Adjacency nextHop, long vpnId, BigInteger dpnId,
1525 int lportTag, String gwMac, String interfaceName,
1526 TypedReadWriteTransaction<Configuration> writeInvTxn)
1527 throws ExecutionException, InterruptedException {
1528 final Uuid subnetId = nextHop.getSubnetId();
1529 if (nextHop.getSubnetGatewayMacAddress() == null) {
1530 // A valid mac-address was not available for this subnet-gateway-ip
1531 // So a connected-mac-address was used for this subnet and we need
1532 // to remove the flows for the same here from the L3_GW_MAC_TABLE.
1533 vpnUtil.setupGwMacIfExternalVpn(dpnId, interfaceName, vpnId, writeInvTxn, NwConstants.DEL_FLOW, gwMac);
1535 arpResponderHandler.removeArpResponderFlow(dpnId, lportTag, interfaceName, nextHop.getSubnetGatewayIp(),
1539 private List<String> getNextHopForNonPrimaryAdjacency(Adjacency nextHop, String vpnName, BigInteger dpnId,
1540 String interfaceName) {
1541 // This is either an extra-route (or) a learned IP via subnet-route
1542 List<String> nhList = null;
1543 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
1544 if (nextHopIp == null || nextHopIp.isEmpty()) {
1545 LOG.error("removeAdjacenciesFromVpn: Unable to obtain nextHopIp for"
1546 + " extra-route/learned-route in rd {} prefix {} interface {} on dpn {}"
1547 + " for vpn {}", nextHop.getVrfId(), nextHop.getIpAddress(), interfaceName, dpnId,
1549 nhList = emptyList();
1551 nhList = Collections.singletonList(nextHopIp);
1556 private Optional<String> getMacAddressForSubnetIp(String vpnName, String ifName, String ipAddress) {
1557 VpnPortipToPort gwPort = vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnName, ipAddress);
1558 //Check if a router gateway interface is available for the subnet gw is so then use Router interface
1559 // else use connected interface
1560 if (gwPort != null && gwPort.isSubnetIp()) {
1561 LOG.info("getGatewayMacAddressForSubnetIp: Retrieved gw Mac as {} for ip {} interface {} vpn {}",
1562 gwPort.getMacAddress(), ipAddress, ifName, vpnName);
1563 return Optional.of(gwPort.getMacAddress());
1565 return Optional.absent();
1569 protected void update(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface original,
1570 final VpnInterface update) {
1571 LOG.trace("Received VpnInterface update event: original={}, update={}", original, update);
1572 LOG.info("update: VPN Interface update event - intfName {} on dpn {} oldVpn {} newVpn {}", update.getName(),
1573 update.getDpnId(), original.getVpnInstanceNames(), update.getVpnInstanceNames());
1574 final String vpnInterfaceName = update.getName();
1575 final BigInteger dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
1576 LOG.info("VPN Interface update event - intfName {}", vpnInterfaceName);
1577 //handles switching between <internal VPN - external VPN>
1578 jobCoordinator.enqueueJob("VPNINTERFACE-" + vpnInterfaceName, () -> {
1579 List<ListenableFuture<Void>> futures = new ArrayList<>();
1580 if (handleVpnInstanceUpdateForVpnInterface(identifier, original, update, futures)) {
1581 LOG.info("update: handled Instance update for VPNInterface {} on dpn {} from oldVpn(s) {} "
1582 + "to newVpn(s) {}",
1583 original.getName(), dpnId,
1584 VpnHelper.getVpnInterfaceVpnInstanceNamesString(original.getVpnInstanceNames()),
1585 VpnHelper.getVpnInterfaceVpnInstanceNamesString(update.getVpnInstanceNames()));
1588 updateVpnInstanceAdjChange(original, update, vpnInterfaceName, futures);
1593 private boolean handleVpnInstanceUpdateForVpnInterface(InstanceIdentifier<VpnInterface> identifier,
1594 VpnInterface original, VpnInterface update,
1595 List<ListenableFuture<Void>> futures) {
1596 boolean isVpnInstanceUpdate = false;
1597 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class);
1598 final String interfaceName = key.getName();
1599 List<String> oldVpnList = VpnUtil.getVpnListForVpnInterface(original);
1600 List<String> oldVpnListCopy = new ArrayList<>();
1601 oldVpnListCopy.addAll(oldVpnList);
1602 List<String> newVpnList = VpnUtil.getVpnListForVpnInterface(update);
1603 List<String> newVpnListCopy = new ArrayList<>();
1604 newVpnListCopy.addAll(newVpnList);
1606 oldVpnList.removeAll(newVpnList);
1607 newVpnList.removeAll(oldVpnListCopy);
1608 //This block will execute only on if there is a change in the VPN Instance.
1609 if (!oldVpnList.isEmpty() || !newVpnList.isEmpty()) {
1611 * Internet BGP-VPN Instance update with single router:
1612 * ====================================================
1613 * In this case single VPN Interface will be part of maximum 2 VPN Instance only.
1614 * 1st VPN Instance : router VPN or external BGP-VPN.
1615 * 2nd VPN Instance : Internet BGP-VPN(router-gw update/delete) for public network access.
1617 * VPN Instance UPDATE:
1618 * oldVpnList = 0 and newVpnList = 1 (Internet BGP-VPN)
1619 * oldVpnList = 1 and newVpnList = 0 (Internet BGP-VPN)
1621 * External BGP-VPN Instance update with single router:
1622 * ====================================================
1623 * In this case single VPN interface will be part of maximum 1 VPN Instance only.
1625 * Updated VPN Instance will be always either internal router VPN to
1626 * external BGP-VPN or external BGP-VPN to internal router VPN swap.
1628 * VPN Instance UPDATE:
1629 * oldVpnList = 1 and newVpnList = 1 (router VPN to Ext-BGPVPN)
1630 * oldVpnList = 1 and newVpnList = 1 (Ext-BGPVPN to router VPN)
1632 * Dual Router VPN Instance Update:
1633 * ================================
1634 * In this case single VPN interface will be part of maximum 3 VPN Instance only.
1636 * 1st VPN Instance : router VPN or external BGP-VPN-1.
1637 * 2nd VPN Instance : router VPN or external BGP-VPN-2.
1638 * 3rd VPN Instance : Internet BGP-VPN(router-gw update/delete) for public network access.
1640 * Dual Router --> Associated with common external BGP-VPN Instance.
1641 * 1st router and 2nd router are getting associated with single External BGP-VPN
1642 * 1) add 1st router to external bgpvpn --> oldVpnList=1, newVpnList=1;
1643 * 2) add 2nd router to the same external bgpvpn --> oldVpnList=1, newVpnList=0
1644 * In this case, we need to call removeVpnInterfaceCall() followed by addVpnInterfaceCall()
1648 isVpnInstanceUpdate = true;
1649 if (VpnUtil.isDualRouterVpnUpdate(oldVpnListCopy, newVpnListCopy)) {
1650 if ((oldVpnListCopy.size() == 2 || oldVpnListCopy.size() == 3)
1651 && (oldVpnList.size() == 1 && newVpnList.size() == 0)) {
1652 //Identify the external BGP-VPN Instance and pass that value as newVpnList
1653 List<String> externalBgpVpnList = new ArrayList<>();
1654 for (String newVpnName : newVpnListCopy) {
1655 String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
1656 VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(primaryRd);
1657 if (vpnInstanceOpDataEntry.getBgpvpnType() == VpnInstanceOpDataEntry
1658 .BgpvpnType.BGPVPNExternal) {
1659 externalBgpVpnList.add(newVpnName);
1663 //This call will execute removeVpnInterfaceCall() followed by addVpnInterfaceCall()
1664 updateVpnInstanceChange(identifier, interfaceName, original, update, oldVpnList,
1665 externalBgpVpnList, oldVpnListCopy, futures);
1667 } else if ((oldVpnListCopy.size() == 2 || oldVpnListCopy.size() == 3)
1668 && (oldVpnList.size() == 0 && newVpnList.size() == 1)) {
1669 //Identify the router VPN Instance and pass that value as oldVpnList
1670 List<String> routerVpnList = new ArrayList<>();
1671 for (String newVpnName : newVpnListCopy) {
1672 String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
1673 VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(primaryRd);
1674 if (vpnInstanceOpDataEntry.getBgpvpnType() == VpnInstanceOpDataEntry
1676 routerVpnList.add(newVpnName);
1680 //This call will execute removeVpnInterfaceCall() followed by addVpnInterfaceCall()
1681 updateVpnInstanceChange(identifier, interfaceName, original, update, routerVpnList,
1682 newVpnList, oldVpnListCopy, futures);
1685 //Handle remaining use cases.
1686 updateVpnInstanceChange(identifier, interfaceName, original, update, oldVpnList, newVpnList,
1687 oldVpnListCopy, futures);
1690 updateVpnInstanceChange(identifier, interfaceName, original, update, oldVpnList, newVpnList,
1691 oldVpnListCopy, futures);
1694 return isVpnInstanceUpdate;
1697 private void updateVpnInstanceChange(InstanceIdentifier<VpnInterface> identifier, String interfaceName,
1698 VpnInterface original, VpnInterface update, List<String> oldVpnList,
1699 List<String> newVpnList, List<String> oldVpnListCopy,
1700 List<ListenableFuture<Void>> futures) {
1701 final Adjacencies origAdjs = original.augmentation(Adjacencies.class);
1702 final List<Adjacency> oldAdjs = (origAdjs != null && origAdjs.getAdjacency() != null)
1703 ? origAdjs.getAdjacency() : new ArrayList<>();
1704 final Adjacencies updateAdjs = update.augmentation(Adjacencies.class);
1705 final List<Adjacency> newAdjs = (updateAdjs != null && updateAdjs.getAdjacency() != null)
1706 ? updateAdjs.getAdjacency() : new ArrayList<>();
1708 boolean isOldVpnRemoveCallExecuted = false;
1709 for (String oldVpnName : oldVpnList) {
1710 LOG.info("updateVpnInstanceChange: VPN Interface update event - intfName {} "
1711 + "remove from vpnName {} ", interfaceName, oldVpnName);
1712 removeVpnInterfaceCall(identifier, original, oldVpnName, interfaceName);
1713 LOG.info("updateVpnInstanceChange: Processed Remove for update on VPNInterface"
1714 + " {} upon VPN update from old vpn {} to newVpn(s) {}", interfaceName, oldVpnName,
1716 isOldVpnRemoveCallExecuted = true;
1718 //Wait for previous interface bindings to be removed
1719 if (isOldVpnRemoveCallExecuted && !newVpnList.isEmpty()) {
1722 } catch (InterruptedException e) {
1726 for (String newVpnName : newVpnList) {
1727 String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
1728 if (!vpnUtil.isVpnPendingDelete(primaryRd)) {
1729 LOG.info("updateVpnInstanceChange: VPN Interface update event - intfName {} "
1730 + "onto vpnName {} ", interfaceName, newVpnName);
1731 addVpnInterfaceCall(identifier, update, oldAdjs, newAdjs, newVpnName);
1732 LOG.info("updateVpnInstanceChange: Processed Add for update on VPNInterface {}"
1733 + "from oldVpn(s) {} to newVpn {} ",
1734 interfaceName, oldVpnListCopy, newVpnName);
1735 /* This block will execute only if V6 subnet is associated with internet BGP-VPN.
1737 * In Dual stack network, first V4 subnet only attached to router and router is associated
1738 * with internet BGP-VPN(router-gw). At this point VPN interface is having only router vpn instance.
1739 * Later V6 subnet is added to router, at this point existing VPN interface will get updated
1740 * with Internet BGP-VPN instance(Note: Internet BGP-VPN Instance update in vpn interface
1741 * is applicable for only on V6 subnet is added to router). newVpnList = Contains only Internet
1742 * BGP-VPN Instance. So we required V6 primary adjacency info needs to be populated onto
1743 * router VPN as well as Internet BGP-VPN.
1745 * addVpnInterfaceCall() --> It will create V6 Adj onto Internet BGP-VPN only.
1746 * updateVpnInstanceAdjChange() --> This method call is needed for second primary V6 Adj
1747 * update in existing router VPN instance.
1749 if (vpnUtil.isBgpVpnInternet(newVpnName)) {
1750 LOG.info("updateVpnInstanceChange: VPN Interface {} with new Adjacency {} in existing "
1751 + "VPN instance {}", interfaceName, newAdjs, original.getVpnInstanceNames());
1752 updateVpnInstanceAdjChange(original, update, interfaceName, futures);
1758 private List<ListenableFuture<Void>> updateVpnInstanceAdjChange(VpnInterface original, VpnInterface update,
1759 String vpnInterfaceName,
1760 List<ListenableFuture<Void>> futures) {
1761 final Adjacencies origAdjs = original.augmentation(Adjacencies.class);
1762 final List<Adjacency> oldAdjs = origAdjs != null && origAdjs.getAdjacency()
1763 != null ? origAdjs.getAdjacency() : new ArrayList<>();
1764 final Adjacencies updateAdjs = update.augmentation(Adjacencies.class);
1765 final List<Adjacency> newAdjs = updateAdjs != null && updateAdjs.getAdjacency()
1766 != null ? updateAdjs.getAdjacency() : new ArrayList<>();
1768 final BigInteger dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
1769 for (VpnInstanceNames vpnInterfaceVpnInstance : requireNonNullElse(update.getVpnInstanceNames(),
1770 Collections.<VpnInstanceNames>emptyList())) {
1771 String newVpnName = vpnInterfaceVpnInstance.getVpnName();
1772 List<Adjacency> copyNewAdjs = new ArrayList<>(newAdjs);
1773 List<Adjacency> copyOldAdjs = new ArrayList<>(oldAdjs);
1774 String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
1775 if (!vpnUtil.isVpnPendingDelete(primaryRd)) {
1776 // TODO Deal with sequencing — the config tx must only submitted if the oper tx goes in
1777 //set of prefix used as entry in prefix-to-interface datastore
1778 // is prerequisite for refresh Fib to avoid race condition leading to missing remote next hop
1779 // in bucket actions on bgp-vpn delete
1780 Set<String> prefixListForRefreshFib = new HashSet<>();
1781 ListenableFuture<Void> configTxFuture = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
1782 confTx -> futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL,
1784 InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier =
1785 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterfaceName, newVpnName);
1786 LOG.info("VPN Interface update event-intfName {} onto vpnName {} running config-driven",
1787 update.getName(), newVpnName);
1788 //handle both addition and removal of adjacencies
1789 // currently, new adjacency may be an extra route
1790 boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(newVpnName);
1791 if (!oldAdjs.equals(newAdjs)) {
1792 for (Adjacency adj : copyNewAdjs) {
1793 if (copyOldAdjs.contains(adj)) {
1794 copyOldAdjs.remove(adj);
1796 // add new adjacency
1797 if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
1798 addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adj,
1799 dpnId, operTx, confTx, confTx, prefixListForRefreshFib);
1801 LOG.info("update: new Adjacency {} with nextHop {} label {} subnet {} "
1802 + " added to vpn interface {} on vpn {} dpnId {}",
1803 adj.getIpAddress(), adj.getNextHopIpList(), adj.getLabel(),
1804 adj.getSubnetId(), update.getName(), newVpnName, dpnId);
1807 for (Adjacency adj : copyOldAdjs) {
1808 if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
1809 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency
1810 && !adj.isPhysNetworkFunc()) {
1811 delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId, operTx,
1814 String vpnRd = vpnUtil.getVpnRd(newVpnName);
1815 LOG.debug("update: remove prefix {} from the FIB and BGP entry "
1816 + "for the Vpn-Rd {} ", adj.getIpAddress(), vpnRd);
1818 fibManager.removeFibEntry(vpnRd, adj.getIpAddress(), confTx);
1819 if (vpnRd != null && !vpnRd.equalsIgnoreCase(newVpnName)) {
1820 bgpManager.withdrawPrefix(vpnRd, adj.getIpAddress());
1823 delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId,
1827 LOG.info("update: Adjacency {} with nextHop {} label {} subnet {} removed from"
1828 + " vpn interface {} on vpn {}", adj.getIpAddress(), adj.getNextHopIpList(),
1829 adj.getLabel(), adj.getSubnetId(), update.getName(), newVpnName);
1833 Futures.addCallback(configTxFuture, new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
1834 MoreExecutors.directExecutor());
1835 futures.add(configTxFuture);
1836 for (ListenableFuture<Void> future : futures) {
1837 ListenableFutures.addErrorLogging(future, LOG, "update: failed for interface {} on vpn {}",
1838 update.getName(), update.getVpnInstanceNames());
1841 LOG.error("update: Ignoring update of vpnInterface {}, as newVpnInstance {} with primaryRd {}"
1842 + " is already marked for deletion", vpnInterfaceName, newVpnName, primaryRd);
1848 private void updateLabelMapper(Long label, List<String> nextHopIpList) {
1850 Preconditions.checkNotNull(label, "updateLabelMapper: label cannot be null or empty!");
1851 synchronized (label.toString().intern()) {
1852 InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
1853 .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build();
1854 Optional<LabelRouteInfo> opResult = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1855 LogicalDatastoreType.OPERATIONAL, lriIid);
1856 if (opResult.isPresent()) {
1857 LabelRouteInfo labelRouteInfo =
1858 new LabelRouteInfoBuilder(opResult.get()).setNextHopIpList(nextHopIpList).build();
1859 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid,
1860 labelRouteInfo, VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
1863 LOG.info("updateLabelMapper: Updated label rotue info for label {} with nextHopList {}", label,
1865 } catch (ReadFailedException e) {
1866 LOG.error("updateLabelMapper: Failed to read data store for label {} nexthopList {}", label,
1868 } catch (TransactionCommitFailedException e) {
1869 LOG.error("updateLabelMapper: Failed to commit to data store for label {} nexthopList {}", label,
1874 public synchronized void importSubnetRouteForNewVpn(String rd, String prefix, String nextHop, int label,
1875 SubnetRoute route, String parentVpnRd, TypedWriteTransaction<Configuration> writeConfigTxn) {
1877 RouteOrigin origin = RouteOrigin.SELF_IMPORTED;
1878 VrfEntry vrfEntry = FibHelper.getVrfEntryBuilder(prefix, label, nextHop, origin, parentVpnRd)
1879 .addAugmentation(SubnetRoute.class, route).build();
1880 List<VrfEntry> vrfEntryList = Collections.singletonList(vrfEntry);
1881 InstanceIdentifierBuilder<VrfTables> idBuilder =
1882 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1883 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
1884 VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).setVrfEntry(vrfEntryList).build();
1885 if (writeConfigTxn != null) {
1886 writeConfigTxn.merge(vrfTableId, vrfTableNew, CREATE_MISSING_PARENTS);
1888 vpnUtil.syncUpdate(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
1890 LOG.info("SUBNETROUTE: importSubnetRouteForNewVpn: Created vrfEntry for rd {} prefix {} nexthop {} label {}"
1891 + " and elantag {}", rd, prefix, nextHop, label, route.getElantag());
1894 protected void addNewAdjToVpnInterface(InstanceIdentifier<VpnInterfaceOpDataEntry> identifier, String primaryRd,
1895 Adjacency adj, BigInteger dpnId,
1896 TypedWriteTransaction<Operational> writeOperTxn,
1897 TypedWriteTransaction<Configuration> writeConfigTxn,
1898 TypedReadWriteTransaction<Configuration> writeInvTxn,
1899 Set<String> prefixListForRefreshFib)
1900 throws ExecutionException, InterruptedException {
1901 String interfaceName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getName();
1902 String configVpnName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getVpnInstanceName();
1904 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker
1905 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, identifier);
1906 if (optVpnInterface.isPresent()) {
1907 VpnInterfaceOpDataEntry currVpnIntf = optVpnInterface.get();
1908 String prefix = VpnUtil.getIpPrefix(adj.getIpAddress());
1909 String vpnName = currVpnIntf.getVpnInstanceName();
1910 VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(primaryRd);
1911 InstanceIdentifier<AdjacenciesOp> adjPath = identifier.augmentation(AdjacenciesOp.class);
1912 Optional<AdjacenciesOp> optAdjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1913 LogicalDatastoreType.OPERATIONAL, adjPath);
1914 boolean isL3VpnOverVxLan = VpnUtil.isL3VpnOverVxLan(vpnInstanceOpData.getL3vni());
1915 VrfEntry.EncapType encapType = VpnUtil.getEncapType(isL3VpnOverVxLan);
1916 long l3vni = vpnInstanceOpData.getL3vni() == null ? 0L : vpnInstanceOpData.getL3vni();
1917 VpnPopulator populator = L3vpnRegistry.getRegisteredPopulator(encapType);
1918 List<Adjacency> adjacencies = new ArrayList<>();
1919 if (optAdjacencies.isPresent() && optAdjacencies.get().getAdjacency() != null) {
1920 adjacencies.addAll(optAdjacencies.get().getAdjacency());
1922 long vpnId = vpnUtil.getVpnId(vpnName);
1923 L3vpnInput input = new L3vpnInput().setNextHop(adj).setVpnName(vpnName)
1924 .setInterfaceName(currVpnIntf.getName()).setPrimaryRd(primaryRd).setRd(primaryRd);
1925 Adjacency operationalAdjacency = null;
1926 //Handling dual stack neutron port primary adjacency
1927 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency && !adj.isPhysNetworkFunc()) {
1928 LOG.trace("addNewAdjToVpnInterface: Adding prefix {} to existing interface {} for vpn {}", prefix,
1929 currVpnIntf.getName(), vpnName);
1930 Interface interfaceState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker,
1931 currVpnIntf.getName());
1932 if (interfaceState != null) {
1933 processVpnInterfaceAdjacencies(dpnId, currVpnIntf.getLportTag().intValue(), vpnName, primaryRd,
1934 currVpnIntf.getName(), vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState,
1935 prefixListForRefreshFib);
1938 if (adj.getNextHopIpList() != null && !adj.getNextHopIpList().isEmpty()
1939 && adj.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
1940 RouteOrigin origin = adj.getAdjacencyType() == AdjacencyType.LearntIp ? RouteOrigin.DYNAMIC
1941 : RouteOrigin.STATIC;
1942 String nh = adj.getNextHopIpList().get(0);
1943 String vpnPrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
1944 synchronized (vpnPrefixKey.intern()) {
1945 java.util.Optional<String> rdToAllocate = vpnUtil.allocateRdForExtraRouteAndUpdateUsedRdsMap(
1946 vpnId, null, prefix, vpnName, nh, dpnId);
1947 if (rdToAllocate.isPresent()) {
1948 input.setRd(rdToAllocate.get());
1949 operationalAdjacency = populator.createOperationalAdjacency(input);
1950 int label = operationalAdjacency.getLabel().intValue();
1951 vpnManager.addExtraRoute(vpnName, adj.getIpAddress(), nh, rdToAllocate.get(),
1952 currVpnIntf.getVpnInstanceName(), l3vni, origin,
1953 currVpnIntf.getName(), operationalAdjacency, encapType,
1954 prefixListForRefreshFib, writeConfigTxn);
1955 LOG.info("addNewAdjToVpnInterface: Added extra route ip {} nh {} rd {} vpnname {} label {}"
1956 + " Interface {} on dpn {}", adj.getIpAddress(), nh, rdToAllocate.get(),
1957 vpnName, label, currVpnIntf.getName(), dpnId);
1959 LOG.error("addNewAdjToVpnInterface: No rds to allocate extraroute vpn {} prefix {}",
1963 // iRT/eRT use case Will be handled in a new patchset for L3VPN Over VxLAN.
1964 // Keeping the MPLS check for now.
1965 if (encapType.equals(VrfEntryBase.EncapType.Mplsgre)) {
1966 final Adjacency opAdjacency = new AdjacencyBuilder(operationalAdjacency).build();
1967 List<VpnInstanceOpDataEntry> vpnsToImportRoute =
1968 vpnUtil.getVpnsImportingMyRoute(vpnName);
1969 vpnsToImportRoute.forEach(vpn -> {
1970 if (vpn.getVrfId() != null) {
1971 vpnUtil.allocateRdForExtraRouteAndUpdateUsedRdsMap(vpn.getVpnId(), vpnId, prefix,
1972 vpnUtil.getVpnName(vpn.getVpnId()), nh, dpnId)
1974 rds -> vpnManager.addExtraRoute(
1975 vpnUtil.getVpnName(vpn.getVpnId()), adj.getIpAddress(),
1976 nh, rds, currVpnIntf.getVpnInstanceName(), l3vni,
1977 RouteOrigin.SELF_IMPORTED, currVpnIntf.getName(), opAdjacency,
1978 encapType, prefixListForRefreshFib, writeConfigTxn));
1983 } else if (adj.isPhysNetworkFunc()) { // PNF adjacency.
1984 LOG.trace("addNewAdjToVpnInterface: Adding prefix {} to interface {} for vpn {}", prefix,
1985 currVpnIntf.getName(), vpnName);
1987 InstanceIdentifier<VpnInterface> vpnIfaceConfigidentifier = VpnUtil
1988 .getVpnInterfaceIdentifier(currVpnIntf.getName());
1989 Optional<VpnInterface> vpnIntefaceConfig = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1990 LogicalDatastoreType.CONFIGURATION, vpnIfaceConfigidentifier);
1991 Prefixes pnfPrefix = VpnUtil.getPrefixToInterface(BigInteger.ZERO, currVpnIntf.getName(), prefix,
1992 Prefixes.PrefixCue.PhysNetFunc);
1993 if (vpnIntefaceConfig.isPresent()) {
1994 pnfPrefix = VpnUtil.getPrefixToInterface(BigInteger.ZERO, currVpnIntf.getName(), prefix,
1995 vpnIntefaceConfig.get().getNetworkId(), vpnIntefaceConfig.get().getNetworkType(),
1996 vpnIntefaceConfig.get().getSegmentationId(), Prefixes.PrefixCue.PhysNetFunc);
1999 String parentVpnRd = getParentVpnRdForExternalSubnet(adj);
2002 VpnUtil.getPrefixToInterfaceIdentifier(vpnUtil.getVpnId(adj.getSubnetId().getValue()),
2003 prefix), pnfPrefix, true);
2005 fibManager.addOrUpdateFibEntry(adj.getSubnetId().getValue(), adj.getMacAddress(),
2006 adj.getIpAddress(), emptyList(), null /* EncapType */, 0 /* label */,
2007 0 /*l3vni*/, null /* gw-mac */, parentVpnRd, RouteOrigin.LOCAL, writeConfigTxn);
2009 input.setRd(adj.getVrfId());
2011 if (operationalAdjacency == null) {
2012 operationalAdjacency = populator.createOperationalAdjacency(input);
2014 adjacencies.add(operationalAdjacency);
2015 AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(adjacencies);
2016 VpnInterfaceOpDataEntry newVpnIntf =
2017 VpnUtil.getVpnInterfaceOpDataEntry(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(),
2018 aug, dpnId, currVpnIntf.getLportTag(),
2019 currVpnIntf.getGatewayMacAddress());
2021 writeOperTxn.merge(identifier, newVpnIntf, CREATE_MISSING_PARENTS);
2023 } catch (ReadFailedException e) {
2024 LOG.error("addNewAdjToVpnInterface: Failed to read data store for interface {} dpn {} vpn {} rd {} ip "
2025 + "{}", interfaceName, dpnId, configVpnName, primaryRd, adj.getIpAddress());
2030 private String getParentVpnRdForExternalSubnet(Adjacency adj) {
2031 Subnets subnets = vpnUtil.getExternalSubnet(adj.getSubnetId());
2032 return subnets != null ? subnets.getExternalNetworkId().getValue() : null;
2035 protected void delAdjFromVpnInterface(InstanceIdentifier<VpnInterfaceOpDataEntry> identifier, Adjacency adj,
2036 BigInteger dpnId, TypedWriteTransaction<Operational> writeOperTxn,
2037 TypedWriteTransaction<Configuration> writeConfigTxn) {
2038 String interfaceName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getName();
2039 String vpnName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getVpnInstanceName();
2041 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker.syncReadOptional(
2042 dataBroker, LogicalDatastoreType.OPERATIONAL, identifier);
2043 if (optVpnInterface.isPresent()) {
2044 VpnInterfaceOpDataEntry currVpnIntf = optVpnInterface.get();
2045 InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
2046 Optional<AdjacenciesOp> optAdjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
2047 LogicalDatastoreType.OPERATIONAL, path);
2048 if (optAdjacencies.isPresent()) {
2049 List<Adjacency> adjacencies = optAdjacencies.get().getAdjacency();
2051 if (adjacencies != null && !adjacencies.isEmpty()) {
2052 LOG.trace("delAdjFromVpnInterface: Adjacencies are {}", adjacencies);
2053 for (Adjacency adjacency : adjacencies) {
2054 if (Objects.equals(adjacency.getIpAddress(), adj.getIpAddress())) {
2055 String rd = adjacency.getVrfId();
2056 if (adj.getNextHopIpList() != null) {
2057 for (String nh : adj.getNextHopIpList()) {
2058 deleteExtraRouteFromCurrentAndImportingVpns(
2059 currVpnIntf.getVpnInstanceName(), adj.getIpAddress(), nh, rd,
2060 currVpnIntf.getName(), writeConfigTxn, writeOperTxn);
2062 } else if (adj.isPhysNetworkFunc()) {
2063 LOG.info("delAdjFromVpnInterface: deleting PNF adjacency prefix {} subnet {}",
2064 adj.getIpAddress(), adj.getSubnetId());
2065 fibManager.removeFibEntry(adj.getSubnetId().getValue(), adj.getIpAddress(),
2073 LOG.info("delAdjFromVpnInterface: Removed adj {} on dpn {} rd {}", adj.getIpAddress(),
2074 dpnId, adj.getVrfId());
2076 LOG.error("delAdjFromVpnInterface: Cannnot DEL adjacency, since operational interface is "
2077 + "unavailable dpnId {} adjIP {} rd {}", dpnId, adj.getIpAddress(), adj.getVrfId());
2080 } catch (ReadFailedException e) {
2081 LOG.error("delAdjFromVpnInterface: Failed to read data store for ip {} interface {} dpn {} vpn {}",
2082 adj.getIpAddress(), interfaceName, dpnId, vpnName);
2086 private void deleteExtraRouteFromCurrentAndImportingVpns(String vpnName, String destination, String nextHop,
2087 String rd, String intfName, TypedWriteTransaction<Configuration> writeConfigTxn,
2088 TypedWriteTransaction<Operational> writeOperTx) {
2089 vpnManager.delExtraRoute(vpnName, destination, nextHop, rd, vpnName, intfName, writeConfigTxn, writeOperTx);
2090 List<VpnInstanceOpDataEntry> vpnsToImportRoute = vpnUtil.getVpnsImportingMyRoute(vpnName);
2091 for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
2092 String vpnRd = vpn.getVrfId();
2093 if (vpnRd != null) {
2094 vpnManager.delExtraRoute(vpnName, destination, nextHop, vpnRd, vpnName, intfName, writeConfigTxn,
2100 InstanceIdentifier<DpnVpninterfacesList> getRouterDpnId(String routerName, BigInteger dpnId) {
2101 return InstanceIdentifier.builder(NeutronRouterDpns.class)
2102 .child(RouterDpnList.class, new RouterDpnListKey(routerName))
2103 .child(DpnVpninterfacesList.class, new DpnVpninterfacesListKey(dpnId)).build();
2106 InstanceIdentifier<RouterDpnList> getRouterId(String routerName) {
2107 return InstanceIdentifier.builder(NeutronRouterDpns.class)
2108 .child(RouterDpnList.class, new RouterDpnListKey(routerName)).build();
2111 protected void createFibEntryForRouterInterface(String primaryRd, VpnInterface vpnInterface, String interfaceName,
2112 TypedWriteTransaction<Configuration> writeConfigTxn, String vpnName) {
2113 if (vpnInterface == null) {
2116 List<Adjacency> adjs = vpnUtil.getAdjacenciesForVpnInterfaceFromConfig(interfaceName);
2118 LOG.error("createFibEntryForRouterInterface: VPN Interface {} of router addition failed as adjacencies for"
2119 + " this vpn interface could not be obtained. vpn {}", interfaceName, vpnName);
2122 for (Adjacency adj : adjs) {
2123 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
2124 String primaryInterfaceIp = adj.getIpAddress();
2125 String macAddress = adj.getMacAddress();
2126 String prefix = VpnUtil.getIpPrefix(primaryInterfaceIp);
2128 long label = vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME,
2129 VpnUtil.getNextHopLabelKey(primaryRd, prefix));
2131 RouterInterface routerInt = new RouterInterfaceBuilder().setUuid(vpnName)
2132 .setIpAddress(primaryInterfaceIp).setMacAddress(macAddress).build();
2133 fibManager.addFibEntryForRouterInterface(primaryRd, prefix,
2134 routerInt, label, writeConfigTxn);
2135 LOG.info("createFibEntryForRouterInterface: Router interface {} for vpn {} rd {} prefix {} label {}"
2136 + " macAddress {} processed successfully;", interfaceName, vpnName, primaryRd, prefix, label,
2139 LOG.error("createFibEntryForRouterInterface: VPN Interface {} of router addition failed as primary"
2140 + " adjacency for this vpn interface could not be obtained. rd {} vpnName {}",
2141 interfaceName, primaryRd, vpnName);
2146 protected void deleteFibEntryForRouterInterface(VpnInterface vpnInterface,
2147 TypedWriteTransaction<Configuration> writeConfigTxn, String vpnName) {
2148 Adjacencies adjs = vpnInterface.augmentation(Adjacencies.class);
2149 String rd = vpnUtil.getVpnRd(vpnName);
2151 List<Adjacency> adjsList = requireNonNullElse(adjs.getAdjacency(), emptyList());
2152 for (Adjacency adj : adjsList) {
2153 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
2154 String primaryInterfaceIp = adj.getIpAddress();
2155 String prefix = VpnUtil.getIpPrefix(primaryInterfaceIp);
2156 fibManager.removeFibEntry(rd, prefix, writeConfigTxn);
2157 LOG.info("deleteFibEntryForRouterInterface: FIB for router interface {} deleted for vpn {} rd {}"
2158 + " prefix {}", vpnInterface.getName(), vpnName, rd, prefix);
2163 LOG.error("deleteFibEntryForRouterInterface: Adjacencies for vpninterface {} is null, rd: {}",
2164 vpnInterface.getName(), rd);
2168 private void processSavedInterface(UnprocessedVpnInterfaceData intefaceData, String vpnName) {
2169 final VpnInterfaceKey key = intefaceData.identifier.firstKeyOf(VpnInterface.class);
2170 final String interfaceName = key.getName();
2171 InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier = VpnUtil
2172 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
2173 addVpnInterfaceToVpn(vpnInterfaceOpIdentifier, intefaceData.vpnInterface, null, null,
2174 intefaceData.identifier, vpnName);
2177 private void addToUnprocessedVpnInterfaces(InstanceIdentifier<VpnInterface> identifier,
2178 VpnInterface vpnInterface, String vpnName) {
2179 ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces = unprocessedVpnInterfaces
2181 if (vpnInterfaces == null) {
2182 vpnInterfaces = new ConcurrentLinkedQueue<>();
2184 vpnInterfaces.add(new UnprocessedVpnInterfaceData(identifier, vpnInterface));
2185 unprocessedVpnInterfaces.put(vpnName, vpnInterfaces);
2186 LOG.info("addToUnprocessedVpnInterfaces: Saved unhandled vpn interface {} in vpn instance {}",
2187 vpnInterface.getName(), vpnName);
2190 public boolean isVpnInstanceReady(String vpnInstanceName) {
2191 String vpnRd = vpnUtil.getVpnRd(vpnInstanceName);
2192 if (vpnRd == null) {
2195 VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(vpnRd);
2197 return vpnInstanceOpDataEntry != null;
2200 public void processSavedInterfaces(String vpnInstanceName, boolean hasVpnInstanceCreatedSuccessfully) {
2201 synchronized (vpnInstanceName.intern()) {
2202 ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces =
2203 unprocessedVpnInterfaces.get(vpnInstanceName);
2204 if (vpnInterfaces != null) {
2205 while (!vpnInterfaces.isEmpty()) {
2206 UnprocessedVpnInterfaceData savedInterface = vpnInterfaces.poll();
2207 if (hasVpnInstanceCreatedSuccessfully) {
2208 processSavedInterface(savedInterface, vpnInstanceName);
2209 LOG.info("processSavedInterfaces: Handle saved vpn interfaces {} in vpn instance {}",
2210 savedInterface.vpnInterface.getName(), vpnInstanceName);
2212 LOG.error("processSavedInterfaces: Cannot process vpn interface {} in vpn instance {}",
2213 savedInterface.vpnInterface.getName(), vpnInstanceName);
2217 LOG.info("processSavedInterfaces: No interfaces in queue for VPN {}", vpnInstanceName);
2222 private void removeInterfaceFromUnprocessedList(InstanceIdentifier<VpnInterface> identifier,
2223 VpnInterface vpnInterface) {
2224 synchronized (VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface).intern()) {
2225 ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces =
2226 unprocessedVpnInterfaces.get(VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface));
2227 if (vpnInterfaces != null) {
2228 if (vpnInterfaces.remove(new UnprocessedVpnInterfaceData(identifier, vpnInterface))) {
2229 LOG.info("removeInterfaceFromUnprocessedList: Removed vpn interface {} in vpn instance {} from "
2230 + "unprocessed list", vpnInterface.getName(),
2231 VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface));
2234 LOG.info("removeInterfaceFromUnprocessedList: No interfaces in queue for VPN {}",
2235 VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface));
2240 public void vpnInstanceIsReady(String vpnInstanceName) {
2241 processSavedInterfaces(vpnInstanceName, true);
2244 public void vpnInstanceFailed(String vpnInstanceName) {
2245 processSavedInterfaces(vpnInstanceName, false);
2248 private static class UnprocessedVpnInterfaceData {
2249 InstanceIdentifier<VpnInterface> identifier;
2250 VpnInterface vpnInterface;
2252 UnprocessedVpnInterfaceData(InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
2253 this.identifier = identifier;
2254 this.vpnInterface = vpnInterface;
2258 public int hashCode() {
2259 final int prime = 31;
2261 result = prime * result + (identifier == null ? 0 : identifier.hashCode());
2262 result = prime * result + (vpnInterface == null ? 0 : vpnInterface.hashCode());
2267 public boolean equals(Object obj) {
2274 if (getClass() != obj.getClass()) {
2277 UnprocessedVpnInterfaceData other = (UnprocessedVpnInterfaceData) obj;
2278 if (identifier == null) {
2279 if (other.identifier != null) {
2282 } else if (!identifier.equals(other.identifier)) {
2285 if (vpnInterface == null) {
2286 if (other.vpnInterface != null) {
2289 } else if (!vpnInterface.equals(other.vpnInterface)) {
2296 public void updateVpnInterfacesForUnProcessAdjancencies(String vpnName) {
2297 String primaryRd = vpnUtil.getVpnRd(vpnName);
2298 VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(primaryRd);
2299 if (vpnInstanceOpData == null) {
2302 List<VpnToDpnList> vpnToDpnLists = vpnInstanceOpData.getVpnToDpnList();
2303 if (vpnToDpnLists == null || vpnToDpnLists.isEmpty()) {
2306 LOG.debug("Update the VpnInterfaces for Unprocessed Adjancencies for vpnName:{}", vpnName);
2307 vpnToDpnLists.forEach(vpnToDpnList -> {
2308 if (vpnToDpnList.getVpnInterfaces() == null) {
2311 vpnToDpnList.getVpnInterfaces().forEach(vpnInterface -> {
2313 InstanceIdentifier<VpnInterfaceOpDataEntry> existingVpnInterfaceId =
2314 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterface.getInterfaceName(), vpnName);
2315 Optional<VpnInterfaceOpDataEntry> vpnInterfaceOptional = SingleTransactionDataBroker
2316 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, existingVpnInterfaceId);
2317 if (!vpnInterfaceOptional.isPresent()) {
2320 List<Adjacency> configVpnAdjacencies = vpnUtil.getAdjacenciesForVpnInterfaceFromConfig(
2321 vpnInterface.getInterfaceName());
2322 if (configVpnAdjacencies == null) {
2323 LOG.debug("There is no adjacency available for vpnInterface:{}", vpnInterface);
2326 List<Adjacency> operationVpnAdjacencies = requireNonNullElse(vpnInterfaceOptional.get()
2327 .augmentation(AdjacenciesOp.class).getAdjacency(), emptyList());
2328 // Due to insufficient rds, some of the extra route wont get processed when it is added.
2329 // The unprocessed adjacencies will be present in config vpn interface DS but will be missing
2330 // in operational DS. These unprocessed adjacencies will be handled below.
2331 // To obtain unprocessed adjacencies, filtering is done by which the missing adjacencies in
2332 // operational DS are retrieved which is used to call addNewAdjToVpnInterface method.
2333 configVpnAdjacencies.stream()
2334 .filter(adjacency -> operationVpnAdjacencies.stream()
2335 .noneMatch(operationalAdjacency ->
2336 Objects.equals(operationalAdjacency.getIpAddress(), adjacency.getIpAddress())))
2337 .forEach(adjacency -> {
2338 LOG.debug("Processing the vpnInterface{} for the Ajacency:{}", vpnInterface, adjacency);
2339 jobCoordinator.enqueueJob("VPNINTERFACE-" + vpnInterface.getInterfaceName(),
2341 // TODO Deal with sequencing — the config tx must only submitted
2342 // if the oper tx goes in
2343 if (vpnUtil.isAdjacencyEligibleToVpn(adjacency, vpnName)) {
2344 List<ListenableFuture<Void>> futures = new ArrayList<>();
2346 txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
2347 //set of prefix used, as entry in prefix-to-interface datastore
2348 // is prerequisite for refresh Fib to avoid race condition leading
2349 // to missing remote next hop in bucket actions on bgp-vpn delete
2350 Set<String> prefixListForRefreshFib = new HashSet<>();
2351 ListenableFuture<Void> configTxFuture =
2352 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
2353 confTx -> addNewAdjToVpnInterface(existingVpnInterfaceId,
2354 primaryRd, adjacency, vpnInterfaceOptional.get().getDpnId(),
2355 operTx, confTx, confTx, prefixListForRefreshFib));
2356 Futures.addCallback(configTxFuture,
2357 new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
2358 MoreExecutors.directExecutor());
2359 futures.add(configTxFuture);
2367 } catch (ReadFailedException e) {
2368 LOG.error("updateVpnInterfacesForUnProcessAdjancencies: Failed to read data store for vpn {} rd {}",
2369 vpnName, primaryRd);
2375 private class PostVpnInterfaceWorker implements FutureCallback<Void> {
2376 private final String interfaceName;
2377 private final boolean add;
2378 private final String txnDestination;
2380 PostVpnInterfaceWorker(String interfaceName, boolean add, String transactionDest) {
2381 this.interfaceName = interfaceName;
2383 this.txnDestination = transactionDest;
2387 public void onSuccess(Void voidObj) {
2389 LOG.debug("VpnInterfaceManager: VrfEntries for {} stored into destination {} successfully",
2390 interfaceName, txnDestination);
2392 LOG.debug("VpnInterfaceManager: VrfEntries for {} removed successfully", interfaceName);
2397 public void onFailure(Throwable throwable) {
2399 LOG.error("VpnInterfaceManager: VrfEntries for {} failed to store into destination {}",
2400 interfaceName, txnDestination, throwable);
2402 LOG.error("VpnInterfaceManager: VrfEntries for {} removal failed", interfaceName, throwable);
2403 vpnUtil.unsetScheduledToRemoveForVpnInterface(interfaceName);
2408 private class VpnInterfaceCallBackHandler implements FutureCallback<Void> {
2409 private final String primaryRd;
2410 private final Set<String> prefixListForRefreshFib;
2412 VpnInterfaceCallBackHandler(String primaryRd, Set<String> prefixListForRefreshFib) {
2413 this.primaryRd = primaryRd;
2414 this.prefixListForRefreshFib = prefixListForRefreshFib;
2418 public void onSuccess(Void voidObj) {
2419 prefixListForRefreshFib.forEach(prefix -> {
2420 fibManager.refreshVrfEntry(primaryRd, prefix);
2425 public void onFailure(Throwable throwable) {
2426 LOG.debug("write Tx config operation failed {}", throwable);