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 String primaryRd = vpnUtil.getVpnRd(vpnName);
1388 LOG.info("removeAdjacenciesFromVpn: For interface {} on dpn {} RD recovered for vpn {} as rd {}",
1389 interfaceName, dpnId, vpnName, primaryRd);
1390 if (adjacencies.isPresent() && adjacencies.get().getAdjacency() != null
1391 && !adjacencies.get().getAdjacency().isEmpty()) {
1392 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
1393 LOG.info("removeAdjacenciesFromVpn: NextHops for interface {} on dpn {} for vpn {} are {}",
1394 interfaceName, dpnId, vpnName, nextHops);
1395 for (Adjacency nextHop : nextHops) {
1396 if (nextHop.isPhysNetworkFunc()) {
1397 LOG.info("removeAdjacenciesFromVpn: Removing PNF FIB entry rd {} prefix {}",
1398 nextHop.getSubnetId().getValue(), nextHop.getIpAddress());
1399 fibManager.removeFibEntry(nextHop.getSubnetId().getValue(), nextHop.getIpAddress(),
1400 null/*writeCfgTxn*/);
1402 String rd = nextHop.getVrfId();
1403 List<String> nhList;
1404 if (nextHop.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
1405 nhList = getNextHopForNonPrimaryAdjacency(nextHop, vpnName, dpnId, interfaceName);
1407 // This is a primary adjacency
1408 nhList = nextHop.getNextHopIpList() != null ? nextHop.getNextHopIpList()
1410 removeGwMacAndArpResponderFlows(nextHop, vpnId, dpnId, lportTag, gwMac,
1411 interfaceName, writeInvTxn);
1413 if (!nhList.isEmpty()) {
1414 if (Objects.equals(primaryRd, vpnName)) {
1415 //this is an internal vpn - the rd is assigned to the vpn instance name;
1416 //remove from FIB directly
1417 nhList.forEach(removeAdjacencyFromInternalVpn(nextHop, vpnName,
1418 interfaceName, dpnId, writeConfigTxn, writeOperTxn));
1420 removeAdjacencyFromBgpvpn(nextHop, nhList, vpnName, primaryRd, dpnId, rd,
1421 interfaceName, writeConfigTxn, writeOperTxn);
1424 LOG.error("removeAdjacenciesFromVpn: nextHop empty for ip {} rd {} adjacencyType {}"
1425 + " interface {}", nextHop.getIpAddress(), rd,
1426 nextHop.getAdjacencyType().toString(), interfaceName);
1427 bgpManager.withdrawPrefixIfPresent(rd, nextHop.getIpAddress());
1428 fibManager.removeFibEntry(primaryRd, nextHop.getIpAddress(), writeConfigTxn);
1431 String ip = nextHop.getIpAddress().split("/")[0];
1432 LearntVpnVipToPort vpnVipToPort = vpnUtil.getLearntVpnVipToPort(vpnName, ip);
1433 if (vpnVipToPort != null) {
1434 vpnUtil.removeLearntVpnVipToPort(vpnName, ip, null);
1435 LOG.info("removeAdjacenciesFromVpn: VpnInterfaceManager removed LearntVpnVipToPort entry"
1436 + " for Interface {} ip {} on dpn {} for vpn {}",
1437 vpnVipToPort.getPortName(), ip, dpnId, vpnName);
1439 VpnPortipToPort vpnPortipToPort = vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnName, ip);
1440 if (vpnPortipToPort != null) {
1441 VpnUtil.removeVpnPortFixedIpToPort(dataBroker, vpnName, ip, null);
1442 LOG.info("removeAdjacenciesFromVpn: VpnInterfaceManager removed vpnPortipToPort entry for "
1443 + "Interface {} ip {} on dpn {} for vpn {}",
1444 vpnPortipToPort.getPortName(), ip, dpnId, vpnName);
1448 // this vpn interface has no more adjacency left, so clean up the vpn interface from Operational DS
1449 LOG.info("removeAdjacenciesFromVpn: Vpn Interface {} on vpn {} dpn {} has no adjacencies."
1450 + " Removing it.", interfaceName, vpnName, dpnId);
1451 writeOperTxn.delete(identifier);
1453 } catch (ReadFailedException e) {
1454 LOG.error("removeAdjacenciesFromVpn: Failed to read data store for interface {} dpn {} vpn {}",
1455 interfaceName, dpnId, vpnName);
1459 private Consumer<String> removeAdjacencyFromInternalVpn(Adjacency nextHop, String vpnName,
1460 String interfaceName, BigInteger dpnId,
1461 TypedWriteTransaction<Configuration> writeConfigTxn,
1462 TypedWriteTransaction<Operational> writeOperTx) {
1464 String primaryRd = vpnUtil.getVpnRd(vpnName);
1465 String prefix = nextHop.getIpAddress();
1466 String vpnNamePrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
1467 LOG.info("remove adjacencies for nexthop {} vpnName {} interfaceName {} dpnId {}",
1468 nextHop, vpnName, interfaceName, dpnId);
1469 synchronized (vpnNamePrefixKey.intern()) {
1470 if (vpnUtil.removeOrUpdateDSForExtraRoute(vpnName, primaryRd, dpnId.toString(), interfaceName,
1471 prefix, nextHop.getNextHopIpList().get(0), nh, writeOperTx)) {
1472 //If extra-route is present behind at least one VM, then do not remove or update
1473 //fib entry for route-path representing that CSS nexthop, just update vpntoextraroute and
1474 //prefixtointerface DS
1477 fibManager.removeOrUpdateFibEntry(vpnName, nextHop.getIpAddress(), nh,
1480 LOG.info("removeAdjacenciesFromVpn: removed/updated FIB with rd {} prefix {}"
1481 + " nexthop {} for interface {} on dpn {} for internal vpn {}",
1482 vpnName, nextHop.getIpAddress(), nh, interfaceName, dpnId, vpnName);
1486 private void removeAdjacencyFromBgpvpn(Adjacency nextHop, List<String> nhList, String vpnName, String primaryRd,
1487 BigInteger dpnId, String rd, String interfaceName,
1488 TypedWriteTransaction<Configuration> writeConfigTxn,
1489 TypedWriteTransaction<Operational> writeOperTx) {
1490 List<VpnInstanceOpDataEntry> vpnsToImportRoute =
1491 vpnUtil.getVpnsImportingMyRoute(vpnName);
1492 nhList.forEach((nh) -> {
1493 //IRT: remove routes from other vpns importing it
1494 vpnManager.removePrefixFromBGP(vpnName, primaryRd, rd, interfaceName, nextHop.getIpAddress(),
1495 nextHop.getNextHopIpList().get(0), nh, dpnId, writeConfigTxn, writeOperTx);
1496 for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
1497 String vpnRd = vpn.getVrfId();
1498 if (vpnRd != null) {
1499 fibManager.removeOrUpdateFibEntry(vpnRd,
1500 nextHop.getIpAddress(), nh, writeConfigTxn);
1501 LOG.info("removeAdjacenciesFromVpn: Removed Exported route with rd {}"
1502 + " prefix {} nextHop {} from VPN {} parentVpn {}"
1503 + " for interface {} on dpn {}", vpnRd, nextHop.getIpAddress(), nh,
1504 vpn.getVpnInstanceName(), vpnName, interfaceName, dpnId);
1510 private void removeGwMacAndArpResponderFlows(Adjacency nextHop, long vpnId, BigInteger dpnId,
1511 int lportTag, String gwMac, String interfaceName,
1512 TypedReadWriteTransaction<Configuration> writeInvTxn)
1513 throws ExecutionException, InterruptedException {
1514 final Uuid subnetId = nextHop.getSubnetId();
1515 if (nextHop.getSubnetGatewayMacAddress() == null) {
1516 // A valid mac-address was not available for this subnet-gateway-ip
1517 // So a connected-mac-address was used for this subnet and we need
1518 // to remove the flows for the same here from the L3_GW_MAC_TABLE.
1519 vpnUtil.setupGwMacIfExternalVpn(dpnId, interfaceName, vpnId, writeInvTxn, NwConstants.DEL_FLOW, gwMac);
1521 arpResponderHandler.removeArpResponderFlow(dpnId, lportTag, interfaceName, nextHop.getSubnetGatewayIp(),
1525 private List<String> getNextHopForNonPrimaryAdjacency(Adjacency nextHop, String vpnName, BigInteger dpnId,
1526 String interfaceName) {
1527 // This is either an extra-route (or) a learned IP via subnet-route
1528 List<String> nhList = null;
1529 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
1530 if (nextHopIp == null || nextHopIp.isEmpty()) {
1531 LOG.error("removeAdjacenciesFromVpn: Unable to obtain nextHopIp for"
1532 + " extra-route/learned-route in rd {} prefix {} interface {} on dpn {}"
1533 + " for vpn {}", nextHop.getVrfId(), nextHop.getIpAddress(), interfaceName, dpnId,
1535 nhList = emptyList();
1537 nhList = Collections.singletonList(nextHopIp);
1542 private Optional<String> getMacAddressForSubnetIp(String vpnName, String ifName, String ipAddress) {
1543 VpnPortipToPort gwPort = vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnName, ipAddress);
1544 //Check if a router gateway interface is available for the subnet gw is so then use Router interface
1545 // else use connected interface
1546 if (gwPort != null && gwPort.isSubnetIp()) {
1547 LOG.info("getGatewayMacAddressForSubnetIp: Retrieved gw Mac as {} for ip {} interface {} vpn {}",
1548 gwPort.getMacAddress(), ipAddress, ifName, vpnName);
1549 return Optional.of(gwPort.getMacAddress());
1551 return Optional.absent();
1555 protected void update(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface original,
1556 final VpnInterface update) {
1557 LOG.trace("Received VpnInterface update event: original={}, update={}", original, update);
1558 LOG.info("update: VPN Interface update event - intfName {} on dpn {} oldVpn {} newVpn {}", update.getName(),
1559 update.getDpnId(), original.getVpnInstanceNames(), update.getVpnInstanceNames());
1560 final String vpnInterfaceName = update.getName();
1561 final BigInteger dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
1562 LOG.info("VPN Interface update event - intfName {}", vpnInterfaceName);
1563 //handles switching between <internal VPN - external VPN>
1564 jobCoordinator.enqueueJob("VPNINTERFACE-" + vpnInterfaceName, () -> {
1565 List<ListenableFuture<Void>> futures = new ArrayList<>();
1566 if (handleVpnInstanceUpdateForVpnInterface(identifier, original, update, futures)) {
1567 LOG.info("update: handled Instance update for VPNInterface {} on dpn {} from oldVpn(s) {} "
1568 + "to newVpn(s) {}",
1569 original.getName(), dpnId,
1570 VpnHelper.getVpnInterfaceVpnInstanceNamesString(original.getVpnInstanceNames()),
1571 VpnHelper.getVpnInterfaceVpnInstanceNamesString(update.getVpnInstanceNames()));
1574 updateVpnInstanceAdjChange(original, update, vpnInterfaceName, futures);
1579 private boolean handleVpnInstanceUpdateForVpnInterface(InstanceIdentifier<VpnInterface> identifier,
1580 VpnInterface original, VpnInterface update,
1581 List<ListenableFuture<Void>> futures) {
1582 boolean isVpnInstanceUpdate = false;
1583 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class);
1584 final String interfaceName = key.getName();
1585 List<String> oldVpnList = VpnUtil.getVpnListForVpnInterface(original);
1586 List<String> oldVpnListCopy = new ArrayList<>();
1587 oldVpnListCopy.addAll(oldVpnList);
1588 List<String> newVpnList = VpnUtil.getVpnListForVpnInterface(update);
1589 List<String> newVpnListCopy = new ArrayList<>();
1590 newVpnListCopy.addAll(newVpnList);
1592 oldVpnList.removeAll(newVpnList);
1593 newVpnList.removeAll(oldVpnListCopy);
1594 //This block will execute only on if there is a change in the VPN Instance.
1595 if (!oldVpnList.isEmpty() || !newVpnList.isEmpty()) {
1597 * Internet BGP-VPN Instance update with single router:
1598 * ====================================================
1599 * In this case single VPN Interface will be part of maximum 2 VPN Instance only.
1600 * 1st VPN Instance : router VPN or external BGP-VPN.
1601 * 2nd VPN Instance : Internet BGP-VPN(router-gw update/delete) for public network access.
1603 * VPN Instance UPDATE:
1604 * oldVpnList = 0 and newVpnList = 1 (Internet BGP-VPN)
1605 * oldVpnList = 1 and newVpnList = 0 (Internet BGP-VPN)
1607 * External BGP-VPN Instance update with single router:
1608 * ====================================================
1609 * In this case single VPN interface will be part of maximum 1 VPN Instance only.
1611 * Updated VPN Instance will be always either internal router VPN to
1612 * external BGP-VPN or external BGP-VPN to internal router VPN swap.
1614 * VPN Instance UPDATE:
1615 * oldVpnList = 1 and newVpnList = 1 (router VPN to Ext-BGPVPN)
1616 * oldVpnList = 1 and newVpnList = 1 (Ext-BGPVPN to router VPN)
1618 * Dual Router VPN Instance Update:
1619 * ================================
1620 * In this case single VPN interface will be part of maximum 3 VPN Instance only.
1622 * 1st VPN Instance : router VPN or external BGP-VPN-1.
1623 * 2nd VPN Instance : router VPN or external BGP-VPN-2.
1624 * 3rd VPN Instance : Internet BGP-VPN(router-gw update/delete) for public network access.
1626 * Dual Router --> Associated with common external BGP-VPN Instance.
1627 * 1st router and 2nd router are getting associated with single External BGP-VPN
1628 * 1) add 1st router to external bgpvpn --> oldVpnList=1, newVpnList=1;
1629 * 2) add 2nd router to the same external bgpvpn --> oldVpnList=1, newVpnList=0
1630 * In this case, we need to call removeVpnInterfaceCall() followed by addVpnInterfaceCall()
1634 isVpnInstanceUpdate = true;
1635 if (VpnUtil.isDualRouterVpnUpdate(oldVpnListCopy, newVpnListCopy)) {
1636 if ((oldVpnListCopy.size() == 2 || oldVpnListCopy.size() == 3)
1637 && (oldVpnList.size() == 1 && newVpnList.size() == 0)) {
1638 //Identify the external BGP-VPN Instance and pass that value as newVpnList
1639 List<String> externalBgpVpnList = new ArrayList<>();
1640 for (String newVpnName : newVpnListCopy) {
1641 String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
1642 VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(primaryRd);
1643 if (vpnInstanceOpDataEntry.getBgpvpnType() == VpnInstanceOpDataEntry
1644 .BgpvpnType.BGPVPNExternal) {
1645 externalBgpVpnList.add(newVpnName);
1649 //This call will execute removeVpnInterfaceCall() followed by addVpnInterfaceCall()
1650 updateVpnInstanceChange(identifier, interfaceName, original, update, oldVpnList,
1651 externalBgpVpnList, oldVpnListCopy, futures);
1653 } else if ((oldVpnListCopy.size() == 2 || oldVpnListCopy.size() == 3)
1654 && (oldVpnList.size() == 0 && newVpnList.size() == 1)) {
1655 //Identify the router VPN Instance and pass that value as oldVpnList
1656 List<String> routerVpnList = new ArrayList<>();
1657 for (String newVpnName : newVpnListCopy) {
1658 String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
1659 VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(primaryRd);
1660 if (vpnInstanceOpDataEntry.getBgpvpnType() == VpnInstanceOpDataEntry
1662 routerVpnList.add(newVpnName);
1666 //This call will execute removeVpnInterfaceCall() followed by addVpnInterfaceCall()
1667 updateVpnInstanceChange(identifier, interfaceName, original, update, routerVpnList,
1668 newVpnList, oldVpnListCopy, futures);
1671 //Handle remaining use cases.
1672 updateVpnInstanceChange(identifier, interfaceName, original, update, oldVpnList, newVpnList,
1673 oldVpnListCopy, futures);
1676 updateVpnInstanceChange(identifier, interfaceName, original, update, oldVpnList, newVpnList,
1677 oldVpnListCopy, futures);
1680 return isVpnInstanceUpdate;
1683 private void updateVpnInstanceChange(InstanceIdentifier<VpnInterface> identifier, String interfaceName,
1684 VpnInterface original, VpnInterface update, List<String> oldVpnList,
1685 List<String> newVpnList, List<String> oldVpnListCopy,
1686 List<ListenableFuture<Void>> futures) {
1687 final Adjacencies origAdjs = original.augmentation(Adjacencies.class);
1688 final List<Adjacency> oldAdjs = (origAdjs != null && origAdjs.getAdjacency() != null)
1689 ? origAdjs.getAdjacency() : new ArrayList<>();
1690 final Adjacencies updateAdjs = update.augmentation(Adjacencies.class);
1691 final List<Adjacency> newAdjs = (updateAdjs != null && updateAdjs.getAdjacency() != null)
1692 ? updateAdjs.getAdjacency() : new ArrayList<>();
1694 boolean isOldVpnRemoveCallExecuted = false;
1695 for (String oldVpnName : oldVpnList) {
1696 LOG.info("updateVpnInstanceChange: VPN Interface update event - intfName {} "
1697 + "remove from vpnName {} ", interfaceName, oldVpnName);
1698 removeVpnInterfaceCall(identifier, original, oldVpnName, interfaceName);
1699 LOG.info("updateVpnInstanceChange: Processed Remove for update on VPNInterface"
1700 + " {} upon VPN update from old vpn {} to newVpn(s) {}", interfaceName, oldVpnName,
1702 isOldVpnRemoveCallExecuted = true;
1704 //Wait for previous interface bindings to be removed
1705 if (isOldVpnRemoveCallExecuted && !newVpnList.isEmpty()) {
1708 } catch (InterruptedException e) {
1712 for (String newVpnName : newVpnList) {
1713 String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
1714 if (!vpnUtil.isVpnPendingDelete(primaryRd)) {
1715 LOG.info("updateVpnInstanceChange: VPN Interface update event - intfName {} "
1716 + "onto vpnName {} ", interfaceName, newVpnName);
1717 addVpnInterfaceCall(identifier, update, oldAdjs, newAdjs, newVpnName);
1718 LOG.info("updateVpnInstanceChange: Processed Add for update on VPNInterface {}"
1719 + "from oldVpn(s) {} to newVpn {} ",
1720 interfaceName, oldVpnListCopy, newVpnName);
1721 /* This block will execute only if V6 subnet is associated with internet BGP-VPN.
1723 * In Dual stack network, first V4 subnet only attached to router and router is associated
1724 * with internet BGP-VPN(router-gw). At this point VPN interface is having only router vpn instance.
1725 * Later V6 subnet is added to router, at this point existing VPN interface will get updated
1726 * with Internet BGP-VPN instance(Note: Internet BGP-VPN Instance update in vpn interface
1727 * is applicable for only on V6 subnet is added to router). newVpnList = Contains only Internet
1728 * BGP-VPN Instance. So we required V6 primary adjacency info needs to be populated onto
1729 * router VPN as well as Internet BGP-VPN.
1731 * addVpnInterfaceCall() --> It will create V6 Adj onto Internet BGP-VPN only.
1732 * updateVpnInstanceAdjChange() --> This method call is needed for second primary V6 Adj
1733 * update in existing router VPN instance.
1735 if (vpnUtil.isBgpVpnInternet(newVpnName)) {
1736 LOG.info("updateVpnInstanceChange: VPN Interface {} with new Adjacency {} in existing "
1737 + "VPN instance {}", interfaceName, newAdjs, original.getVpnInstanceNames());
1738 updateVpnInstanceAdjChange(original, update, interfaceName, futures);
1744 private List<ListenableFuture<Void>> updateVpnInstanceAdjChange(VpnInterface original, VpnInterface update,
1745 String vpnInterfaceName,
1746 List<ListenableFuture<Void>> futures) {
1747 final Adjacencies origAdjs = original.augmentation(Adjacencies.class);
1748 final List<Adjacency> oldAdjs = origAdjs != null && origAdjs.getAdjacency()
1749 != null ? origAdjs.getAdjacency() : new ArrayList<>();
1750 final Adjacencies updateAdjs = update.augmentation(Adjacencies.class);
1751 final List<Adjacency> newAdjs = updateAdjs != null && updateAdjs.getAdjacency()
1752 != null ? updateAdjs.getAdjacency() : new ArrayList<>();
1754 final BigInteger dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
1755 for (VpnInstanceNames vpnInterfaceVpnInstance : requireNonNullElse(update.getVpnInstanceNames(),
1756 Collections.<VpnInstanceNames>emptyList())) {
1757 String newVpnName = vpnInterfaceVpnInstance.getVpnName();
1758 List<Adjacency> copyNewAdjs = new ArrayList<>(newAdjs);
1759 List<Adjacency> copyOldAdjs = new ArrayList<>(oldAdjs);
1760 String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
1761 if (!vpnUtil.isVpnPendingDelete(primaryRd)) {
1762 // TODO Deal with sequencing — the config tx must only submitted if the oper tx goes in
1763 //set of prefix used as entry in prefix-to-interface datastore
1764 // is prerequisite for refresh Fib to avoid race condition leading to missing remote next hop
1765 // in bucket actions on bgp-vpn delete
1766 Set<String> prefixListForRefreshFib = new HashSet<>();
1767 ListenableFuture<Void> configTxFuture = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
1768 confTx -> futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL,
1770 InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier =
1771 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterfaceName, newVpnName);
1772 LOG.info("VPN Interface update event-intfName {} onto vpnName {} running config-driven",
1773 update.getName(), newVpnName);
1774 //handle both addition and removal of adjacencies
1775 // currently, new adjacency may be an extra route
1776 boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(newVpnName);
1777 if (!oldAdjs.equals(newAdjs)) {
1778 for (Adjacency adj : copyNewAdjs) {
1779 if (copyOldAdjs.contains(adj)) {
1780 copyOldAdjs.remove(adj);
1782 // add new adjacency
1783 if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
1784 addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adj,
1785 dpnId, operTx, confTx, confTx, prefixListForRefreshFib);
1787 LOG.info("update: new Adjacency {} with nextHop {} label {} subnet {} "
1788 + " added to vpn interface {} on vpn {} dpnId {}",
1789 adj.getIpAddress(), adj.getNextHopIpList(), adj.getLabel(),
1790 adj.getSubnetId(), update.getName(), newVpnName, dpnId);
1793 for (Adjacency adj : copyOldAdjs) {
1794 if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
1795 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency
1796 && !adj.isPhysNetworkFunc()) {
1797 delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId, operTx,
1800 String vpnRd = vpnUtil.getVpnRd(newVpnName);
1801 LOG.debug("update: remove prefix {} from the FIB and BGP entry "
1802 + "for the Vpn-Rd {} ", adj.getIpAddress(), vpnRd);
1804 fibManager.removeFibEntry(vpnRd, adj.getIpAddress(), confTx);
1805 if (vpnRd != null && !vpnRd.equalsIgnoreCase(newVpnName)) {
1806 bgpManager.withdrawPrefix(vpnRd, adj.getIpAddress());
1809 delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId,
1813 LOG.info("update: Adjacency {} with nextHop {} label {} subnet {} removed from"
1814 + " vpn interface {} on vpn {}", adj.getIpAddress(), adj.getNextHopIpList(),
1815 adj.getLabel(), adj.getSubnetId(), update.getName(), newVpnName);
1819 Futures.addCallback(configTxFuture, new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
1820 MoreExecutors.directExecutor());
1821 futures.add(configTxFuture);
1822 for (ListenableFuture<Void> future : futures) {
1823 ListenableFutures.addErrorLogging(future, LOG, "update: failed for interface {} on vpn {}",
1824 update.getName(), update.getVpnInstanceNames());
1827 LOG.error("update: Ignoring update of vpnInterface {}, as newVpnInstance {} with primaryRd {}"
1828 + " is already marked for deletion", vpnInterfaceName, newVpnName, primaryRd);
1834 private void updateLabelMapper(Long label, List<String> nextHopIpList) {
1836 Preconditions.checkNotNull(label, "updateLabelMapper: label cannot be null or empty!");
1837 synchronized (label.toString().intern()) {
1838 InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
1839 .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build();
1840 Optional<LabelRouteInfo> opResult = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1841 LogicalDatastoreType.OPERATIONAL, lriIid);
1842 if (opResult.isPresent()) {
1843 LabelRouteInfo labelRouteInfo =
1844 new LabelRouteInfoBuilder(opResult.get()).setNextHopIpList(nextHopIpList).build();
1845 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid,
1846 labelRouteInfo, VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
1849 LOG.info("updateLabelMapper: Updated label rotue info for label {} with nextHopList {}", label,
1851 } catch (ReadFailedException e) {
1852 LOG.error("updateLabelMapper: Failed to read data store for label {} nexthopList {}", label,
1854 } catch (TransactionCommitFailedException e) {
1855 LOG.error("updateLabelMapper: Failed to commit to data store for label {} nexthopList {}", label,
1860 public synchronized void importSubnetRouteForNewVpn(String rd, String prefix, String nextHop, int label,
1861 SubnetRoute route, String parentVpnRd, TypedWriteTransaction<Configuration> writeConfigTxn) {
1863 RouteOrigin origin = RouteOrigin.SELF_IMPORTED;
1864 VrfEntry vrfEntry = FibHelper.getVrfEntryBuilder(prefix, label, nextHop, origin, parentVpnRd)
1865 .addAugmentation(SubnetRoute.class, route).build();
1866 List<VrfEntry> vrfEntryList = Collections.singletonList(vrfEntry);
1867 InstanceIdentifierBuilder<VrfTables> idBuilder =
1868 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1869 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
1870 VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).setVrfEntry(vrfEntryList).build();
1871 if (writeConfigTxn != null) {
1872 writeConfigTxn.merge(vrfTableId, vrfTableNew, CREATE_MISSING_PARENTS);
1874 vpnUtil.syncUpdate(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
1876 LOG.info("SUBNETROUTE: importSubnetRouteForNewVpn: Created vrfEntry for rd {} prefix {} nexthop {} label {}"
1877 + " and elantag {}", rd, prefix, nextHop, label, route.getElantag());
1880 protected void addNewAdjToVpnInterface(InstanceIdentifier<VpnInterfaceOpDataEntry> identifier, String primaryRd,
1881 Adjacency adj, BigInteger dpnId,
1882 TypedWriteTransaction<Operational> writeOperTxn,
1883 TypedWriteTransaction<Configuration> writeConfigTxn,
1884 TypedReadWriteTransaction<Configuration> writeInvTxn,
1885 Set<String> prefixListForRefreshFib)
1886 throws ExecutionException, InterruptedException {
1887 String interfaceName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getName();
1888 String configVpnName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getVpnInstanceName();
1890 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker
1891 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, identifier);
1892 if (optVpnInterface.isPresent()) {
1893 VpnInterfaceOpDataEntry currVpnIntf = optVpnInterface.get();
1894 String prefix = VpnUtil.getIpPrefix(adj.getIpAddress());
1895 String vpnName = currVpnIntf.getVpnInstanceName();
1896 VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(primaryRd);
1897 InstanceIdentifier<AdjacenciesOp> adjPath = identifier.augmentation(AdjacenciesOp.class);
1898 Optional<AdjacenciesOp> optAdjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1899 LogicalDatastoreType.OPERATIONAL, adjPath);
1900 boolean isL3VpnOverVxLan = VpnUtil.isL3VpnOverVxLan(vpnInstanceOpData.getL3vni());
1901 VrfEntry.EncapType encapType = VpnUtil.getEncapType(isL3VpnOverVxLan);
1902 long l3vni = vpnInstanceOpData.getL3vni() == null ? 0L : vpnInstanceOpData.getL3vni();
1903 VpnPopulator populator = L3vpnRegistry.getRegisteredPopulator(encapType);
1904 List<Adjacency> adjacencies = new ArrayList<>();
1905 if (optAdjacencies.isPresent() && optAdjacencies.get().getAdjacency() != null) {
1906 adjacencies.addAll(optAdjacencies.get().getAdjacency());
1908 long vpnId = vpnUtil.getVpnId(vpnName);
1909 L3vpnInput input = new L3vpnInput().setNextHop(adj).setVpnName(vpnName)
1910 .setInterfaceName(currVpnIntf.getName()).setPrimaryRd(primaryRd).setRd(primaryRd);
1911 Adjacency operationalAdjacency = null;
1912 //Handling dual stack neutron port primary adjacency
1913 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency && !adj.isPhysNetworkFunc()) {
1914 LOG.trace("addNewAdjToVpnInterface: Adding prefix {} to existing interface {} for vpn {}", prefix,
1915 currVpnIntf.getName(), vpnName);
1916 Interface interfaceState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker,
1917 currVpnIntf.getName());
1918 if (interfaceState != null) {
1919 processVpnInterfaceAdjacencies(dpnId, currVpnIntf.getLportTag().intValue(), vpnName, primaryRd,
1920 currVpnIntf.getName(), vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState,
1921 prefixListForRefreshFib);
1924 if (adj.getNextHopIpList() != null && !adj.getNextHopIpList().isEmpty()
1925 && adj.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
1926 RouteOrigin origin = adj.getAdjacencyType() == AdjacencyType.LearntIp ? RouteOrigin.DYNAMIC
1927 : RouteOrigin.STATIC;
1928 String nh = adj.getNextHopIpList().get(0);
1929 String vpnPrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
1930 synchronized (vpnPrefixKey.intern()) {
1931 java.util.Optional<String> rdToAllocate = vpnUtil.allocateRdForExtraRouteAndUpdateUsedRdsMap(
1932 vpnId, null, prefix, vpnName, nh, dpnId);
1933 if (rdToAllocate.isPresent()) {
1934 input.setRd(rdToAllocate.get());
1935 operationalAdjacency = populator.createOperationalAdjacency(input);
1936 int label = operationalAdjacency.getLabel().intValue();
1937 vpnManager.addExtraRoute(vpnName, adj.getIpAddress(), nh, rdToAllocate.get(),
1938 currVpnIntf.getVpnInstanceName(), l3vni, origin,
1939 currVpnIntf.getName(), operationalAdjacency, encapType,
1940 prefixListForRefreshFib, writeConfigTxn);
1941 LOG.info("addNewAdjToVpnInterface: Added extra route ip {} nh {} rd {} vpnname {} label {}"
1942 + " Interface {} on dpn {}", adj.getIpAddress(), nh, rdToAllocate.get(),
1943 vpnName, label, currVpnIntf.getName(), dpnId);
1945 LOG.error("addNewAdjToVpnInterface: No rds to allocate extraroute vpn {} prefix {}",
1949 // iRT/eRT use case Will be handled in a new patchset for L3VPN Over VxLAN.
1950 // Keeping the MPLS check for now.
1951 if (encapType.equals(VrfEntryBase.EncapType.Mplsgre)) {
1952 final Adjacency opAdjacency = new AdjacencyBuilder(operationalAdjacency).build();
1953 List<VpnInstanceOpDataEntry> vpnsToImportRoute =
1954 vpnUtil.getVpnsImportingMyRoute(vpnName);
1955 vpnsToImportRoute.forEach(vpn -> {
1956 if (vpn.getVrfId() != null) {
1957 vpnUtil.allocateRdForExtraRouteAndUpdateUsedRdsMap(vpn.getVpnId(), vpnId, prefix,
1958 vpnUtil.getVpnName(vpn.getVpnId()), nh, dpnId)
1960 rds -> vpnManager.addExtraRoute(
1961 vpnUtil.getVpnName(vpn.getVpnId()), adj.getIpAddress(),
1962 nh, rds, currVpnIntf.getVpnInstanceName(), l3vni,
1963 RouteOrigin.SELF_IMPORTED, currVpnIntf.getName(), opAdjacency,
1964 encapType, prefixListForRefreshFib, writeConfigTxn));
1969 } else if (adj.isPhysNetworkFunc()) { // PNF adjacency.
1970 LOG.trace("addNewAdjToVpnInterface: Adding prefix {} to interface {} for vpn {}", prefix,
1971 currVpnIntf.getName(), vpnName);
1973 InstanceIdentifier<VpnInterface> vpnIfaceConfigidentifier = VpnUtil
1974 .getVpnInterfaceIdentifier(currVpnIntf.getName());
1975 Optional<VpnInterface> vpnIntefaceConfig = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1976 LogicalDatastoreType.CONFIGURATION, vpnIfaceConfigidentifier);
1977 Prefixes pnfPrefix = VpnUtil.getPrefixToInterface(BigInteger.ZERO, currVpnIntf.getName(), prefix,
1978 Prefixes.PrefixCue.PhysNetFunc);
1979 if (vpnIntefaceConfig.isPresent()) {
1980 pnfPrefix = VpnUtil.getPrefixToInterface(BigInteger.ZERO, currVpnIntf.getName(), prefix,
1981 vpnIntefaceConfig.get().getNetworkId(), vpnIntefaceConfig.get().getNetworkType(),
1982 vpnIntefaceConfig.get().getSegmentationId(), Prefixes.PrefixCue.PhysNetFunc);
1985 String parentVpnRd = getParentVpnRdForExternalSubnet(adj);
1988 VpnUtil.getPrefixToInterfaceIdentifier(vpnUtil.getVpnId(adj.getSubnetId().getValue()),
1989 prefix), pnfPrefix, true);
1991 fibManager.addOrUpdateFibEntry(adj.getSubnetId().getValue(), adj.getMacAddress(),
1992 adj.getIpAddress(), emptyList(), null /* EncapType */, 0 /* label */,
1993 0 /*l3vni*/, null /* gw-mac */, parentVpnRd, RouteOrigin.LOCAL, writeConfigTxn);
1995 input.setRd(adj.getVrfId());
1997 if (operationalAdjacency == null) {
1998 operationalAdjacency = populator.createOperationalAdjacency(input);
2000 adjacencies.add(operationalAdjacency);
2001 AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(adjacencies);
2002 VpnInterfaceOpDataEntry newVpnIntf =
2003 VpnUtil.getVpnInterfaceOpDataEntry(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(),
2004 aug, dpnId, currVpnIntf.getLportTag(),
2005 currVpnIntf.getGatewayMacAddress());
2007 writeOperTxn.merge(identifier, newVpnIntf, CREATE_MISSING_PARENTS);
2009 } catch (ReadFailedException e) {
2010 LOG.error("addNewAdjToVpnInterface: Failed to read data store for interface {} dpn {} vpn {} rd {} ip "
2011 + "{}", interfaceName, dpnId, configVpnName, primaryRd, adj.getIpAddress());
2016 private String getParentVpnRdForExternalSubnet(Adjacency adj) {
2017 Subnets subnets = vpnUtil.getExternalSubnet(adj.getSubnetId());
2018 return subnets != null ? subnets.getExternalNetworkId().getValue() : null;
2021 protected void delAdjFromVpnInterface(InstanceIdentifier<VpnInterfaceOpDataEntry> identifier, Adjacency adj,
2022 BigInteger dpnId, TypedWriteTransaction<Operational> writeOperTxn,
2023 TypedWriteTransaction<Configuration> writeConfigTxn) {
2024 String interfaceName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getName();
2025 String vpnName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getVpnInstanceName();
2027 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker.syncReadOptional(
2028 dataBroker, LogicalDatastoreType.OPERATIONAL, identifier);
2029 if (optVpnInterface.isPresent()) {
2030 VpnInterfaceOpDataEntry currVpnIntf = optVpnInterface.get();
2031 InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
2032 Optional<AdjacenciesOp> optAdjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
2033 LogicalDatastoreType.OPERATIONAL, path);
2034 if (optAdjacencies.isPresent()) {
2035 List<Adjacency> adjacencies = optAdjacencies.get().getAdjacency();
2037 if (adjacencies != null && !adjacencies.isEmpty()) {
2038 LOG.trace("delAdjFromVpnInterface: Adjacencies are {}", adjacencies);
2039 for (Adjacency adjacency : adjacencies) {
2040 if (Objects.equals(adjacency.getIpAddress(), adj.getIpAddress())) {
2041 String rd = adjacency.getVrfId();
2042 if (adj.getNextHopIpList() != null) {
2043 for (String nh : adj.getNextHopIpList()) {
2044 deleteExtraRouteFromCurrentAndImportingVpns(
2045 currVpnIntf.getVpnInstanceName(), adj.getIpAddress(), nh, rd,
2046 currVpnIntf.getName(), writeConfigTxn, writeOperTxn);
2048 } else if (adj.isPhysNetworkFunc()) {
2049 LOG.info("delAdjFromVpnInterface: deleting PNF adjacency prefix {} subnet {}",
2050 adj.getIpAddress(), adj.getSubnetId());
2051 fibManager.removeFibEntry(adj.getSubnetId().getValue(), adj.getIpAddress(),
2059 LOG.info("delAdjFromVpnInterface: Removed adj {} on dpn {} rd {}", adj.getIpAddress(),
2060 dpnId, adj.getVrfId());
2062 LOG.error("delAdjFromVpnInterface: Cannnot DEL adjacency, since operational interface is "
2063 + "unavailable dpnId {} adjIP {} rd {}", dpnId, adj.getIpAddress(), adj.getVrfId());
2066 } catch (ReadFailedException e) {
2067 LOG.error("delAdjFromVpnInterface: Failed to read data store for ip {} interface {} dpn {} vpn {}",
2068 adj.getIpAddress(), interfaceName, dpnId, vpnName);
2072 private void deleteExtraRouteFromCurrentAndImportingVpns(String vpnName, String destination, String nextHop,
2073 String rd, String intfName, TypedWriteTransaction<Configuration> writeConfigTxn,
2074 TypedWriteTransaction<Operational> writeOperTx) {
2075 vpnManager.delExtraRoute(vpnName, destination, nextHop, rd, vpnName, intfName, writeConfigTxn, writeOperTx);
2076 List<VpnInstanceOpDataEntry> vpnsToImportRoute = vpnUtil.getVpnsImportingMyRoute(vpnName);
2077 for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
2078 String vpnRd = vpn.getVrfId();
2079 if (vpnRd != null) {
2080 vpnManager.delExtraRoute(vpnName, destination, nextHop, vpnRd, vpnName, intfName, writeConfigTxn,
2086 InstanceIdentifier<DpnVpninterfacesList> getRouterDpnId(String routerName, BigInteger dpnId) {
2087 return InstanceIdentifier.builder(NeutronRouterDpns.class)
2088 .child(RouterDpnList.class, new RouterDpnListKey(routerName))
2089 .child(DpnVpninterfacesList.class, new DpnVpninterfacesListKey(dpnId)).build();
2092 InstanceIdentifier<RouterDpnList> getRouterId(String routerName) {
2093 return InstanceIdentifier.builder(NeutronRouterDpns.class)
2094 .child(RouterDpnList.class, new RouterDpnListKey(routerName)).build();
2097 protected void createFibEntryForRouterInterface(String primaryRd, VpnInterface vpnInterface, String interfaceName,
2098 TypedWriteTransaction<Configuration> writeConfigTxn, String vpnName) {
2099 if (vpnInterface == null) {
2102 List<Adjacency> adjs = vpnUtil.getAdjacenciesForVpnInterfaceFromConfig(interfaceName);
2104 LOG.error("createFibEntryForRouterInterface: VPN Interface {} of router addition failed as adjacencies for"
2105 + " this vpn interface could not be obtained. vpn {}", interfaceName, vpnName);
2108 for (Adjacency adj : adjs) {
2109 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
2110 String primaryInterfaceIp = adj.getIpAddress();
2111 String macAddress = adj.getMacAddress();
2112 String prefix = VpnUtil.getIpPrefix(primaryInterfaceIp);
2114 long label = vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME,
2115 VpnUtil.getNextHopLabelKey(primaryRd, prefix));
2117 RouterInterface routerInt = new RouterInterfaceBuilder().setUuid(vpnName)
2118 .setIpAddress(primaryInterfaceIp).setMacAddress(macAddress).build();
2119 fibManager.addFibEntryForRouterInterface(primaryRd, prefix,
2120 routerInt, label, writeConfigTxn);
2121 LOG.info("createFibEntryForRouterInterface: Router interface {} for vpn {} rd {} prefix {} label {}"
2122 + " macAddress {} processed successfully;", interfaceName, vpnName, primaryRd, prefix, label,
2125 LOG.error("createFibEntryForRouterInterface: VPN Interface {} of router addition failed as primary"
2126 + " adjacency for this vpn interface could not be obtained. rd {} vpnName {}",
2127 interfaceName, primaryRd, vpnName);
2132 protected void deleteFibEntryForRouterInterface(VpnInterface vpnInterface,
2133 TypedWriteTransaction<Configuration> writeConfigTxn, String vpnName) {
2134 Adjacencies adjs = vpnInterface.augmentation(Adjacencies.class);
2135 String rd = vpnUtil.getVpnRd(vpnName);
2137 List<Adjacency> adjsList = requireNonNullElse(adjs.getAdjacency(), emptyList());
2138 for (Adjacency adj : adjsList) {
2139 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
2140 String primaryInterfaceIp = adj.getIpAddress();
2141 String prefix = VpnUtil.getIpPrefix(primaryInterfaceIp);
2142 fibManager.removeFibEntry(rd, prefix, writeConfigTxn);
2143 LOG.info("deleteFibEntryForRouterInterface: FIB for router interface {} deleted for vpn {} rd {}"
2144 + " prefix {}", vpnInterface.getName(), vpnName, rd, prefix);
2149 LOG.error("deleteFibEntryForRouterInterface: Adjacencies for vpninterface {} is null, rd: {}",
2150 vpnInterface.getName(), rd);
2154 private void processSavedInterface(UnprocessedVpnInterfaceData intefaceData, String vpnName) {
2155 final VpnInterfaceKey key = intefaceData.identifier.firstKeyOf(VpnInterface.class);
2156 final String interfaceName = key.getName();
2157 InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier = VpnUtil
2158 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
2159 addVpnInterfaceToVpn(vpnInterfaceOpIdentifier, intefaceData.vpnInterface, null, null,
2160 intefaceData.identifier, vpnName);
2163 private void addToUnprocessedVpnInterfaces(InstanceIdentifier<VpnInterface> identifier,
2164 VpnInterface vpnInterface, String vpnName) {
2165 ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces = unprocessedVpnInterfaces
2167 if (vpnInterfaces == null) {
2168 vpnInterfaces = new ConcurrentLinkedQueue<>();
2170 vpnInterfaces.add(new UnprocessedVpnInterfaceData(identifier, vpnInterface));
2171 unprocessedVpnInterfaces.put(vpnName, vpnInterfaces);
2172 LOG.info("addToUnprocessedVpnInterfaces: Saved unhandled vpn interface {} in vpn instance {}",
2173 vpnInterface.getName(), vpnName);
2176 public boolean isVpnInstanceReady(String vpnInstanceName) {
2177 String vpnRd = vpnUtil.getVpnRd(vpnInstanceName);
2178 if (vpnRd == null) {
2181 VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(vpnRd);
2183 return vpnInstanceOpDataEntry != null;
2186 public void processSavedInterfaces(String vpnInstanceName, boolean hasVpnInstanceCreatedSuccessfully) {
2187 synchronized (vpnInstanceName.intern()) {
2188 ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces =
2189 unprocessedVpnInterfaces.get(vpnInstanceName);
2190 if (vpnInterfaces != null) {
2191 while (!vpnInterfaces.isEmpty()) {
2192 UnprocessedVpnInterfaceData savedInterface = vpnInterfaces.poll();
2193 if (hasVpnInstanceCreatedSuccessfully) {
2194 processSavedInterface(savedInterface, vpnInstanceName);
2195 LOG.info("processSavedInterfaces: Handle saved vpn interfaces {} in vpn instance {}",
2196 savedInterface.vpnInterface.getName(), vpnInstanceName);
2198 LOG.error("processSavedInterfaces: Cannot process vpn interface {} in vpn instance {}",
2199 savedInterface.vpnInterface.getName(), vpnInstanceName);
2203 LOG.info("processSavedInterfaces: No interfaces in queue for VPN {}", vpnInstanceName);
2208 private void removeInterfaceFromUnprocessedList(InstanceIdentifier<VpnInterface> identifier,
2209 VpnInterface vpnInterface) {
2210 synchronized (VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface).intern()) {
2211 ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces =
2212 unprocessedVpnInterfaces.get(VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface));
2213 if (vpnInterfaces != null) {
2214 if (vpnInterfaces.remove(new UnprocessedVpnInterfaceData(identifier, vpnInterface))) {
2215 LOG.info("removeInterfaceFromUnprocessedList: Removed vpn interface {} in vpn instance {} from "
2216 + "unprocessed list", vpnInterface.getName(),
2217 VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface));
2220 LOG.info("removeInterfaceFromUnprocessedList: No interfaces in queue for VPN {}",
2221 VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface));
2226 public void vpnInstanceIsReady(String vpnInstanceName) {
2227 processSavedInterfaces(vpnInstanceName, true);
2230 public void vpnInstanceFailed(String vpnInstanceName) {
2231 processSavedInterfaces(vpnInstanceName, false);
2234 private static class UnprocessedVpnInterfaceData {
2235 InstanceIdentifier<VpnInterface> identifier;
2236 VpnInterface vpnInterface;
2238 UnprocessedVpnInterfaceData(InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
2239 this.identifier = identifier;
2240 this.vpnInterface = vpnInterface;
2244 public int hashCode() {
2245 final int prime = 31;
2247 result = prime * result + (identifier == null ? 0 : identifier.hashCode());
2248 result = prime * result + (vpnInterface == null ? 0 : vpnInterface.hashCode());
2253 public boolean equals(Object obj) {
2260 if (getClass() != obj.getClass()) {
2263 UnprocessedVpnInterfaceData other = (UnprocessedVpnInterfaceData) obj;
2264 if (identifier == null) {
2265 if (other.identifier != null) {
2268 } else if (!identifier.equals(other.identifier)) {
2271 if (vpnInterface == null) {
2272 if (other.vpnInterface != null) {
2275 } else if (!vpnInterface.equals(other.vpnInterface)) {
2282 public void updateVpnInterfacesForUnProcessAdjancencies(String vpnName) {
2283 String primaryRd = vpnUtil.getVpnRd(vpnName);
2284 VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(primaryRd);
2285 if (vpnInstanceOpData == null) {
2288 List<VpnToDpnList> vpnToDpnLists = vpnInstanceOpData.getVpnToDpnList();
2289 if (vpnToDpnLists == null || vpnToDpnLists.isEmpty()) {
2292 LOG.debug("Update the VpnInterfaces for Unprocessed Adjancencies for vpnName:{}", vpnName);
2293 vpnToDpnLists.forEach(vpnToDpnList -> {
2294 if (vpnToDpnList.getVpnInterfaces() == null) {
2297 vpnToDpnList.getVpnInterfaces().forEach(vpnInterface -> {
2299 InstanceIdentifier<VpnInterfaceOpDataEntry> existingVpnInterfaceId =
2300 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterface.getInterfaceName(), vpnName);
2301 Optional<VpnInterfaceOpDataEntry> vpnInterfaceOptional = SingleTransactionDataBroker
2302 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, existingVpnInterfaceId);
2303 if (!vpnInterfaceOptional.isPresent()) {
2306 List<Adjacency> configVpnAdjacencies = vpnUtil.getAdjacenciesForVpnInterfaceFromConfig(
2307 vpnInterface.getInterfaceName());
2308 if (configVpnAdjacencies == null) {
2309 LOG.debug("There is no adjacency available for vpnInterface:{}", vpnInterface);
2312 List<Adjacency> operationVpnAdjacencies = requireNonNullElse(vpnInterfaceOptional.get()
2313 .augmentation(AdjacenciesOp.class).getAdjacency(), emptyList());
2314 // Due to insufficient rds, some of the extra route wont get processed when it is added.
2315 // The unprocessed adjacencies will be present in config vpn interface DS but will be missing
2316 // in operational DS. These unprocessed adjacencies will be handled below.
2317 // To obtain unprocessed adjacencies, filtering is done by which the missing adjacencies in
2318 // operational DS are retrieved which is used to call addNewAdjToVpnInterface method.
2319 configVpnAdjacencies.stream()
2320 .filter(adjacency -> operationVpnAdjacencies.stream()
2321 .noneMatch(operationalAdjacency ->
2322 Objects.equals(operationalAdjacency.getIpAddress(), adjacency.getIpAddress())))
2323 .forEach(adjacency -> {
2324 LOG.debug("Processing the vpnInterface{} for the Ajacency:{}", vpnInterface, adjacency);
2325 jobCoordinator.enqueueJob("VPNINTERFACE-" + vpnInterface.getInterfaceName(),
2327 // TODO Deal with sequencing — the config tx must only submitted
2328 // if the oper tx goes in
2329 if (vpnUtil.isAdjacencyEligibleToVpn(adjacency, vpnName)) {
2330 List<ListenableFuture<Void>> futures = new ArrayList<>();
2332 txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
2333 //set of prefix used, as entry in prefix-to-interface datastore
2334 // is prerequisite for refresh Fib to avoid race condition leading
2335 // to missing remote next hop in bucket actions on bgp-vpn delete
2336 Set<String> prefixListForRefreshFib = new HashSet<>();
2337 ListenableFuture<Void> configTxFuture =
2338 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
2339 confTx -> addNewAdjToVpnInterface(existingVpnInterfaceId,
2340 primaryRd, adjacency, vpnInterfaceOptional.get().getDpnId(),
2341 operTx, confTx, confTx, prefixListForRefreshFib));
2342 Futures.addCallback(configTxFuture,
2343 new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
2344 MoreExecutors.directExecutor());
2345 futures.add(configTxFuture);
2353 } catch (ReadFailedException e) {
2354 LOG.error("updateVpnInterfacesForUnProcessAdjancencies: Failed to read data store for vpn {} rd {}",
2355 vpnName, primaryRd);
2361 private class PostVpnInterfaceWorker implements FutureCallback<Void> {
2362 private final String interfaceName;
2363 private final boolean add;
2364 private final String txnDestination;
2366 PostVpnInterfaceWorker(String interfaceName, boolean add, String transactionDest) {
2367 this.interfaceName = interfaceName;
2369 this.txnDestination = transactionDest;
2373 public void onSuccess(Void voidObj) {
2375 LOG.debug("VpnInterfaceManager: VrfEntries for {} stored into destination {} successfully",
2376 interfaceName, txnDestination);
2378 LOG.debug("VpnInterfaceManager: VrfEntries for {} removed successfully", interfaceName);
2383 public void onFailure(Throwable throwable) {
2385 LOG.error("VpnInterfaceManager: VrfEntries for {} failed to store into destination {}",
2386 interfaceName, txnDestination, throwable);
2388 LOG.error("VpnInterfaceManager: VrfEntries for {} removal failed", interfaceName, throwable);
2389 vpnUtil.unsetScheduledToRemoveForVpnInterface(interfaceName);
2394 private class VpnInterfaceCallBackHandler implements FutureCallback<Void> {
2395 private final String primaryRd;
2396 private final Set<String> prefixListForRefreshFib;
2398 VpnInterfaceCallBackHandler(String primaryRd, Set<String> prefixListForRefreshFib) {
2399 this.primaryRd = primaryRd;
2400 this.prefixListForRefreshFib = prefixListForRefreshFib;
2404 public void onSuccess(Void voidObj) {
2405 prefixListForRefreshFib.forEach(prefix -> {
2406 fibManager.refreshVrfEntry(primaryRd, prefix);
2411 public void onFailure(Throwable throwable) {
2412 LOG.debug("write Tx config operation failed {}", throwable);