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 org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
11 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
14 import com.google.common.base.Optional;
15 import com.google.common.base.Preconditions;
16 import com.google.common.collect.Iterators;
17 import com.google.common.util.concurrent.FutureCallback;
18 import com.google.common.util.concurrent.Futures;
19 import com.google.common.util.concurrent.ListenableFuture;
20 import com.google.common.util.concurrent.MoreExecutors;
21 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
22 import java.math.BigInteger;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.Iterator;
26 import java.util.List;
28 import java.util.Objects;
29 import java.util.concurrent.ConcurrentHashMap;
30 import java.util.concurrent.ConcurrentLinkedQueue;
31 import java.util.concurrent.ExecutionException;
32 import java.util.function.Consumer;
33 import java.util.function.Predicate;
34 import java.util.stream.Collectors;
35 import javax.annotation.PostConstruct;
36 import javax.annotation.PreDestroy;
37 import javax.inject.Inject;
38 import javax.inject.Singleton;
39 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
40 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
41 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
42 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
43 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
44 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
45 import org.opendaylight.genius.infra.Datastore.Configuration;
46 import org.opendaylight.genius.infra.Datastore.Operational;
47 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
48 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
49 import org.opendaylight.genius.infra.TransactionAdapter;
50 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
51 import org.opendaylight.genius.infra.TypedWriteTransaction;
52 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
53 import org.opendaylight.genius.mdsalutil.NWUtil;
54 import org.opendaylight.genius.mdsalutil.NwConstants;
55 import org.opendaylight.genius.mdsalutil.cache.InstanceIdDataObjectCache;
56 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
57 import org.opendaylight.infrautils.caches.CacheProvider;
58 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
59 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
60 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
61 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
62 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
63 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
64 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
65 import org.opendaylight.netvirt.vpnmanager.api.InterfaceUtils;
66 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
67 import org.opendaylight.netvirt.vpnmanager.arp.responder.ArpResponderHandler;
68 import org.opendaylight.netvirt.vpnmanager.populator.input.L3vpnInput;
69 import org.opendaylight.netvirt.vpnmanager.populator.intfc.VpnPopulator;
70 import org.opendaylight.netvirt.vpnmanager.populator.registry.L3vpnRegistry;
71 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
72 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
73 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
74 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames;
75 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
76 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterfaceBuilder;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.VrfEntryBase;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesBuilder;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.AdjacencyType;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesListKey;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntryBuilder;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntryKey;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTarget;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes.NetworkType;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.portip.port.data.VpnPortipToPort;
116 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
117 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
118 import org.slf4j.Logger;
119 import org.slf4j.LoggerFactory;
122 public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInterface, VpnInterfaceManager> {
124 private static final Logger LOG = LoggerFactory.getLogger(VpnInterfaceManager.class);
125 private static final short DJC_MAX_RETRIES = 3;
127 private final DataBroker dataBroker;
128 private final ManagedNewTransactionRunner txRunner;
129 private final IBgpManager bgpManager;
130 private final IFibManager fibManager;
131 private final IMdsalApiManager mdsalManager;
132 private final IdManagerService idManager;
133 private final OdlInterfaceRpcService ifaceMgrRpcService;
134 private final VpnFootprintService vpnFootprintService;
135 private final IInterfaceManager interfaceManager;
136 private final IVpnManager vpnManager;
137 private final ArpResponderHandler arpResponderHandler;
138 private final JobCoordinator jobCoordinator;
139 private final VpnUtil vpnUtil;
141 private final ConcurrentHashMap<String, Runnable> vpnIntfMap = new ConcurrentHashMap<>();
143 private final Map<String, ConcurrentLinkedQueue<UnprocessedVpnInterfaceData>> unprocessedVpnInterfaces =
144 new ConcurrentHashMap<>();
146 private final InstanceIdDataObjectCache<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryCache;
149 public VpnInterfaceManager(final DataBroker dataBroker,
150 final IBgpManager bgpManager,
151 final IdManagerService idManager,
152 final IMdsalApiManager mdsalManager,
153 final IFibManager fibManager,
154 final OdlInterfaceRpcService ifaceMgrRpcService,
155 final VpnFootprintService vpnFootprintService,
156 final IInterfaceManager interfaceManager,
157 final IVpnManager vpnManager,
158 final ArpResponderHandler arpResponderHandler,
159 final JobCoordinator jobCoordinator,
160 final CacheProvider cacheProvider,
161 final VpnUtil vpnUtil) {
162 super(VpnInterface.class, VpnInterfaceManager.class);
164 this.dataBroker = dataBroker;
165 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
166 this.bgpManager = bgpManager;
167 this.idManager = idManager;
168 this.mdsalManager = mdsalManager;
169 this.fibManager = fibManager;
170 this.ifaceMgrRpcService = ifaceMgrRpcService;
171 this.vpnFootprintService = vpnFootprintService;
172 this.interfaceManager = interfaceManager;
173 this.vpnManager = vpnManager;
174 this.arpResponderHandler = arpResponderHandler;
175 this.jobCoordinator = jobCoordinator;
176 this.vpnUtil = vpnUtil;
178 vpnInstanceOpDataEntryCache = new InstanceIdDataObjectCache<>(VpnInstanceOpDataEntry.class, dataBroker,
179 LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.builder(
180 VpnInstanceOpData.class).child(VpnInstanceOpDataEntry.class).build(), cacheProvider);
183 public Runnable isNotifyTaskQueued(String intfName) {
184 return vpnIntfMap.remove(intfName);
188 public void start() {
189 LOG.info("{} start", getClass().getSimpleName());
190 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
195 public void close() {
197 vpnInstanceOpDataEntryCache.close();
201 protected InstanceIdentifier<VpnInterface> getWildCardPath() {
202 return InstanceIdentifier.create(VpnInterfaces.class).child(VpnInterface.class);
206 protected VpnInterfaceManager getDataTreeChangeListener() {
207 return VpnInterfaceManager.this;
211 public void add(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface) {
212 LOG.info("add: intfName {} onto vpnName {}",
213 vpnInterface.getName(),
214 VpnHelper.getVpnInterfaceVpnInstanceNamesString(vpnInterface.getVpnInstanceNames()));
215 addVpnInterface(identifier, vpnInterface, null, null);
218 private boolean canHandleNewVpnInterface(final InstanceIdentifier<VpnInterface> identifier,
219 final VpnInterface vpnInterface, String vpnName) {
220 synchronized (vpnName.intern()) {
221 if (isVpnInstanceReady(vpnName)) {
224 addToUnprocessedVpnInterfaces(identifier, vpnInterface, vpnName);
229 // TODO Clean up the exception handling
230 @SuppressWarnings("checkstyle:IllegalCatch")
231 private void addVpnInterface(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface,
232 final List<Adjacency> oldAdjs, final List<Adjacency> newAdjs) {
233 for (VpnInstanceNames vpnInterfaceVpnInstance : vpnInterface.getVpnInstanceNames()) {
234 String vpnName = vpnInterfaceVpnInstance.getVpnName();
235 addVpnInterfaceCall(identifier, vpnInterface, oldAdjs, newAdjs, vpnName);
239 private void addVpnInterfaceCall(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface,
240 final List<Adjacency> oldAdjs, final List<Adjacency> newAdjs, String vpnName) {
241 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
242 final String interfaceName = key.getName();
244 if (!canHandleNewVpnInterface(identifier, vpnInterface, vpnName)) {
245 LOG.error("add: VpnInstance {} for vpnInterface {} not ready, holding on ",
246 vpnName, vpnInterface.getName());
249 InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier = VpnUtil
250 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
251 List<Adjacency> copyOldAdjs = null;
252 if (oldAdjs != null) {
253 copyOldAdjs = new ArrayList<>();
254 copyOldAdjs.addAll(oldAdjs);
256 List<Adjacency> copyNewAdjs = null;
257 if (newAdjs != null) {
258 copyNewAdjs = new ArrayList<>();
259 copyNewAdjs.addAll(newAdjs);
261 addVpnInterfaceToVpn(vpnInterfaceOpIdentifier, vpnInterface, copyOldAdjs, copyNewAdjs, identifier, vpnName);
264 private void addVpnInterfaceToVpn(final InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier,
265 final VpnInterface vpnInterface, final List<Adjacency> oldAdjs,
266 final List<Adjacency> newAdjs,
267 final InstanceIdentifier<VpnInterface> identifier, String vpnName) {
268 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
269 final String interfaceName = key.getName();
270 String primaryRd = vpnUtil.getPrimaryRd(vpnName);
271 if (!vpnUtil.isVpnPendingDelete(primaryRd)) {
272 Interface interfaceState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker, interfaceName);
273 boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(vpnName);
274 if (interfaceState != null) {
276 final BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(interfaceState);
277 final int ifIndex = interfaceState.getIfIndex();
278 jobCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName, () -> {
279 // TODO Deal with sequencing — the config tx must only submitted if the oper tx goes in
280 // (the inventory tx goes in last)
281 List<ListenableFuture<Void>> futures = new ArrayList<>();
282 ListenableFuture<Void> confFuture =
283 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
284 confTx -> futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
285 operTx -> futures.add(
286 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, invTx -> {
288 "addVpnInterface: VPN Interface add event - intfName {} vpnName {}"
290 vpnInterface.getName(), vpnName, vpnInterface.getDpnId());
291 processVpnInterfaceUp(dpnId, vpnInterface, primaryRd, ifIndex, false,
292 confTx, operTx, invTx, interfaceState, vpnName);
293 if (oldAdjs != null && !oldAdjs.equals(newAdjs)) {
294 LOG.info("addVpnInterface: Adjacency changed upon VPNInterface {}"
295 + " Update for swapping VPN {} case.", interfaceName, vpnName);
296 if (newAdjs != null) {
297 for (Adjacency adj : newAdjs) {
298 if (oldAdjs.contains(adj)) {
301 if (!isBgpVpnInternetVpn
302 || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
303 addNewAdjToVpnInterface(vpnInterfaceOpIdentifier,
304 primaryRd, adj, dpnId, operTx, confTx, invTx);
309 for (Adjacency adj : oldAdjs) {
310 if (!isBgpVpnInternetVpn
311 || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
312 delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId,
318 futures.add(confFuture);
319 Futures.addCallback(confFuture, new PostVpnInterfaceWorker(interfaceName, true, "Config"),
320 MoreExecutors.directExecutor());
321 LOG.info("addVpnInterface: Addition of interface {} in VPN {} on dpn {}"
322 + " processed successfully", interfaceName, vpnName, dpnId);
325 } catch (NumberFormatException | IllegalStateException e) {
326 LOG.error("addVpnInterface: Unable to retrieve dpnId from interface operational data store for "
327 + "interface {}. Interface addition on vpn {} failed", interfaceName,
331 } else if (Boolean.TRUE.equals(vpnInterface.isRouterInterface())) {
332 jobCoordinator.enqueueJob("VPNINTERFACE-" + vpnInterface.getName(),
334 ListenableFuture<Void> future =
335 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
336 createFibEntryForRouterInterface(primaryRd, vpnInterface, interfaceName,
338 LOG.info("addVpnInterface: Router interface {} for vpn {} on dpn {}", interfaceName,
339 vpnName, vpnInterface.getDpnId());
341 ListenableFutures.addErrorLogging(future, LOG,
342 "Error creating FIB entry for interface {} on VPN {}", vpnInterface.getName(), vpnName);
343 return Collections.singletonList(future);
346 LOG.info("addVpnInterface: Handling addition of VPN interface {} on vpn {} skipped as interfaceState"
347 + " is not available", interfaceName, vpnName);
350 LOG.error("addVpnInterface: Handling addition of VPN interface {} on vpn {} dpn {} skipped"
351 + " as vpn is pending delete", interfaceName, vpnName,
352 vpnInterface.getDpnId());
356 // "Unconditional wait" and "Wait not in loop" wrt the VpnNotifyTask below - suppressing the FB violation -
357 // see comments below.
358 @SuppressFBWarnings({"UW_UNCOND_WAIT", "WA_NOT_IN_LOOP"})
359 protected void processVpnInterfaceUp(final BigInteger dpId, VpnInterface vpnInterface, final String primaryRd,
360 final int lportTag, boolean isInterfaceUp,
361 TypedWriteTransaction<Configuration> writeConfigTxn,
362 TypedWriteTransaction<Operational> writeOperTxn,
363 TypedReadWriteTransaction<Configuration> writeInvTxn,
364 Interface interfaceState,
365 final String vpnName) throws ExecutionException, InterruptedException {
366 final String interfaceName = vpnInterface.getName();
367 Optional<VpnInterfaceOpDataEntry> optOpVpnInterface = vpnUtil.getVpnInterfaceOpDataEntry(interfaceName,
369 VpnInterfaceOpDataEntry opVpnInterface = optOpVpnInterface.isPresent() ? optOpVpnInterface.get() : null;
370 boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(vpnName);
371 if (!isInterfaceUp) {
372 LOG.info("processVpnInterfaceUp: Binding vpn service to interface {} onto dpn {} for vpn {}",
373 interfaceName, dpId, vpnName);
374 long vpnId = vpnUtil.getVpnId(vpnName);
375 if (vpnId == VpnConstants.INVALID_ID) {
376 LOG.warn("processVpnInterfaceUp: VpnInstance to VPNId mapping not available for VpnName {}"
377 + " processing vpninterface {} on dpn {}, bailing out now.", vpnName, interfaceName,
382 boolean waitForVpnInterfaceOpRemoval = false;
383 if (opVpnInterface != null) {
384 String opVpnName = opVpnInterface.getVpnInstanceName();
385 String primaryInterfaceIp = null;
386 if (opVpnName.equals(vpnName)) {
387 // Please check if the primary VRF Entry does not exist for VPNInterface
388 // If so, we have to process ADD, as this might be a DPN Restart with Remove and Add triggered
390 // However, if the primary VRF Entry for this VPNInterface exists, please continue bailing out !
391 List<Adjacency> adjs = vpnUtil.getAdjacenciesForVpnInterfaceFromConfig(interfaceName);
393 LOG.error("processVpnInterfaceUp: VPN Interface {} on dpn {} for vpn {} failed as adjacencies"
394 + " for this vpn interface could not be obtained", interfaceName, dpId,
398 for (Adjacency adj : adjs) {
399 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
400 primaryInterfaceIp = adj.getIpAddress();
404 if (primaryInterfaceIp == null) {
405 LOG.error("processVpnInterfaceUp: VPN Interface {} addition on dpn {} for vpn {} failed"
406 + " as primary adjacency for this vpn interface could not be obtained", interfaceName,
410 // Get the rd of the vpn instance
411 VrfEntry vrf = vpnUtil.getVrfEntry(primaryRd, primaryInterfaceIp);
413 LOG.error("processVpnInterfaceUp: VPN Interface {} on dpn {} for vpn {} already provisioned ,"
414 + " bailing out from here.", interfaceName, dpId, vpnName);
417 waitForVpnInterfaceOpRemoval = true;
419 LOG.error("processVpnInterfaceUp: vpn interface {} to go to configured vpn {} on dpn {},"
420 + " but in operational vpn {}", interfaceName, vpnName, dpId, opVpnName);
423 if (!waitForVpnInterfaceOpRemoval) {
424 // Add the VPNInterface and quit
425 vpnFootprintService.updateVpnToDpnMapping(dpId, vpnName, primaryRd, interfaceName,
426 null/*ipAddressSourceValuePair*/,
428 processVpnInterfaceAdjacencies(dpId, lportTag, vpnName, primaryRd, interfaceName,
429 vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState);
430 if (!isBgpVpnInternetVpn) {
431 vpnUtil.bindService(vpnName, interfaceName, false /*isTunnelInterface*/);
433 LOG.info("processVpnInterfaceUp: Plumbed vpn interface {} onto dpn {} for vpn {}", interfaceName,
435 if (interfaceManager.isExternalInterface(interfaceName)) {
436 processExternalVpnInterface(interfaceName, vpnName, dpId, lportTag,
437 NwConstants.ADD_FLOW);
442 // FIB didn't get a chance yet to clean up this VPNInterface
443 // Let us give it a chance here !
444 LOG.info("processVpnInterfaceUp: Trying to add VPN Interface {} on dpn {} for vpn {},"
445 + " but waiting for FIB to clean up! ", interfaceName, dpId, vpnName);
447 Runnable notifyTask = new VpnNotifyTask();
448 synchronized (notifyTask) {
449 // Per FB's "Unconditional wait" violation, the code should really verify that the condition it
450 // intends to wait for is not already satisfied before calling wait. However the VpnNotifyTask is
451 // published here while holding the lock on it so this path will hit the wait before notify can be
453 vpnIntfMap.put(interfaceName, notifyTask);
455 notifyTask.wait(VpnConstants.MAX_WAIT_TIME_IN_MILLISECONDS);
456 } catch (InterruptedException e) {
461 vpnIntfMap.remove(interfaceName);
464 if (opVpnInterface != null) {
465 LOG.warn("processVpnInterfaceUp: VPN Interface {} removal on dpn {} for vpn {}"
466 + " by FIB did not complete on time," + " bailing addition ...", interfaceName,
468 vpnUtil.unsetScheduledToRemoveForVpnInterface(interfaceName);
471 // VPNInterface got removed, proceed with Add
472 LOG.info("processVpnInterfaceUp: Continuing to plumb vpn interface {} onto dpn {} for vpn {}",
473 interfaceName, dpId, vpnName);
474 vpnFootprintService.updateVpnToDpnMapping(dpId, vpnName, primaryRd, interfaceName,
475 null/*ipAddressSourceValuePair*/,
477 processVpnInterfaceAdjacencies(dpId, lportTag, vpnName, primaryRd, interfaceName,
478 vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState);
479 if (!isBgpVpnInternetVpn) {
480 vpnUtil.bindService(vpnName, interfaceName, false/*isTunnelInterface*/);
482 LOG.info("processVpnInterfaceUp: Plumbed vpn interface {} onto dpn {} for vpn {} after waiting for"
483 + " FIB to clean up", interfaceName, dpId, vpnName);
484 if (interfaceManager.isExternalInterface(interfaceName)) {
485 processExternalVpnInterface(interfaceName, vpnName, dpId,
486 lportTag, NwConstants.ADD_FLOW);
490 // Interface is retained in the DPN, but its Link Up.
491 // Advertise prefixes again for this interface to BGP
492 InstanceIdentifier<VpnInterface> identifier =
493 VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getName());
494 InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier =
495 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
496 advertiseAdjacenciesForVpnToBgp(primaryRd, dpId, vpnInterfaceOpIdentifier, vpnName, interfaceName);
497 // Perform similar operation as interface add event for extraroutes.
498 InstanceIdentifier<Adjacencies> path = identifier.augmentation(Adjacencies.class);
499 Optional<Adjacencies> optAdjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
500 LogicalDatastoreType.CONFIGURATION, path);
501 if (!optAdjacencies.isPresent()) {
502 LOG.trace("No config adjacencies present for vpninterface {}", vpnInterface);
505 List<Adjacency> adjacencies = optAdjacencies.get().getAdjacency();
506 for (Adjacency adjacency : adjacencies) {
507 if (adjacency.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
510 // if BGPVPN Internet, filter only IPv6 Adjacencies
511 if (isBgpVpnInternetVpn && !vpnUtil.isAdjacencyEligibleToVpnInternet(adjacency)) {
514 addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adjacency,
515 dpId, writeOperTxn, writeConfigTxn, writeInvTxn);
517 } catch (ReadFailedException e) {
518 LOG.error("processVpnInterfaceUp: Failed to read data store for interface {} vpn {} rd {} dpn {}",
519 interfaceName, vpnName, primaryRd, dpId);
524 private void processExternalVpnInterface(String interfaceName, String vpnName, BigInteger dpId,
525 int lportTag, int addOrRemove) {
528 // vpn instance of ext-net interface is the network-id
529 extNetworkId = new Uuid(vpnName);
530 } catch (IllegalArgumentException e) {
531 LOG.error("processExternalVpnInterface: VPN instance {} is not Uuid. Processing external vpn interface {}"
532 + " on dpn {} failed", vpnName, interfaceName, dpId);
536 List<Uuid> routerIds = vpnUtil.getExternalNetworkRouterIds(extNetworkId);
537 if (routerIds == null || routerIds.isEmpty()) {
538 LOG.info("processExternalVpnInterface: No router is associated with {}."
539 + " Bailing out of processing external vpn interface {} on dpn {} for vpn {}",
540 extNetworkId.getValue(), interfaceName, dpId, vpnName);
544 LOG.info("processExternalVpnInterface: Router-ids {} associated with exernal vpn-interface {} on dpn {}"
545 + " for vpn {}", routerIds, interfaceName, dpId, vpnName);
546 for (Uuid routerId : routerIds) {
547 String routerName = routerId.getValue();
548 BigInteger primarySwitch = vpnUtil.getPrimarySwitchForRouter(routerName);
549 if (Objects.equals(primarySwitch, dpId)) {
550 Routers router = vpnUtil.getExternalRouter(routerName);
551 if (router != null) {
552 if (addOrRemove == NwConstants.ADD_FLOW) {
553 vpnManager.addArpResponderFlowsToExternalNetworkIps(routerName,
554 VpnUtil.getIpsListFromExternalIps(router.getExternalIps()), router.getExtGwMacAddress(),
555 dpId, interfaceName, lportTag);
557 vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerName,
558 VpnUtil.getIpsListFromExternalIps(router.getExternalIps()),
559 dpId, interfaceName, lportTag);
562 LOG.error("processExternalVpnInterface: No external-router found for router-id {}. Bailing out of"
563 + " processing external vpn-interface {} on dpn {} for vpn {}", routerName,
564 interfaceName, dpId, vpnName);
570 // TODO Clean up the exception handling
571 @SuppressWarnings("checkstyle:IllegalCatch")
572 private void advertiseAdjacenciesForVpnToBgp(final String rd, BigInteger dpnId,
573 final InstanceIdentifier<VpnInterfaceOpDataEntry> identifier,
574 String vpnName, String interfaceName) {
576 LOG.error("advertiseAdjacenciesForVpnFromBgp: Unable to recover rd for interface {} on dpn {} in vpn {}",
577 interfaceName, dpnId, vpnName);
580 if (rd.equals(vpnName)) {
581 LOG.info("advertiseAdjacenciesForVpnFromBgp: Ignoring BGP advertisement for interface {} on dpn {}"
582 + " as it is in internal vpn{} with rd {}", interfaceName, dpnId, vpnName, rd);
586 LOG.info("advertiseAdjacenciesForVpnToBgp: Advertising interface {} on dpn {} in vpn {} with rd {} ",
587 interfaceName, dpnId, vpnName, rd);
589 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
590 if (nextHopIp == null) {
591 LOG.error("advertiseAdjacenciesForVpnToBgp: NextHop for interface {} on dpn {} is null,"
592 + " returning from advertising route with rd {} vpn {} to bgp", interfaceName, dpnId,
599 InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
600 Optional<AdjacenciesOp> adjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
601 LogicalDatastoreType.OPERATIONAL, path);
602 if (adjacencies.isPresent()) {
603 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
604 if (!nextHops.isEmpty()) {
605 LOG.debug("advertiseAdjacenciesForVpnToBgp: NextHops are {} for interface {} on dpn {} for vpn {}"
606 + " rd {}", nextHops, interfaceName, dpnId, vpnName, rd);
607 VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(rd);
608 long l3vni = vpnInstanceOpData.getL3vni();
609 VrfEntry.EncapType encapType = VpnUtil.isL3VpnOverVxLan(l3vni)
610 ? VrfEntry.EncapType.Vxlan : VrfEntry.EncapType.Mplsgre;
611 for (Adjacency nextHop : nextHops) {
612 if (nextHop.getAdjacencyType() == AdjacencyType.ExtraRoute) {
615 String gatewayMac = null;
617 if (VpnUtil.isL3VpnOverVxLan(l3vni)) {
618 final VpnPortipToPort gwPort = vpnUtil.getNeutronPortFromVpnPortFixedIp(
619 vpnInstanceOpData.getVpnInstanceName(), nextHop.getIpAddress());
620 gatewayMac = arpResponderHandler.getGatewayMacAddressForInterface(gwPort, interfaceName)
623 label = nextHop.getLabel();
626 LOG.info("VPN ADVERTISE: advertiseAdjacenciesForVpnToBgp: Adding Fib Entry rd {} prefix {}"
627 + " nexthop {} label {}", rd, nextHop.getIpAddress(), nextHopIp, label);
628 bgpManager.advertisePrefix(rd, nextHop.getMacAddress(), nextHop.getIpAddress(), nextHopIp,
629 encapType, (int)label, l3vni, 0 /*l2vni*/,
631 LOG.info("VPN ADVERTISE: advertiseAdjacenciesForVpnToBgp: Added Fib Entry rd {} prefix {}"
632 + " nexthop {} label {} for interface {} on dpn {} for vpn {}", rd,
633 nextHop.getIpAddress(), nextHopIp, label, interfaceName, dpnId, vpnName);
634 } catch (Exception e) {
635 LOG.error("advertiseAdjacenciesForVpnToBgp: Failed to advertise prefix {} in vpn {}"
636 + " with rd {} for interface {} on dpn {}", nextHop.getIpAddress(), vpnName, rd,
637 interfaceName, dpnId, e);
642 } catch (ReadFailedException e) {
643 LOG.error("advertiseAdjacenciesForVpnToBgp: Failed to read data store for interface {} dpn {} nexthop {}"
644 + "vpn {} rd {}", interfaceName, dpnId, nextHopIp, vpnName, rd);
648 // TODO Clean up the exception handling
649 @SuppressWarnings("checkstyle:IllegalCatch")
650 private void withdrawAdjacenciesForVpnFromBgp(final InstanceIdentifier<VpnInterfaceOpDataEntry> identifier,
651 String vpnName, String interfaceName, TypedWriteTransaction<Configuration> writeConfigTxn,
652 TypedWriteTransaction<Operational> writeOperTx) {
654 InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
655 String rd = vpnUtil.getVpnRd(interfaceName);
657 LOG.error("withdrawAdjacenciesForVpnFromBgp: Unable to recover rd for interface {} in vpn {}",
658 interfaceName, vpnName);
661 if (rd.equals(vpnName)) {
663 "withdrawAdjacenciesForVpnFromBgp: Ignoring BGP withdrawal for interface {} as it is in "
664 + "internal vpn{} with rd {}", interfaceName, vpnName, rd);
668 LOG.info("withdrawAdjacenciesForVpnFromBgp: For interface {} in vpn {} with rd {}", interfaceName,
670 Optional<AdjacenciesOp> adjacencies = Optional.absent();
672 adjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
674 } catch (ReadFailedException e) {
675 LOG.error("withdrawAdjacenciesForVpnFromBgp: Failed to read data store for interface {} vpn {}",
676 interfaceName, vpnName);
678 if (adjacencies.isPresent()) {
679 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
681 if (!nextHops.isEmpty()) {
682 LOG.trace("withdrawAdjacenciesForVpnFromBgp: NextHops are {} for interface {} in vpn {} rd {}",
683 nextHops, interfaceName, vpnName, rd);
684 for (Adjacency nextHop : nextHops) {
686 if (nextHop.getAdjacencyType() != AdjacencyType.ExtraRoute) {
687 LOG.info("VPN WITHDRAW: withdrawAdjacenciesForVpnFromBgp: Removing Fib Entry rd {}"
688 + " prefix {} for interface {} in vpn {}", rd, nextHop.getIpAddress(),
689 interfaceName, vpnName);
690 bgpManager.withdrawPrefix(rd, nextHop.getIpAddress());
691 LOG.info("VPN WITHDRAW: withdrawAdjacenciesForVpnFromBgp: Removed Fib Entry rd {}"
692 + " prefix {} for interface {} in vpn {}", rd, nextHop.getIpAddress(),
693 interfaceName, vpnName);
695 // Perform similar operation as interface delete event for extraroutes.
696 String allocatedRd = nextHop.getVrfId();
697 for (String nh : nextHop.getNextHopIpList()) {
698 deleteExtraRouteFromCurrentAndImportingVpns(
699 vpnName, nextHop.getIpAddress(), nh, allocatedRd, interfaceName, writeConfigTxn,
703 } catch (Exception e) {
704 LOG.error("withdrawAdjacenciesForVpnFromBgp: Failed to withdraw prefix {} in vpn {} with rd {}"
705 + " for interface {} ", nextHop.getIpAddress(), vpnName, rd, interfaceName, e);
712 @SuppressWarnings("checkstyle:IllegalCatch")
713 protected void processVpnInterfaceAdjacencies(BigInteger dpnId, final int lportTag, String vpnName,
714 String primaryRd, String interfaceName, final long vpnId,
715 TypedWriteTransaction<Configuration> writeConfigTxn,
716 TypedWriteTransaction<Operational> writeOperTxn,
717 TypedReadWriteTransaction<Configuration> writeInvTxn,
718 Interface interfaceState)
719 throws ExecutionException, InterruptedException {
720 InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
722 Optional<VpnInterface> vpnInteface = Optional.absent();
724 vpnInteface = SingleTransactionDataBroker.syncReadOptional(dataBroker,
725 LogicalDatastoreType.CONFIGURATION, identifier);
726 } catch (ReadFailedException e) {
727 LOG.error("processVpnInterfaceAdjacencies: Failed to read data store for interface {} vpn {} rd {}"
728 + "dpn {}", interfaceName, vpnName, primaryRd, dpnId);
730 Uuid intfnetworkUuid = null;
731 NetworkType networkType = null;
732 Long segmentationId = Long.valueOf(-1);
733 Adjacencies adjacencies = null;
734 if (vpnInteface.isPresent()) {
735 intfnetworkUuid = vpnInteface.get().getNetworkId();
736 networkType = vpnInteface.get().getNetworkType();
737 segmentationId = vpnInteface.get().getSegmentationId();
738 adjacencies = vpnInteface.get().augmentation(Adjacencies.class);
739 if (adjacencies == null) {
740 addVpnInterfaceToOperational(vpnName, interfaceName, dpnId, null/*adjacencies*/, lportTag,
741 null/*gwMac*/, writeOperTxn);
745 // Get the rd of the vpn instance
746 String nextHopIp = null;
748 nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
749 } catch (Exception e) {
750 LOG.error("processVpnInterfaceAdjacencies: Unable to retrieve endpoint ip address for "
751 + "dpnId {} for vpnInterface {} vpnName {}", dpnId, interfaceName, vpnName);
753 List<String> nhList = new ArrayList<>();
754 if (nextHopIp != null) {
755 nhList.add(nextHopIp);
756 LOG.debug("processVpnInterfaceAdjacencies: NextHop for interface {} on dpn {} in vpn {} is {}",
757 interfaceName, dpnId, vpnName, nhList);
759 Optional<String> gwMac = Optional.absent();
760 String vpnInterfaceSubnetGwMacAddress = null;
761 VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(primaryRd);
762 Long l3vni = vpnInstanceOpData.getL3vni();
763 boolean isL3VpnOverVxLan = VpnUtil.isL3VpnOverVxLan(l3vni);
764 VrfEntry.EncapType encapType = isL3VpnOverVxLan ? VrfEntry.EncapType.Vxlan : VrfEntry.EncapType.Mplsgre;
765 VpnPopulator registeredPopulator = L3vpnRegistry.getRegisteredPopulator(encapType);
766 List<Adjacency> nextHops = (adjacencies != null) ? adjacencies.getAdjacency() : Collections.emptyList();
767 List<Adjacency> value = new ArrayList<>();
768 for (Adjacency nextHop : nextHops) {
769 String rd = primaryRd;
770 String nexthopIpValue = nextHop.getIpAddress().split("/")[0];
771 if (vpnInstanceOpData.getBgpvpnType() == VpnInstanceOpDataEntry.BgpvpnType.BGPVPNInternet
772 && NWUtil.isIpv4Address(nexthopIpValue)) {
773 String prefix = nextHop.getIpAddress() == null ? "null" :
774 VpnUtil.getIpPrefix(nextHop.getIpAddress());
775 LOG.debug("processVpnInterfaceAdjacencies: UnsupportedOperation : Not Adding prefix {} to interface {}"
776 + " as InternetVpn has an IPV4 address {}", prefix, interfaceName, vpnName);
779 if (nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
780 String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
781 Prefixes.PrefixCue prefixCue = nextHop.isPhysNetworkFunc()
782 ? Prefixes.PrefixCue.PhysNetFunc : Prefixes.PrefixCue.None;
783 LOG.debug("processVpnInterfaceAdjacencies: Adding prefix {} to interface {} with nextHops {} on dpn {}"
784 + " for vpn {}", prefix, interfaceName, nhList, dpnId, vpnName);
786 Prefixes prefixes = (intfnetworkUuid != null)
787 ? VpnUtil.getPrefixToInterface(dpnId, interfaceName, prefix, intfnetworkUuid ,networkType,
788 segmentationId, prefixCue) :
789 VpnUtil.getPrefixToInterface(dpnId, interfaceName, prefix, prefixCue);
790 writeOperTxn.merge(VpnUtil.getPrefixToInterfaceIdentifier(
791 vpnUtil.getVpnId(vpnName), prefix), prefixes, true);
792 final Uuid subnetId = nextHop.getSubnetId();
794 String gatewayIp = nextHop.getSubnetGatewayIp();
795 if (gatewayIp == null) {
796 Optional<String> gatewayIpOptional = vpnUtil.getVpnSubnetGatewayIp(subnetId);
797 if (gatewayIpOptional.isPresent()) {
798 gatewayIp = gatewayIpOptional.get();
802 if (gatewayIp != null) {
803 gwMac = getMacAddressForSubnetIp(vpnName, interfaceName, gatewayIp);
804 if (gwMac.isPresent()) {
805 // A valid mac-address is available for this subnet-gateway-ip
806 // Use this for programming ARP_RESPONDER table here. And save this
807 // info into vpnInterface operational, so it can used in VrfEntryProcessor
808 // to populate L3_GW_MAC_TABLE there.
809 arpResponderHandler.addArpResponderFlow(dpnId, lportTag, interfaceName,
810 gatewayIp, gwMac.get());
811 vpnInterfaceSubnetGwMacAddress = gwMac.get();
813 // A valid mac-address is not available for this subnet-gateway-ip
814 // Use the connected-mac-address to configure ARP_RESPONDER Table.
815 // Save this connected-mac-address as gateway-mac-address for the
816 // VrfEntryProcessor to use this later to populate the L3_GW_MAC_TABLE.
817 gwMac = InterfaceUtils.getMacAddressFromInterfaceState(interfaceState);
818 if (gwMac.isPresent()) {
819 vpnUtil.setupGwMacIfExternalVpn(dpnId, interfaceName, vpnId, writeInvTxn,
820 NwConstants.ADD_FLOW, gwMac.get());
821 arpResponderHandler.addArpResponderFlow(dpnId, lportTag, interfaceName,
822 gatewayIp, gwMac.get());
824 LOG.error("processVpnInterfaceAdjacencies: Gateway MAC for subnet ID {} could not be "
825 + "obtained, cannot create ARP responder flow for interface name {}, vpnName {}, "
827 subnetId, interfaceName, vpnName, gatewayIp);
831 LOG.warn("processVpnInterfaceAdjacencies: Gateway IP for subnet ID {} could not be obtained, "
832 + "cannot create ARP responder flow for interface name {}, vpnName {}",
833 subnetId, interfaceName, vpnName);
834 gwMac = InterfaceUtils.getMacAddressFromInterfaceState(interfaceState);
836 LOG.info("processVpnInterfaceAdjacencies: Added prefix {} to interface {} with nextHops {} on dpn {}"
837 + " for vpn {}", prefix, interfaceName, nhList, dpnId, vpnName);
839 //Extra route adjacency
840 String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
841 String vpnPrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
842 synchronized (vpnPrefixKey.intern()) {
843 java.util.Optional<String> rdToAllocate = vpnUtil
844 .allocateRdForExtraRouteAndUpdateUsedRdsMap(vpnId, null, prefix, vpnName,
845 nextHop.getNextHopIpList().get(0), dpnId);
846 if (rdToAllocate.isPresent()) {
847 rd = rdToAllocate.get();
848 LOG.info("processVpnInterfaceAdjacencies: The rd {} is allocated for the extraroute {}",
851 LOG.error("processVpnInterfaceAdjacencies: No rds to allocate extraroute {}", prefix);
855 LOG.info("processVpnInterfaceAdjacencies: Added prefix {} and nextHopList {} as extra-route for vpn{}"
856 + " interface {} on dpn {}", nextHop.getIpAddress(), nextHop.getNextHopIpList(), vpnName,
857 interfaceName, dpnId);
859 // Please note that primary adjacency will use a subnet-gateway-mac-address that
860 // can be different from the gateway-mac-address within the VRFEntry as the
861 // gateway-mac-address is a superset.
862 RouteOrigin origin = nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency ? RouteOrigin.LOCAL
863 : RouteOrigin.STATIC;
864 L3vpnInput input = new L3vpnInput().setNextHop(nextHop).setRd(rd).setVpnName(vpnName)
865 .setInterfaceName(interfaceName).setNextHopIp(nextHopIp).setPrimaryRd(primaryRd)
866 .setSubnetGatewayMacAddress(vpnInterfaceSubnetGwMacAddress).setRouteOrigin(origin);
867 Adjacency operationalAdjacency = null;
869 operationalAdjacency = registeredPopulator.createOperationalAdjacency(input);
870 } catch (NullPointerException e) {
871 LOG.error("processVpnInterfaceAdjacencies: failed to create operational adjacency: input: {}, {}",
872 input, e.getMessage());
875 if (nextHop.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
876 vpnManager.addExtraRoute(vpnName, nextHop.getIpAddress(), nextHop.getNextHopIpList().get(0), rd,
877 vpnName, l3vni, origin,
878 interfaceName, operationalAdjacency, encapType, writeConfigTxn);
880 value.add(operationalAdjacency);
883 AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(value);
884 addVpnInterfaceToOperational(vpnName, interfaceName, dpnId, aug, lportTag,
885 gwMac.isPresent() ? gwMac.get() : null, writeOperTxn);
887 L3vpnInput input = new L3vpnInput().setNextHopIp(nextHopIp).setL3vni(l3vni).setPrimaryRd(primaryRd)
888 .setGatewayMac(gwMac.orNull()).setInterfaceName(interfaceName)
889 .setVpnName(vpnName).setDpnId(dpnId).setEncapType(encapType);
891 for (Adjacency nextHop : aug.getAdjacency()) {
892 // Adjacencies other than primary Adjacencies are handled in the addExtraRoute call above.
893 if (nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
894 RouteOrigin origin = nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency ? RouteOrigin.LOCAL
895 : RouteOrigin.STATIC;
896 input.setNextHop(nextHop).setRd(nextHop.getVrfId()).setRouteOrigin(origin);
897 registeredPopulator.populateFib(input, writeConfigTxn);
902 private void addVpnInterfaceToOperational(String vpnName, String interfaceName, BigInteger dpnId, AdjacenciesOp aug,
903 long lportTag, String gwMac,
904 TypedWriteTransaction<Operational> writeOperTxn) {
905 VpnInterfaceOpDataEntry opInterface =
906 VpnUtil.getVpnInterfaceOpDataEntry(interfaceName, vpnName, aug, dpnId, lportTag, gwMac);
907 InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId = VpnUtil
908 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
909 writeOperTxn.put(interfaceId, opInterface, CREATE_MISSING_PARENTS);
910 LOG.info("addVpnInterfaceToOperational: Added VPN Interface {} on dpn {} vpn {} to operational datastore",
911 interfaceName, dpnId, vpnName);
914 // TODO Clean up the exception handling
915 @SuppressWarnings("checkstyle:IllegalCatch")
916 public void updateVpnInterfaceOnTepAdd(VpnInterfaceOpDataEntry vpnInterface,
917 StateTunnelList stateTunnelList,
918 TypedWriteTransaction<Configuration> writeConfigTxn,
919 TypedWriteTransaction<Operational> writeOperTxn) {
921 String srcTepIp = stateTunnelList.getSrcInfo().getTepIp().stringValue();
922 BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
923 AdjacenciesOp adjacencies = vpnInterface.augmentation(AdjacenciesOp.class);
924 List<Adjacency> adjList = adjacencies != null ? adjacencies.getAdjacency() : new ArrayList<>();
925 if (adjList.isEmpty()) {
926 LOG.trace("updateVpnInterfaceOnTepAdd: Adjacencies are empty for vpnInterface {} on dpn {}",
927 vpnInterface, srcDpnId);
930 String prefix = null;
932 List<Adjacency> value = new ArrayList<>();
933 boolean isNextHopAddReqd = false;
934 String vpnName = vpnInterface.getVpnInstanceName();
935 long vpnId = vpnUtil.getVpnId(vpnName);
936 String primaryRd = vpnUtil.getPrimaryRd(vpnName);
937 LOG.info("updateVpnInterfaceOnTepAdd: AdjacencyList for interface {} on dpn {} vpn {} is {}",
938 vpnInterface.getName(), vpnInterface.getDpnId(),
939 vpnInterface.getVpnInstanceName(), adjList);
940 for (Adjacency adj : adjList) {
941 String rd = adj.getVrfId();
942 rd = rd != null ? rd : vpnName;
943 prefix = adj.getIpAddress();
944 label = adj.getLabel();
945 List<String> nhList = Collections.singletonList(srcTepIp);
946 List<String> nextHopList = adj.getNextHopIpList();
947 // If TEP is added , update the nexthop of primary adjacency.
948 // Secondary adj nexthop is already pointing to primary adj IP address.
949 if (nextHopList != null && !nextHopList.isEmpty()) {
950 /* everything right already */
952 isNextHopAddReqd = true;
955 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
956 value.add(new AdjacencyBuilder(adj).setNextHopIpList(nhList).build());
958 Optional<VrfEntry> vrfEntryOptional = FibHelper.getVrfEntry(dataBroker, primaryRd, prefix);
959 if (!vrfEntryOptional.isPresent()) {
962 nhList = FibHelper.getNextHopListFromRoutePaths(vrfEntryOptional.get());
963 if (!nhList.contains(srcTepIp)) {
964 nhList.add(srcTepIp);
965 isNextHopAddReqd = true;
970 if (isNextHopAddReqd) {
971 updateLabelMapper(label, nhList);
972 LOG.info("updateVpnInterfaceOnTepAdd: Updated label mapper : label {} dpn {} prefix {} nexthoplist {}"
973 + " vpn {} vpnid {} rd {} interface {}", label, srcDpnId , prefix, nhList,
974 vpnInterface.getVpnInstanceName(), vpnId, rd, vpnInterface.getName());
975 // Update the VRF entry with nextHop
976 fibManager.updateRoutePathForFibEntry(primaryRd, prefix, srcTepIp,
977 label, true, TransactionAdapter.toWriteTransaction(writeConfigTxn));
979 //Get the list of VPN's importing this route(prefix) .
980 // Then update the VRF entry with nhList
981 List<VpnInstanceOpDataEntry> vpnsToImportRoute = vpnUtil.getVpnsImportingMyRoute(vpnName);
982 for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
983 String vpnRd = vpn.getVrfId();
985 fibManager.updateRoutePathForFibEntry(vpnRd, prefix,
986 srcTepIp, label, true, TransactionAdapter.toWriteTransaction(writeConfigTxn));
987 LOG.info("updateVpnInterfaceOnTepAdd: Exported route with rd {} prefix {} nhList {} label {}"
988 + " interface {} dpn {} from vpn {} to VPN {} vpnRd {}", rd, prefix, nhList, label,
989 vpnInterface.getName(), srcDpnId, vpnName,
990 vpn.getVpnInstanceName(), vpnRd);
993 // Advertise the prefix to BGP only for external vpn
994 // since there is a nexthop change.
996 if (!rd.equalsIgnoreCase(vpnName)) {
997 bgpManager.advertisePrefix(rd, null /*macAddress*/, prefix, nhList,
998 VrfEntry.EncapType.Mplsgre, (int)label, 0 /*evi*/, 0 /*l2vni*/,
999 null /*gatewayMacAddress*/);
1001 LOG.info("updateVpnInterfaceOnTepAdd: Advertised rd {} prefix {} nhList {} label {}"
1002 + " for interface {} on dpn {} vpn {}", rd, prefix, nhList, label, vpnInterface.getName(),
1004 } catch (Exception ex) {
1005 LOG.error("updateVpnInterfaceOnTepAdd: Exception when advertising prefix {} nh {} label {}"
1006 + " on rd {} for interface {} on dpn {} vpn {}", prefix, nhList, label, rd,
1007 vpnInterface.getName(), srcDpnId, vpnName, ex);
1011 AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(value);
1012 VpnInterfaceOpDataEntry opInterface = new VpnInterfaceOpDataEntryBuilder(vpnInterface)
1013 .withKey(new VpnInterfaceOpDataEntryKey(vpnInterface.getName(), vpnName))
1014 .addAugmentation(AdjacenciesOp.class, aug).build();
1015 InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId =
1016 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterface.getName(), vpnName);
1017 writeOperTxn.put(interfaceId, opInterface, CREATE_MISSING_PARENTS);
1018 LOG.info("updateVpnInterfaceOnTepAdd: interface {} updated successully on tep add on dpn {} vpn {}",
1019 vpnInterface.getName(), srcDpnId, vpnName);
1023 // TODO Clean up the exception handling
1024 @SuppressWarnings("checkstyle:IllegalCatch")
1025 public void updateVpnInterfaceOnTepDelete(VpnInterfaceOpDataEntry vpnInterface,
1026 StateTunnelList stateTunnelList,
1027 TypedWriteTransaction<Configuration> writeConfigTxn,
1028 TypedWriteTransaction<Operational> writeOperTxn) {
1030 AdjacenciesOp adjacencies = vpnInterface.augmentation(AdjacenciesOp.class);
1031 List<Adjacency> adjList = adjacencies != null ? adjacencies.getAdjacency() : new ArrayList<>();
1032 String prefix = null;
1034 boolean isNextHopRemoveReqd = false;
1035 String srcTepIp = stateTunnelList.getSrcInfo().getTepIp().stringValue();
1036 BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
1037 String vpnName = vpnInterface.getVpnInstanceName();
1038 long vpnId = vpnUtil.getVpnId(vpnName);
1039 String primaryRd = vpnUtil.getVpnRd(vpnName);
1040 if (adjList != null) {
1041 List<Adjacency> value = new ArrayList<>();
1042 LOG.info("updateVpnInterfaceOnTepDelete: AdjacencyList for interface {} on dpn {} vpn {} is {}",
1043 vpnInterface.getName(), vpnInterface.getDpnId(),
1044 vpnInterface.getVpnInstanceName(), adjList);
1045 for (Adjacency adj : adjList) {
1046 List<String> nhList = new ArrayList<>();
1047 String rd = adj.getVrfId();
1048 rd = rd != null ? rd : vpnName;
1049 prefix = adj.getIpAddress();
1050 List<String> nextHopList = adj.getNextHopIpList();
1051 label = adj.getLabel();
1052 if (nextHopList != null && !nextHopList.isEmpty()) {
1053 isNextHopRemoveReqd = true;
1055 // If TEP is deleted , remove the nexthop from primary adjacency.
1056 // Secondary adj nexthop will continue to point to primary adj IP address.
1057 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
1058 value.add(new AdjacencyBuilder(adj).setNextHopIpList(nhList).build());
1060 Optional<VrfEntry> vrfEntryOptional = FibHelper.getVrfEntry(dataBroker, primaryRd, prefix);
1061 if (!vrfEntryOptional.isPresent()) {
1064 nhList = FibHelper.getNextHopListFromRoutePaths(vrfEntryOptional.get());
1065 if (nhList.contains(srcTepIp)) {
1066 nhList.remove(srcTepIp);
1067 isNextHopRemoveReqd = true;
1072 if (isNextHopRemoveReqd) {
1073 updateLabelMapper(label, nhList);
1074 LOG.info("updateVpnInterfaceOnTepDelete: Updated label mapper : label {} dpn {} prefix {}"
1075 + " nexthoplist {} vpn {} vpnid {} rd {} interface {}", label, srcDpnId,
1076 prefix, nhList, vpnName,
1077 vpnId, rd, vpnInterface.getName());
1078 // Update the VRF entry with removed nextHop
1079 fibManager.updateRoutePathForFibEntry(primaryRd, prefix, srcTepIp,
1080 label, false, TransactionAdapter.toWriteTransaction(writeConfigTxn));
1082 //Get the list of VPN's importing this route(prefix) .
1083 // Then update the VRF entry with nhList
1084 List<VpnInstanceOpDataEntry> vpnsToImportRoute = vpnUtil.getVpnsImportingMyRoute(vpnName);
1085 for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
1086 String vpnRd = vpn.getVrfId();
1087 if (vpnRd != null) {
1088 fibManager.updateRoutePathForFibEntry(vpnRd, prefix,
1089 srcTepIp, label, false, TransactionAdapter.toWriteTransaction(writeConfigTxn));
1090 LOG.info("updateVpnInterfaceOnTepDelete: Exported route with rd {} prefix {} nhList {}"
1091 + " label {} interface {} dpn {} from vpn {} to VPN {} vpnRd {}", rd, prefix,
1092 nhList, label, vpnInterface.getName(), srcDpnId,
1094 vpn.getVpnInstanceName(), vpnRd);
1098 // Withdraw prefix from BGP only for external vpn.
1100 if (!rd.equalsIgnoreCase(vpnName)) {
1101 bgpManager.withdrawPrefix(rd, prefix);
1103 LOG.info("updateVpnInterfaceOnTepDelete: Withdrawn rd {} prefix {} nhList {} label {}"
1104 + " for interface {} on dpn {} vpn {}", rd, prefix, nhList, label,
1105 vpnInterface.getName(), srcDpnId,
1107 } catch (Exception ex) {
1108 LOG.error("updateVpnInterfaceOnTepDelete: Exception when withdrawing prefix {} nh {} label {}"
1109 + " on rd {} for interface {} on dpn {} vpn {}", prefix, nhList, label, rd,
1110 vpnInterface.getName(), srcDpnId, vpnName, ex);
1114 AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(value);
1115 VpnInterfaceOpDataEntry opInterface = new VpnInterfaceOpDataEntryBuilder(vpnInterface)
1116 .withKey(new VpnInterfaceOpDataEntryKey(vpnInterface.getName(), vpnName))
1117 .addAugmentation(AdjacenciesOp.class, aug).build();
1118 InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId =
1119 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterface.getName(), vpnName);
1120 writeOperTxn.put(interfaceId, opInterface, CREATE_MISSING_PARENTS);
1121 LOG.info("updateVpnInterfaceOnTepDelete: interface {} updated successully on tep delete on dpn {} vpn {}",
1122 vpnInterface.getName(), srcDpnId, vpnName);
1126 private List<VpnInstanceOpDataEntry> getVpnsExportingMyRoute(final String vpnName) {
1127 List<VpnInstanceOpDataEntry> vpnsToExportRoute = new ArrayList<>();
1129 String vpnRd = vpnUtil.getVpnRd(vpnName);
1130 final VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(vpnRd);
1131 if (vpnInstanceOpDataEntry == null) {
1132 LOG.debug("getVpnsExportingMyRoute: Could not retrieve vpn instance op data for {}"
1133 + " to check for vpns exporting the routes", vpnName);
1134 return vpnsToExportRoute;
1137 Predicate<VpnInstanceOpDataEntry> excludeVpn = input -> {
1138 if (input.getVpnInstanceName() == null) {
1139 LOG.error("getVpnsExportingMyRoute.excludeVpn: Received vpn instance with rd {} without a name",
1143 return !input.getVpnInstanceName().equals(vpnName);
1146 Predicate<VpnInstanceOpDataEntry> matchRTs = input -> {
1147 Iterable<String> commonRTs =
1148 VpnUtil.intersection(VpnUtil.getRts(vpnInstanceOpDataEntry, VpnTarget.VrfRTType.ImportExtcommunity),
1149 VpnUtil.getRts(input, VpnTarget.VrfRTType.ExportExtcommunity));
1150 return Iterators.size(commonRTs.iterator()) > 0;
1154 vpnUtil.getAllVpnInstanceOpData().stream().filter(excludeVpn).filter(matchRTs).collect(
1155 Collectors.toList());
1156 return vpnsToExportRoute;
1159 // TODO Clean up the exception handling
1160 @SuppressWarnings("checkstyle:IllegalCatch")
1161 void handleVpnsExportingRoutes(String vpnName, String vpnRd) {
1162 List<VpnInstanceOpDataEntry> vpnsToExportRoute = getVpnsExportingMyRoute(vpnName);
1163 for (VpnInstanceOpDataEntry vpn : vpnsToExportRoute) {
1164 List<VrfEntry> vrfEntries = vpnUtil.getAllVrfEntries(vpn.getVrfId());
1165 if (vrfEntries != null) {
1166 ListenableFutures.addErrorLogging(
1167 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
1168 for (VrfEntry vrfEntry : vrfEntries) {
1170 if (!FibHelper.isControllerManagedNonInterVpnLinkRoute(
1171 RouteOrigin.value(vrfEntry.getOrigin()))) {
1172 LOG.info("handleVpnsExportingRoutes: vrfEntry with rd {} prefix {}"
1173 + " is not a controller managed non intervpn link route. Ignoring.",
1174 vpn.getVrfId(), vrfEntry.getDestPrefix());
1177 String prefix = vrfEntry.getDestPrefix();
1178 String gwMac = vrfEntry.getGatewayMacAddress();
1179 vrfEntry.getRoutePaths().forEach(routePath -> {
1180 String nh = routePath.getNexthopAddress();
1181 int label = routePath.getLabel().intValue();
1182 if (FibHelper.isControllerManagedVpnInterfaceRoute(RouteOrigin.value(
1183 vrfEntry.getOrigin()))) {
1185 "handleVpnsExportingRoutesImporting: Importing fib entry rd {} prefix {}"
1186 + " nexthop {} label {} to vpn {} vpnRd {}",
1187 vpn.getVrfId(), prefix, nh, label, vpnName, vpnRd);
1188 fibManager.addOrUpdateFibEntry(vpnRd, null /*macAddress*/, prefix,
1189 Collections.singletonList(nh), VrfEntry.EncapType.Mplsgre, label,
1190 0 /*l3vni*/, gwMac, vpn.getVrfId(), RouteOrigin.SELF_IMPORTED,
1193 LOG.info("handleVpnsExportingRoutes: Importing subnet route fib entry rd {} "
1194 + "prefix {} nexthop {} label {} to vpn {} vpnRd {}",
1195 vpn.getVrfId(), prefix, nh, label, vpnName, vpnRd);
1196 SubnetRoute route = vrfEntry.augmentation(SubnetRoute.class);
1197 importSubnetRouteForNewVpn(vpnRd, prefix, nh, label, route, vpn.getVrfId(),
1201 } catch (RuntimeException e) {
1202 LOG.error("getNextHopAddressList: Exception occurred while importing route with rd {}"
1203 + " prefix {} routePaths {} to vpn {} vpnRd {}", vpn.getVrfId(),
1204 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(), vpnName, vpnRd);
1207 }), LOG, "Error handing VPN exporting routes");
1209 LOG.info("getNextHopAddressList: No vrf entries to import from vpn {} with rd {} to vpn {} with rd {}",
1210 vpn.getVpnInstanceName(), vpn.getVrfId(), vpnName, vpnRd);
1216 public void remove(InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
1217 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
1218 final String interfaceName = key.getName();
1219 for (VpnInstanceNames vpnInterfaceVpnInstance : vpnInterface.getVpnInstanceNames()) {
1220 String vpnName = vpnInterfaceVpnInstance.getVpnName();
1221 removeVpnInterfaceCall(identifier, vpnInterface, vpnName, interfaceName);
1225 private void removeVpnInterfaceCall(final InstanceIdentifier<VpnInterface> identifier,
1226 final VpnInterface vpnInterface, final String vpnName,
1227 final String interfaceName) {
1228 if (Boolean.TRUE.equals(vpnInterface.isRouterInterface())) {
1229 jobCoordinator.enqueueJob("VPNINTERFACE-" + vpnInterface.getName(), () -> {
1230 ListenableFuture<Void> future =
1231 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
1232 deleteFibEntryForRouterInterface(vpnInterface, confTx, vpnName);
1233 LOG.info("remove: Router interface {} for vpn {}", interfaceName, vpnName);
1235 ListenableFutures.addErrorLogging(future, LOG, "Error removing call for interface {} on VPN {}",
1236 vpnInterface.getName(), vpnName);
1237 return Collections.singletonList(future);
1238 }, DJC_MAX_RETRIES);
1240 Interface interfaceState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker, interfaceName);
1241 removeVpnInterfaceFromVpn(identifier, vpnInterface, vpnName, interfaceName, interfaceState);
1245 @SuppressFBWarnings("DLS_DEAD_LOCAL_STORE")
1246 private void removeVpnInterfaceFromVpn(final InstanceIdentifier<VpnInterface> identifier,
1247 final VpnInterface vpnInterface, final String vpnName,
1248 final String interfaceName, final Interface interfaceState) {
1249 LOG.info("remove: VPN Interface remove event - intfName {} vpn {} dpn {}" ,vpnInterface.getName(),
1250 vpnName, vpnInterface.getDpnId());
1251 removeInterfaceFromUnprocessedList(identifier, vpnInterface);
1252 jobCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName,
1254 List<ListenableFuture<Void>> futures = new ArrayList<>(3);
1255 ListenableFuture<Void> configFuture = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1256 writeConfigTxn -> futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
1257 writeOperTxn -> futures.add(
1258 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, writeInvTxn -> {
1259 LOG.info("remove: - intfName {} onto vpnName {} running config-driven",
1260 interfaceName, vpnName);
1261 BigInteger dpId = BigInteger.ZERO;
1263 String gwMacAddress = null;
1264 InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId =
1265 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
1266 Optional<VpnInterfaceOpDataEntry> optVpnInterface = Optional.absent();
1268 optVpnInterface = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1269 LogicalDatastoreType.OPERATIONAL, interfaceId);
1270 } catch (ReadFailedException e) {
1271 LOG.error("remove: Failed to read data store for interface {} vpn {}",
1272 interfaceName, vpnName);
1275 if (interfaceState != null) {
1277 dpId = InterfaceUtils.getDpIdFromInterface(interfaceState);
1278 } catch (NumberFormatException | IllegalStateException e) {
1279 LOG.error("remove: Unable to retrieve dpnId from interface operational"
1280 + " data store for interface {} on dpn {} for vpn {} Fetching"
1281 + " from vpn interface op data store. ", interfaceName,
1282 vpnInterface.getDpnId(), vpnName, e);
1283 dpId = BigInteger.ZERO;
1285 ifIndex = interfaceState.getIfIndex();
1286 gwMacAddress = interfaceState.getPhysAddress().getValue();
1288 LOG.info("remove: Interface state not available for {}. Trying to fetch data"
1289 + " from vpn interface op.", interfaceName);
1290 if (optVpnInterface.isPresent()) {
1291 VpnInterfaceOpDataEntry vpnOpInterface = optVpnInterface.get();
1292 dpId = vpnOpInterface.getDpnId();
1293 ifIndex = vpnOpInterface.getLportTag().intValue();
1294 gwMacAddress = vpnOpInterface.getGatewayMacAddress();
1296 LOG.error("remove: Handling removal of VPN interface {} for vpn {} skipped"
1297 + " as interfaceState and vpn interface op is not"
1298 + " available", interfaceName, vpnName);
1302 processVpnInterfaceDown(dpId, interfaceName, ifIndex, gwMacAddress,
1303 optVpnInterface.isPresent() ? optVpnInterface.get() : null, false,
1304 writeConfigTxn, writeOperTxn, writeInvTxn);
1306 "remove: Removal of vpn interface {} on dpn {} for vpn {} processed "
1308 interfaceName, vpnInterface.getDpnId(), vpnName);
1310 futures.add(configFuture);
1311 Futures.addCallback(configFuture, new PostVpnInterfaceWorker(interfaceName, false, "Config"));
1313 }, DJC_MAX_RETRIES);
1316 protected void processVpnInterfaceDown(BigInteger dpId,
1317 String interfaceName,
1320 VpnInterfaceOpDataEntry vpnOpInterface,
1321 boolean isInterfaceStateDown,
1322 TypedWriteTransaction<Configuration> writeConfigTxn,
1323 TypedWriteTransaction<Operational> writeOperTxn,
1324 TypedReadWriteTransaction<Configuration> writeInvTxn)
1325 throws ExecutionException, InterruptedException {
1326 if (vpnOpInterface == null) {
1327 LOG.error("processVpnInterfaceDown: Unable to process delete/down for interface {} on dpn {}"
1328 + " as it is not available in operational data store", interfaceName, dpId);
1331 final String vpnName = vpnOpInterface.getVpnInstanceName();
1332 InstanceIdentifier<VpnInterfaceOpDataEntry> identifier = VpnUtil.getVpnInterfaceOpDataEntryIdentifier(
1333 interfaceName, vpnName);
1334 if (!isInterfaceStateDown) {
1335 final long vpnId = vpnUtil.getVpnId(vpnName);
1336 vpnUtil.scheduleVpnInterfaceForRemoval(interfaceName, dpId, vpnName, null);
1337 final boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(vpnName);
1338 removeAdjacenciesFromVpn(dpId, lportTag, interfaceName, vpnName,
1339 vpnId, gwMac, writeConfigTxn, writeOperTxn, writeInvTxn);
1340 if (interfaceManager.isExternalInterface(interfaceName)) {
1341 processExternalVpnInterface(interfaceName, vpnName, dpId, lportTag,
1342 NwConstants.DEL_FLOW);
1344 if (!isBgpVpnInternetVpn) {
1345 vpnUtil.unbindService(interfaceName, isInterfaceStateDown);
1347 LOG.info("processVpnInterfaceDown: Unbound vpn service from interface {} on dpn {} for vpn {}"
1348 + " successful", interfaceName, dpId, vpnName);
1350 // Interface is retained in the DPN, but its Link Down.
1351 // Only withdraw the prefixes for this interface from BGP
1352 withdrawAdjacenciesForVpnFromBgp(identifier, vpnName, interfaceName, writeConfigTxn, writeOperTxn);
1356 private void removeAdjacenciesFromVpn(final BigInteger dpnId, final int lportTag, final String interfaceName,
1357 final String vpnName, final long vpnId, String gwMac,
1358 TypedWriteTransaction<Configuration> writeConfigTxn,
1359 TypedWriteTransaction<Operational> writeOperTxn,
1360 TypedReadWriteTransaction<Configuration> writeInvTxn)
1361 throws ExecutionException, InterruptedException {
1364 InstanceIdentifier<VpnInterfaceOpDataEntry> identifier = VpnUtil
1365 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
1366 InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
1367 Optional<AdjacenciesOp> adjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1368 LogicalDatastoreType.OPERATIONAL, path);
1369 String primaryRd = vpnUtil.getVpnRd(vpnName);
1370 LOG.info("removeAdjacenciesFromVpn: For interface {} on dpn {} RD recovered for vpn {} as rd {}",
1371 interfaceName, dpnId, vpnName, primaryRd);
1372 if (adjacencies.isPresent() && !adjacencies.get().getAdjacency().isEmpty()) {
1373 List<Adjacency> nextHops = adjacencies.get().getAdjacency();
1374 LOG.info("removeAdjacenciesFromVpn: NextHops for interface {} on dpn {} for vpn {} are {}",
1375 interfaceName, dpnId, vpnName, nextHops);
1376 for (Adjacency nextHop : nextHops) {
1377 if (nextHop.isPhysNetworkFunc()) {
1378 LOG.info("removeAdjacenciesFromVpn: Removing PNF FIB entry rd {} prefix {}",
1379 nextHop.getSubnetId().getValue(), nextHop.getIpAddress());
1380 fibManager.removeFibEntry(nextHop.getSubnetId().getValue(), nextHop.getIpAddress(),
1381 null/*writeCfgTxn*/);
1383 String rd = nextHop.getVrfId();
1384 List<String> nhList;
1385 if (nextHop.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
1386 nhList = getNextHopForNonPrimaryAdjacency(nextHop, vpnName, dpnId, interfaceName);
1388 // This is a primary adjacency
1389 nhList = nextHop.getNextHopIpList() != null ? nextHop.getNextHopIpList()
1390 : Collections.emptyList();
1391 removeGwMacAndArpResponderFlows(nextHop, vpnId, dpnId, lportTag, gwMac,
1392 interfaceName, writeInvTxn);
1394 if (!nhList.isEmpty()) {
1395 if (rd.equals(vpnName)) {
1396 //this is an internal vpn - the rd is assigned to the vpn instance name;
1397 //remove from FIB directly
1398 nhList.forEach(removeAdjacencyFromInternalVpn(nextHop, vpnName,
1399 interfaceName, dpnId, writeConfigTxn, writeOperTxn));
1401 removeAdjacencyFromBgpvpn(nextHop, nhList, vpnName, primaryRd, dpnId, rd,
1402 interfaceName, writeConfigTxn, writeOperTxn);
1405 LOG.error("removeAdjacenciesFromVpn: nextHop empty for ip {} rd {} adjacencyType {}"
1406 + " interface {}", nextHop.getIpAddress(), rd,
1407 nextHop.getAdjacencyType().toString(), interfaceName);
1408 bgpManager.withdrawPrefixIfPresent(rd, nextHop.getIpAddress());
1409 fibManager.removeFibEntry(primaryRd, nextHop.getIpAddress(), writeConfigTxn);
1412 String ip = nextHop.getIpAddress().split("/")[0];
1413 LearntVpnVipToPort vpnVipToPort = vpnUtil.getLearntVpnVipToPort(vpnName, ip);
1414 if (vpnVipToPort != null) {
1415 vpnUtil.removeLearntVpnVipToPort(vpnName, ip, null);
1416 LOG.info("removeAdjacenciesFromVpn: VpnInterfaceManager removed LearntVpnVipToPort entry"
1417 + " for Interface {} ip {} on dpn {} for vpn {}",
1418 vpnVipToPort.getPortName(), ip, dpnId, vpnName);
1420 VpnPortipToPort vpnPortipToPort = vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnName, ip);
1421 if (vpnPortipToPort != null) {
1422 VpnUtil.removeVpnPortFixedIpToPort(dataBroker, vpnName, ip, null);
1423 LOG.info("removeAdjacenciesFromVpn: VpnInterfaceManager removed vpnPortipToPort entry for "
1424 + "Interface {} ip {} on dpn {} for vpn {}",
1425 vpnPortipToPort.getPortName(), ip, dpnId, vpnName);
1429 // this vpn interface has no more adjacency left, so clean up the vpn interface from Operational DS
1430 LOG.info("removeAdjacenciesFromVpn: Vpn Interface {} on vpn {} dpn {} has no adjacencies."
1431 + " Removing it.", interfaceName, vpnName, dpnId);
1432 writeOperTxn.delete(identifier);
1434 } catch (ReadFailedException e) {
1435 LOG.error("removeAdjacenciesFromVpn: Failed to read data store for interface {} dpn {} vpn {}",
1436 interfaceName, dpnId, vpnName);
1440 private Consumer<String> removeAdjacencyFromInternalVpn(Adjacency nextHop, String vpnName,
1441 String interfaceName, BigInteger dpnId,
1442 TypedWriteTransaction<Configuration> writeConfigTxn,
1443 TypedWriteTransaction<Operational> writeOperTx) {
1445 String primaryRd = vpnUtil.getVpnRd(vpnName);
1446 String prefix = nextHop.getIpAddress();
1447 String vpnNamePrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
1448 LOG.info("remove adjacencies for nexthop {} vpnName {} interfaceName {} dpnId {}",
1449 nextHop, vpnName, interfaceName, dpnId);
1450 synchronized (vpnNamePrefixKey.intern()) {
1451 if (vpnUtil.removeOrUpdateDSForExtraRoute(vpnName, primaryRd, dpnId.toString(), interfaceName,
1452 prefix, nextHop.getNextHopIpList().get(0), nh, writeOperTx)) {
1453 //If extra-route is present behind at least one VM, then do not remove or update
1454 //fib entry for route-path representing that CSS nexthop, just update vpntoextraroute and
1455 //prefixtointerface DS
1458 fibManager.removeOrUpdateFibEntry(vpnName, nextHop.getIpAddress(), nh,
1461 LOG.info("removeAdjacenciesFromVpn: removed/updated FIB with rd {} prefix {}"
1462 + " nexthop {} for interface {} on dpn {} for internal vpn {}",
1463 vpnName, nextHop.getIpAddress(), nh, interfaceName, dpnId, vpnName);
1467 private void removeAdjacencyFromBgpvpn(Adjacency nextHop, List<String> nhList, String vpnName, String primaryRd,
1468 BigInteger dpnId, String rd, String interfaceName,
1469 TypedWriteTransaction<Configuration> writeConfigTxn,
1470 TypedWriteTransaction<Operational> writeOperTx) {
1471 List<VpnInstanceOpDataEntry> vpnsToImportRoute =
1472 vpnUtil.getVpnsImportingMyRoute(vpnName);
1473 nhList.forEach((nh) -> {
1474 //IRT: remove routes from other vpns importing it
1475 vpnManager.removePrefixFromBGP(vpnName, primaryRd, rd, interfaceName, nextHop.getIpAddress(),
1476 nextHop.getNextHopIpList().get(0), nh, dpnId, writeConfigTxn, writeOperTx);
1477 for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
1478 String vpnRd = vpn.getVrfId();
1479 if (vpnRd != null) {
1480 fibManager.removeOrUpdateFibEntry(vpnRd,
1481 nextHop.getIpAddress(), nh, writeConfigTxn);
1482 LOG.info("removeAdjacenciesFromVpn: Removed Exported route with rd {}"
1483 + " prefix {} nextHop {} from VPN {} parentVpn {}"
1484 + " for interface {} on dpn {}", vpnRd, nextHop.getIpAddress(), nh,
1485 vpn.getVpnInstanceName(), vpnName, interfaceName, dpnId);
1491 private void removeGwMacAndArpResponderFlows(Adjacency nextHop, long vpnId, BigInteger dpnId,
1492 int lportTag, String gwMac, String interfaceName,
1493 TypedReadWriteTransaction<Configuration> writeInvTxn)
1494 throws ExecutionException, InterruptedException {
1495 final Uuid subnetId = nextHop.getSubnetId();
1496 if (nextHop.getSubnetGatewayMacAddress() == null) {
1497 // A valid mac-address was not available for this subnet-gateway-ip
1498 // So a connected-mac-address was used for this subnet and we need
1499 // to remove the flows for the same here from the L3_GW_MAC_TABLE.
1500 vpnUtil.setupGwMacIfExternalVpn(dpnId, interfaceName, vpnId, writeInvTxn, NwConstants.DEL_FLOW, gwMac);
1502 arpResponderHandler.removeArpResponderFlow(dpnId, lportTag, interfaceName, nextHop.getSubnetGatewayIp(),
1506 private List<String> getNextHopForNonPrimaryAdjacency(Adjacency nextHop, String vpnName, BigInteger dpnId,
1507 String interfaceName) {
1508 // This is either an extra-route (or) a learned IP via subnet-route
1509 List<String> nhList = null;
1510 String nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
1511 if (nextHopIp == null || nextHopIp.isEmpty()) {
1512 LOG.error("removeAdjacenciesFromVpn: Unable to obtain nextHopIp for"
1513 + " extra-route/learned-route in rd {} prefix {} interface {} on dpn {}"
1514 + " for vpn {}", nextHop.getVrfId(), nextHop.getIpAddress(), interfaceName, dpnId,
1516 nhList = Collections.emptyList();
1518 nhList = Collections.singletonList(nextHopIp);
1523 private Optional<String> getMacAddressForSubnetIp(String vpnName, String ifName, String ipAddress) {
1524 VpnPortipToPort gwPort = vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnName, ipAddress);
1525 //Check if a router gateway interface is available for the subnet gw is so then use Router interface
1526 // else use connected interface
1527 if (gwPort != null && gwPort.isSubnetIp()) {
1528 LOG.info("getGatewayMacAddressForSubnetIp: Retrieved gw Mac as {} for ip {} interface {} vpn {}",
1529 gwPort.getMacAddress(), ipAddress, ifName, vpnName);
1530 return Optional.of(gwPort.getMacAddress());
1532 return Optional.absent();
1536 protected void update(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface original,
1537 final VpnInterface update) {
1538 LOG.info("update: VPN Interface update event - intfName {} on dpn {} oldVpn {} newVpn {}" ,update.getName(),
1539 update.getDpnId(), original.getVpnInstanceNames(),
1540 update.getVpnInstanceNames());
1541 final String vpnInterfaceName = update.getName();
1542 final BigInteger dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
1543 LOG.info("VPN Interface update event - intfName {}", vpnInterfaceName);
1544 //handles switching between <internal VPN - external VPN>
1545 jobCoordinator.enqueueJob("VPNINTERFACE-" + vpnInterfaceName, () -> {
1546 List<ListenableFuture<Void>> futures = new ArrayList<>();
1547 if (handleVpnInstanceUpdateForVpnInterface(identifier, original, update, futures)) {
1548 LOG.info("update: handled Instance update for VPNInterface {} on dpn {} from oldVpn(s) {} "
1549 + "to newVpn(s) {}",
1550 original.getName(), dpnId,
1551 VpnHelper.getVpnInterfaceVpnInstanceNamesString(original.getVpnInstanceNames()),
1552 VpnHelper.getVpnInterfaceVpnInstanceNamesString(update.getVpnInstanceNames()));
1553 return Collections.emptyList();
1555 updateVpnInstanceAdjChange(original, update, vpnInterfaceName, futures);
1560 private boolean handleVpnInstanceUpdateForVpnInterface(InstanceIdentifier<VpnInterface> identifier,
1561 VpnInterface original, VpnInterface update,
1562 List<ListenableFuture<Void>> futures) {
1563 boolean isVpnInstanceUpdate = Boolean.FALSE;
1564 final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
1565 final String interfaceName = key.getName();
1566 List<String> oldVpnList = vpnUtil.getVpnListForVpnInterface(original);
1567 List<String> oldVpnListCopy = new ArrayList<>();
1568 oldVpnListCopy.addAll(oldVpnList);
1569 List<String> newVpnList = vpnUtil.getVpnListForVpnInterface(update);
1571 oldVpnList.removeAll(newVpnList);
1572 newVpnList.removeAll(oldVpnListCopy);
1573 //This block will execute only on if there is a change in the VPN Instance.
1574 if (!oldVpnList.isEmpty() || !newVpnList.isEmpty()) {
1576 * Internet BGP-VPN Instance update with single router:
1577 * ====================================================
1578 * In this case single VPN Interface will be part of maximum 2 VPN Instance only.
1579 * 1st VPN Instance : router VPN or external BGP-VPN.
1580 * 2nd VPN Instance : Internet BGP-VPN(router-gw update/delete) for public network access.
1582 * VPN Instance UPDATE:
1583 * oldVpnList = 0 and newVpnList = 1 (Internet BGP-VPN)
1584 * oldVpnList = 1 and newVpnList = 0 (Internet BGP-VPN)
1586 * External BGP-VPN Instance update with single router:
1587 * ====================================================
1588 * In this case single VPN interface will be part of maximum 1 VPN Instance only.
1590 * Updated VPN Instance will be always either internal router VPN to
1591 * external BGP-VPN or external BGP-VPN to internal router VPN swap.
1593 * VPN Instance UPDATE:
1594 * oldVpnList = 1 and newVpnList = 1 (router VPN to Ext-BGPVPN)
1595 * oldVpnList = 1 and newVpnList = 1 (Ext-BGPVPN to router VPN)
1597 * TODO Two router VPN instance update use case will be addressed in separate patch
1599 isVpnInstanceUpdate = Boolean.TRUE;
1600 updateVpnInstanceChange(identifier, interfaceName, original, update, oldVpnList, newVpnList,
1601 oldVpnListCopy, futures);
1603 return isVpnInstanceUpdate;
1606 private void updateVpnInstanceChange(InstanceIdentifier<VpnInterface> identifier, String interfaceName,
1607 VpnInterface original, VpnInterface update, List<String> oldVpnList,
1608 List<String> newVpnList, List<String> oldVpnListCopy,
1609 List<ListenableFuture<Void>> futures) {
1610 final Adjacencies origAdjs = original.augmentation(Adjacencies.class);
1611 final List<Adjacency> oldAdjs = (origAdjs != null && origAdjs.getAdjacency() != null)
1612 ? origAdjs.getAdjacency() : new ArrayList<>();
1613 final Adjacencies updateAdjs = update.augmentation(Adjacencies.class);
1614 final List<Adjacency> newAdjs = (updateAdjs != null && updateAdjs.getAdjacency() != null)
1615 ? updateAdjs.getAdjacency() : new ArrayList<>();
1617 boolean isOldVpnRemoveCallExecuted = false;
1618 for (String oldVpnName : oldVpnList) {
1619 LOG.info("updateVpnInstanceChange: VPN Interface update event - intfName {} "
1620 + "remove from vpnName {} ", interfaceName, oldVpnName);
1621 removeVpnInterfaceCall(identifier, original, oldVpnName, interfaceName);
1622 LOG.info("updateVpnInstanceChange: Processed Remove for update on VPNInterface"
1623 + " {} upon VPN update from old vpn {} to newVpn(s) {}", interfaceName, oldVpnName,
1625 isOldVpnRemoveCallExecuted = true;
1627 //Wait for previous interface bindings to be removed
1628 if (isOldVpnRemoveCallExecuted && !newVpnList.isEmpty()) {
1631 } catch (InterruptedException e) {
1635 for (String newVpnName : newVpnList) {
1636 String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
1637 if (!vpnUtil.isVpnPendingDelete(primaryRd)) {
1638 LOG.info("updateVpnInstanceChange: VPN Interface update event - intfName {} "
1639 + "onto vpnName {} ", interfaceName, newVpnName);
1640 addVpnInterfaceCall(identifier, update, oldAdjs, newAdjs, newVpnName);
1641 LOG.info("updateVpnInstanceChange: Processed Add for update on VPNInterface {}"
1642 + "from oldVpn(s) {} to newVpn {} ",
1643 interfaceName, oldVpnListCopy, newVpnName);
1644 /* This block will execute only if V6 subnet is associated with internet BGP-VPN.
1646 * In Dual stack network, first V4 subnet only attached to router and router is associated
1647 * with internet BGP-VPN(router-gw). At this point VPN interface is having only router vpn instance.
1648 * Later V6 subnet is added to router, at this point existing VPN interface will get updated
1649 * with Internet BGP-VPN instance(Note: Internet BGP-VPN Instance update in vpn interface
1650 * is applicable for only on V6 subnet is added to router). newVpnList = Contains only Internet
1651 * BGP-VPN Instance. So we required V6 primary adjacency info needs to be populated onto
1652 * router VPN as well as Internet BGP-VPN.
1654 * addVpnInterfaceCall() --> It will create V6 Adj onto Internet BGP-VPN only.
1655 * updateVpnInstanceAdjChange() --> This method call is needed for second primary V6 Adj
1656 * update in existing router VPN instance.
1658 if (vpnUtil.isBgpVpnInternet(newVpnName)) {
1659 LOG.info("updateVpnInstanceChange: VPN Interface {} with new Adjacency {} in existing "
1660 + "VPN instance {}", interfaceName, newAdjs, original.getVpnInstanceNames());
1661 updateVpnInstanceAdjChange(original, update, interfaceName, futures);
1667 private List<ListenableFuture<Void>> updateVpnInstanceAdjChange(VpnInterface original, VpnInterface update,
1668 String vpnInterfaceName,
1669 List<ListenableFuture<Void>> futures) {
1670 final Adjacencies origAdjs = original.augmentation(Adjacencies.class);
1671 final List<Adjacency> oldAdjs = origAdjs != null && origAdjs.getAdjacency()
1672 != null ? origAdjs.getAdjacency() : new ArrayList<>();
1673 final Adjacencies updateAdjs = update.augmentation(Adjacencies.class);
1674 final List<Adjacency> newAdjs = updateAdjs != null && updateAdjs.getAdjacency()
1675 != null ? updateAdjs.getAdjacency() : new ArrayList<>();
1677 final BigInteger dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
1678 for (VpnInstanceNames vpnInterfaceVpnInstance : update.getVpnInstanceNames()) {
1679 String newVpnName = vpnInterfaceVpnInstance.getVpnName();
1680 List<Adjacency> copyNewAdjs = new ArrayList<>(newAdjs);
1681 List<Adjacency> copyOldAdjs = new ArrayList<>(oldAdjs);
1682 String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
1683 if (!vpnUtil.isVpnPendingDelete(primaryRd)) {
1684 // TODO Deal with sequencing — the config tx must only submitted if the oper tx goes in
1685 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
1686 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
1687 InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier =
1688 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterfaceName, newVpnName);
1689 LOG.info("VPN Interface update event - intfName {} onto vpnName {} running config-driven",
1690 update.getName(), newVpnName);
1691 //handle both addition and removal of adjacencies
1692 //currently, new adjacency may be an extra route
1693 boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(newVpnName);
1694 if (!oldAdjs.equals(newAdjs)) {
1695 for (Adjacency adj : copyNewAdjs) {
1696 if (copyOldAdjs.contains(adj)) {
1697 copyOldAdjs.remove(adj);
1699 // add new adjacency
1700 if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
1701 addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adj,
1702 dpnId, operTx, confTx, confTx);
1704 LOG.info("update: new Adjacency {} with nextHop {} label {} subnet {} added to"
1705 + " vpn interface {} on vpn {} dpnId {}",
1706 adj.getIpAddress(), adj.getNextHopIpList(),
1707 adj.getLabel(), adj.getSubnetId(), update.getName(),
1711 for (Adjacency adj : copyOldAdjs) {
1712 if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
1713 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency
1714 && !adj.isPhysNetworkFunc()) {
1715 delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId,
1718 String vpnRd = vpnUtil.getVpnRd(newVpnName);
1719 LOG.debug("update: remove prefix {} from the FIB and BGP entry "
1720 + "for the Vpn-Rd {} ", adj.getIpAddress(), vpnRd);
1722 fibManager.removeFibEntry(vpnRd, adj.getIpAddress(), confTx);
1723 if (vpnRd != null && !vpnRd.equalsIgnoreCase(newVpnName)) {
1724 bgpManager.withdrawPrefix(vpnRd, adj.getIpAddress());
1727 delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId,
1731 LOG.info("update: Adjacency {} with nextHop {} label {} subnet {} removed from"
1732 + " vpn interface {} on vpn {}", adj.getIpAddress(), adj
1733 .getNextHopIpList(),
1734 adj.getLabel(), adj.getSubnetId(), update.getName(), newVpnName);
1739 for (ListenableFuture<Void> future : futures) {
1740 ListenableFutures.addErrorLogging(future, LOG, "update: failed for interface {} on vpn {}",
1741 update.getName(), update.getVpnInstanceNames());
1744 LOG.error("update: Ignoring update of vpnInterface {}, as newVpnInstance {} with primaryRd {}"
1745 + " is already marked for deletion", vpnInterfaceName, newVpnName, primaryRd);
1751 private void updateLabelMapper(Long label, List<String> nextHopIpList) {
1753 Preconditions.checkNotNull(label, "updateLabelMapper: label cannot be null or empty!");
1754 synchronized (label.toString().intern()) {
1755 InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
1756 .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build();
1757 Optional<LabelRouteInfo> opResult = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1758 LogicalDatastoreType.OPERATIONAL, lriIid);
1759 if (opResult.isPresent()) {
1760 LabelRouteInfo labelRouteInfo =
1761 new LabelRouteInfoBuilder(opResult.get()).setNextHopIpList(nextHopIpList).build();
1762 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid,
1763 labelRouteInfo, VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
1766 LOG.info("updateLabelMapper: Updated label rotue info for label {} with nextHopList {}", label,
1768 } catch (ReadFailedException e) {
1769 LOG.error("updateLabelMapper: Failed to read data store for label {} nexthopList {}", label,
1771 } catch (TransactionCommitFailedException e) {
1772 LOG.error("updateLabelMapper: Failed to commit to data store for label {} nexthopList {}", label,
1777 public synchronized void importSubnetRouteForNewVpn(String rd, String prefix, String nextHop, int label,
1778 SubnetRoute route, String parentVpnRd, TypedWriteTransaction<Configuration> writeConfigTxn) {
1780 RouteOrigin origin = RouteOrigin.SELF_IMPORTED;
1781 VrfEntry vrfEntry = FibHelper.getVrfEntryBuilder(prefix, label, nextHop, origin, parentVpnRd)
1782 .addAugmentation(SubnetRoute.class, route).build();
1783 List<VrfEntry> vrfEntryList = Collections.singletonList(vrfEntry);
1784 InstanceIdentifierBuilder<VrfTables> idBuilder =
1785 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1786 InstanceIdentifier<VrfTables> vrfTableId = idBuilder.build();
1787 VrfTables vrfTableNew = new VrfTablesBuilder().setRouteDistinguisher(rd).setVrfEntry(vrfEntryList).build();
1788 if (writeConfigTxn != null) {
1789 writeConfigTxn.merge(vrfTableId, vrfTableNew, CREATE_MISSING_PARENTS);
1791 vpnUtil.syncUpdate(LogicalDatastoreType.CONFIGURATION, vrfTableId, vrfTableNew);
1793 LOG.info("SUBNETROUTE: importSubnetRouteForNewVpn: Created vrfEntry for rd {} prefix {} nexthop {} label {}"
1794 + " and elantag {}", rd, prefix, nextHop, label, route.getElantag());
1797 protected void addNewAdjToVpnInterface(InstanceIdentifier<VpnInterfaceOpDataEntry> identifier, String primaryRd,
1798 Adjacency adj, BigInteger dpnId,
1799 TypedWriteTransaction<Operational> writeOperTxn,
1800 TypedWriteTransaction<Configuration> writeConfigTxn,
1801 TypedReadWriteTransaction<Configuration> writeInvTxn)
1802 throws ExecutionException, InterruptedException {
1803 String interfaceName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getName();
1804 String configVpnName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getVpnInstanceName();
1806 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker
1807 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, identifier);
1808 if (optVpnInterface.isPresent()) {
1809 VpnInterfaceOpDataEntry currVpnIntf = optVpnInterface.get();
1810 String prefix = VpnUtil.getIpPrefix(adj.getIpAddress());
1811 String vpnName = currVpnIntf.getVpnInstanceName();
1812 VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(primaryRd);
1813 InstanceIdentifier<AdjacenciesOp> adjPath = identifier.augmentation(AdjacenciesOp.class);
1814 Optional<AdjacenciesOp> optAdjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1815 LogicalDatastoreType.OPERATIONAL, adjPath);
1816 boolean isL3VpnOverVxLan = VpnUtil.isL3VpnOverVxLan(vpnInstanceOpData.getL3vni());
1817 VrfEntry.EncapType encapType = VpnUtil.getEncapType(isL3VpnOverVxLan);
1818 long l3vni = vpnInstanceOpData.getL3vni() == null ? 0L : vpnInstanceOpData.getL3vni();
1819 VpnPopulator populator = L3vpnRegistry.getRegisteredPopulator(encapType);
1820 List<Adjacency> adjacencies;
1821 if (optAdjacencies.isPresent()) {
1822 adjacencies = optAdjacencies.get().getAdjacency();
1824 // This code will be hit in case of first PNF adjacency
1825 adjacencies = new ArrayList<>();
1827 long vpnId = vpnUtil.getVpnId(vpnName);
1828 L3vpnInput input = new L3vpnInput().setNextHop(adj).setVpnName(vpnName)
1829 .setInterfaceName(currVpnIntf.getName()).setPrimaryRd(primaryRd).setRd(primaryRd);
1830 Adjacency operationalAdjacency = null;
1831 //Handling dual stack neutron port primary adjacency
1832 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency && !adj.isPhysNetworkFunc()) {
1833 LOG.trace("addNewAdjToVpnInterface: Adding prefix {} to existing interface {} for vpn {}", prefix,
1834 currVpnIntf.getName(), vpnName);
1835 Interface interfaceState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker,
1836 currVpnIntf.getName());
1837 if (interfaceState != null) {
1838 processVpnInterfaceAdjacencies(dpnId, currVpnIntf.getLportTag().intValue(), vpnName, primaryRd,
1839 currVpnIntf.getName(),
1840 vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState);
1843 if (adj.getNextHopIpList() != null && !adj.getNextHopIpList().isEmpty()
1844 && adj.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
1845 RouteOrigin origin = adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency ? RouteOrigin.LOCAL
1846 : RouteOrigin.STATIC;
1847 String nh = adj.getNextHopIpList().get(0);
1848 String vpnPrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
1849 synchronized (vpnPrefixKey.intern()) {
1850 java.util.Optional<String> rdToAllocate = vpnUtil.allocateRdForExtraRouteAndUpdateUsedRdsMap(
1851 vpnId, null, prefix, vpnName, nh, dpnId);
1852 if (rdToAllocate.isPresent()) {
1853 input.setRd(rdToAllocate.get());
1854 operationalAdjacency = populator.createOperationalAdjacency(input);
1855 int label = operationalAdjacency.getLabel().intValue();
1856 vpnManager.addExtraRoute(vpnName, adj.getIpAddress(), nh, rdToAllocate.get(),
1857 currVpnIntf.getVpnInstanceName(), l3vni, origin,
1858 currVpnIntf.getName(), operationalAdjacency, encapType, writeConfigTxn);
1859 LOG.info("addNewAdjToVpnInterface: Added extra route ip {} nh {} rd {} vpnname {} label {}"
1860 + " Interface {} on dpn {}", adj.getIpAddress(), nh, rdToAllocate.get(),
1861 vpnName, label, currVpnIntf.getName(), dpnId);
1863 LOG.error("addNewAdjToVpnInterface: No rds to allocate extraroute vpn {} prefix {}",
1867 // iRT/eRT use case Will be handled in a new patchset for L3VPN Over VxLAN.
1868 // Keeping the MPLS check for now.
1869 if (encapType.equals(VrfEntryBase.EncapType.Mplsgre)) {
1870 final Adjacency opAdjacency = new AdjacencyBuilder(operationalAdjacency).build();
1871 List<VpnInstanceOpDataEntry> vpnsToImportRoute =
1872 vpnUtil.getVpnsImportingMyRoute(vpnName);
1873 vpnsToImportRoute.forEach(vpn -> {
1874 if (vpn.getVrfId() != null) {
1875 vpnUtil.allocateRdForExtraRouteAndUpdateUsedRdsMap(vpn.getVpnId(), vpnId, prefix,
1876 vpnUtil.getVpnName(vpn.getVpnId()), nh, dpnId)
1878 rds -> vpnManager.addExtraRoute(
1879 vpnUtil.getVpnName(vpn.getVpnId()),
1880 adj.getIpAddress(), nh, rds,
1881 currVpnIntf.getVpnInstanceName(), l3vni,
1882 RouteOrigin.SELF_IMPORTED, currVpnIntf.getName(),
1883 opAdjacency, encapType, writeConfigTxn));
1888 } else if (adj.isPhysNetworkFunc()) { // PNF adjacency.
1889 LOG.trace("addNewAdjToVpnInterface: Adding prefix {} to interface {} for vpn {}", prefix,
1890 currVpnIntf.getName(), vpnName);
1892 InstanceIdentifier<VpnInterface> vpnIfaceConfigidentifier = VpnUtil
1893 .getVpnInterfaceIdentifier(currVpnIntf.getName());
1894 Optional<VpnInterface> vpnIntefaceConfig = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1895 LogicalDatastoreType.CONFIGURATION, vpnIfaceConfigidentifier);
1896 Prefixes pnfPrefix = VpnUtil.getPrefixToInterface(BigInteger.ZERO, currVpnIntf.getName(), prefix,
1897 Prefixes.PrefixCue.PhysNetFunc);
1898 if (vpnIntefaceConfig.isPresent()) {
1899 pnfPrefix = VpnUtil.getPrefixToInterface(BigInteger.ZERO, currVpnIntf.getName(), prefix,
1900 vpnIntefaceConfig.get().getNetworkId(), vpnIntefaceConfig.get().getNetworkType(),
1901 vpnIntefaceConfig.get().getSegmentationId(), Prefixes.PrefixCue.PhysNetFunc);
1904 String parentVpnRd = getParentVpnRdForExternalSubnet(adj);
1907 VpnUtil.getPrefixToInterfaceIdentifier(vpnUtil.getVpnId(adj.getSubnetId().getValue()),
1908 prefix), pnfPrefix, true);
1910 fibManager.addOrUpdateFibEntry(adj.getSubnetId().getValue(), adj.getMacAddress(),
1911 adj.getIpAddress(), Collections.emptyList(), null /* EncapType */, 0 /* label */,
1912 0 /*l3vni*/, null /* gw-mac */, parentVpnRd, RouteOrigin.LOCAL, writeConfigTxn);
1914 input.setRd(adj.getVrfId());
1916 if (operationalAdjacency == null) {
1917 operationalAdjacency = populator.createOperationalAdjacency(input);
1919 adjacencies.add(operationalAdjacency);
1920 AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(adjacencies);
1921 VpnInterfaceOpDataEntry newVpnIntf =
1922 VpnUtil.getVpnInterfaceOpDataEntry(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(),
1923 aug, dpnId, currVpnIntf.getLportTag(),
1924 currVpnIntf.getGatewayMacAddress());
1926 writeOperTxn.merge(identifier, newVpnIntf, CREATE_MISSING_PARENTS);
1928 } catch (ReadFailedException e) {
1929 LOG.error("addNewAdjToVpnInterface: Failed to read data store for interface {} dpn {} vpn {} rd {} ip "
1930 + "{}", interfaceName, dpnId, configVpnName, primaryRd, adj.getIpAddress());
1934 private String getParentVpnRdForExternalSubnet(Adjacency adj) {
1935 Subnets subnets = vpnUtil.getExternalSubnet(adj.getSubnetId());
1936 return subnets != null ? subnets.getExternalNetworkId().getValue() : null;
1939 protected void delAdjFromVpnInterface(InstanceIdentifier<VpnInterfaceOpDataEntry> identifier, Adjacency adj,
1940 BigInteger dpnId, TypedWriteTransaction<Operational> writeOperTxn,
1941 TypedWriteTransaction<Configuration> writeConfigTxn) {
1942 String interfaceName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getName();
1943 String vpnName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getVpnInstanceName();
1945 Optional<VpnInterfaceOpDataEntry> optVpnInterface = SingleTransactionDataBroker.syncReadOptional(
1946 dataBroker, LogicalDatastoreType.OPERATIONAL, identifier);
1947 if (optVpnInterface.isPresent()) {
1948 VpnInterfaceOpDataEntry currVpnIntf = optVpnInterface.get();
1949 InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
1950 Optional<AdjacenciesOp> optAdjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
1951 LogicalDatastoreType.OPERATIONAL, path);
1952 if (optAdjacencies.isPresent()) {
1953 List<Adjacency> adjacencies = optAdjacencies.get().getAdjacency();
1955 if (!adjacencies.isEmpty()) {
1956 LOG.trace("delAdjFromVpnInterface: Adjacencies are {}", adjacencies);
1957 Iterator<Adjacency> adjIt = adjacencies.iterator();
1958 while (adjIt.hasNext()) {
1959 Adjacency adjElem = adjIt.next();
1960 if (adjElem.getIpAddress().equals(adj.getIpAddress())) {
1961 String rd = adjElem.getVrfId();
1962 if (adj.getNextHopIpList() != null) {
1963 for (String nh : adj.getNextHopIpList()) {
1964 deleteExtraRouteFromCurrentAndImportingVpns(
1965 currVpnIntf.getVpnInstanceName(), adj.getIpAddress(), nh, rd,
1966 currVpnIntf.getName(), writeConfigTxn, writeOperTxn);
1968 } else if (adj.isPhysNetworkFunc()) {
1969 LOG.info("delAdjFromVpnInterface: deleting PNF adjacency prefix {} subnet {}",
1970 adj.getIpAddress(), adj.getSubnetId());
1971 fibManager.removeFibEntry(adj.getSubnetId().getValue(), adj.getIpAddress(),
1979 LOG.info("delAdjFromVpnInterface: Removed adj {} on dpn {} rd {}", adj.getIpAddress(),
1980 dpnId, adj.getVrfId());
1982 LOG.error("delAdjFromVpnInterface: Cannnot DEL adjacency, since operational interface is "
1983 + "unavailable dpnId {} adjIP {} rd {}", dpnId, adj.getIpAddress(), adj.getVrfId());
1986 } catch (ReadFailedException e) {
1987 LOG.error("delAdjFromVpnInterface: Failed to read data store for ip {} interface {} dpn {} vpn {}",
1988 adj.getIpAddress(), interfaceName, dpnId, vpnName);
1992 private void deleteExtraRouteFromCurrentAndImportingVpns(String vpnName, String destination, String nextHop,
1993 String rd, String intfName, TypedWriteTransaction<Configuration> writeConfigTxn,
1994 TypedWriteTransaction<Operational> writeOperTx) {
1995 vpnManager.delExtraRoute(vpnName, destination, nextHop, rd, vpnName, intfName, writeConfigTxn, writeOperTx);
1996 List<VpnInstanceOpDataEntry> vpnsToImportRoute = vpnUtil.getVpnsImportingMyRoute(vpnName);
1997 for (VpnInstanceOpDataEntry vpn : vpnsToImportRoute) {
1998 String vpnRd = vpn.getVrfId();
1999 if (vpnRd != null) {
2000 vpnManager.delExtraRoute(vpnName, destination, nextHop, vpnRd, vpnName, intfName, writeConfigTxn,
2006 InstanceIdentifier<DpnVpninterfacesList> getRouterDpnId(String routerName, BigInteger dpnId) {
2007 return InstanceIdentifier.builder(NeutronRouterDpns.class)
2008 .child(RouterDpnList.class, new RouterDpnListKey(routerName))
2009 .child(DpnVpninterfacesList.class, new DpnVpninterfacesListKey(dpnId)).build();
2012 InstanceIdentifier<RouterDpnList> getRouterId(String routerName) {
2013 return InstanceIdentifier.builder(NeutronRouterDpns.class)
2014 .child(RouterDpnList.class, new RouterDpnListKey(routerName)).build();
2017 protected void createFibEntryForRouterInterface(String primaryRd, VpnInterface vpnInterface, String interfaceName,
2018 TypedWriteTransaction<Configuration> writeConfigTxn, String vpnName) {
2019 if (vpnInterface == null) {
2022 List<Adjacency> adjs = vpnUtil.getAdjacenciesForVpnInterfaceFromConfig(interfaceName);
2024 LOG.error("createFibEntryForRouterInterface: VPN Interface {} of router addition failed as adjacencies for"
2025 + " this vpn interface could not be obtained. vpn {}", interfaceName, vpnName);
2028 for (Adjacency adj : adjs) {
2029 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
2030 String primaryInterfaceIp = adj.getIpAddress();
2031 String macAddress = adj.getMacAddress();
2032 String prefix = VpnUtil.getIpPrefix(primaryInterfaceIp);
2034 long label = vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME,
2035 VpnUtil.getNextHopLabelKey(primaryRd, prefix));
2037 RouterInterface routerInt = new RouterInterfaceBuilder().setUuid(vpnName)
2038 .setIpAddress(primaryInterfaceIp).setMacAddress(macAddress).build();
2039 fibManager.addFibEntryForRouterInterface(primaryRd, prefix,
2040 routerInt, label, writeConfigTxn);
2041 LOG.info("createFibEntryForRouterInterface: Router interface {} for vpn {} rd {} prefix {} label {}"
2042 + " macAddress {} processed successfully;", interfaceName, vpnName, primaryRd, prefix, label,
2047 LOG.error("createFibEntryForRouterInterface: VPN Interface {} of router addition failed as primary"
2048 + " adjacency for this vpn interface could not be obtained. rd {} vpnName {}", interfaceName,
2049 primaryRd, vpnName);
2052 protected void deleteFibEntryForRouterInterface(VpnInterface vpnInterface,
2053 TypedWriteTransaction<Configuration> writeConfigTxn, String vpnName) {
2054 Adjacencies adjs = vpnInterface.augmentation(Adjacencies.class);
2055 String rd = vpnUtil.getVpnRd(vpnName);
2057 List<Adjacency> adjsList = adjs.getAdjacency();
2058 for (Adjacency adj : adjsList) {
2059 if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
2060 String primaryInterfaceIp = adj.getIpAddress();
2061 String prefix = VpnUtil.getIpPrefix(primaryInterfaceIp);
2062 fibManager.removeFibEntry(rd, prefix, writeConfigTxn);
2063 LOG.info("deleteFibEntryForRouterInterface: FIB for router interface {} deleted for vpn {} rd {}"
2064 + " prefix {}", vpnInterface.getName(), vpnName, rd, prefix);
2069 LOG.error("deleteFibEntryForRouterInterface: Adjacencies for vpninterface {} is null, rd: {}",
2070 vpnInterface.getName(), rd);
2074 private void processSavedInterface(UnprocessedVpnInterfaceData intefaceData, String vpnName) {
2075 if (!canHandleNewVpnInterface(intefaceData.identifier, intefaceData.vpnInterface, vpnName)) {
2076 LOG.error("add: VpnInstance {} for vpnInterface {} not ready, holding on ",
2077 vpnName, intefaceData.vpnInterface.getName());
2080 final VpnInterfaceKey key = intefaceData.identifier
2081 .firstKeyOf(VpnInterface.class, VpnInterfaceKey.class);
2082 final String interfaceName = key.getName();
2083 InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier = VpnUtil
2084 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
2085 addVpnInterfaceToVpn(vpnInterfaceOpIdentifier, intefaceData.vpnInterface, null, null,
2086 intefaceData.identifier, vpnName);
2090 private void addToUnprocessedVpnInterfaces(InstanceIdentifier<VpnInterface> identifier,
2091 VpnInterface vpnInterface, String vpnName) {
2092 ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces = unprocessedVpnInterfaces
2094 if (vpnInterfaces == null) {
2095 vpnInterfaces = new ConcurrentLinkedQueue<>();
2097 vpnInterfaces.add(new UnprocessedVpnInterfaceData(identifier, vpnInterface));
2098 unprocessedVpnInterfaces.put(vpnName, vpnInterfaces);
2099 LOG.info("addToUnprocessedVpnInterfaces: Saved unhandled vpn interface {} in vpn instance {}",
2100 vpnInterface.getName(), vpnName);
2103 public boolean isVpnInstanceReady(String vpnInstanceName) {
2104 String vpnRd = vpnUtil.getVpnRd(vpnInstanceName);
2105 if (vpnRd == null) {
2108 VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(vpnRd);
2110 return vpnInstanceOpDataEntry != null;
2113 public void processSavedInterfaces(String vpnInstanceName, boolean hasVpnInstanceCreatedSuccessfully) {
2114 synchronized (vpnInstanceName.intern()) {
2115 ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces =
2116 unprocessedVpnInterfaces.get(vpnInstanceName);
2117 if (vpnInterfaces != null) {
2118 while (!vpnInterfaces.isEmpty()) {
2119 UnprocessedVpnInterfaceData savedInterface = vpnInterfaces.poll();
2120 if (hasVpnInstanceCreatedSuccessfully) {
2121 processSavedInterface(savedInterface, vpnInstanceName);
2122 LOG.info("processSavedInterfaces: Handle saved vpn interfaces {} in vpn instance {}",
2123 savedInterface.vpnInterface.getName(), vpnInstanceName);
2125 LOG.error("processSavedInterfaces: Cannot process vpn interface {} in vpn instance {}",
2126 savedInterface.vpnInterface.getName(), vpnInstanceName);
2130 LOG.info("processSavedInterfaces: No interfaces in queue for VPN {}", vpnInstanceName);
2135 private void removeInterfaceFromUnprocessedList(InstanceIdentifier<VpnInterface> identifier,
2136 VpnInterface vpnInterface) {
2137 synchronized (VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface).intern()) {
2138 ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces =
2139 unprocessedVpnInterfaces.get(VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface));
2140 if (vpnInterfaces != null) {
2141 if (vpnInterfaces.remove(new UnprocessedVpnInterfaceData(identifier, vpnInterface))) {
2142 LOG.info("removeInterfaceFromUnprocessedList: Removed vpn interface {} in vpn instance {} from "
2143 + "unprocessed list", vpnInterface.getName(),
2144 VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface));
2147 LOG.info("removeInterfaceFromUnprocessedList: No interfaces in queue for VPN {}",
2148 VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface));
2153 public void vpnInstanceIsReady(String vpnInstanceName) {
2154 processSavedInterfaces(vpnInstanceName, true);
2157 public void vpnInstanceFailed(String vpnInstanceName) {
2158 processSavedInterfaces(vpnInstanceName, false);
2161 private static class UnprocessedVpnInterfaceData {
2162 InstanceIdentifier<VpnInterface> identifier;
2163 VpnInterface vpnInterface;
2165 UnprocessedVpnInterfaceData(InstanceIdentifier<VpnInterface> identifier, VpnInterface vpnInterface) {
2166 this.identifier = identifier;
2167 this.vpnInterface = vpnInterface;
2171 public int hashCode() {
2172 final int prime = 31;
2174 result = prime * result + (identifier == null ? 0 : identifier.hashCode());
2175 result = prime * result + (vpnInterface == null ? 0 : vpnInterface.hashCode());
2180 public boolean equals(Object obj) {
2187 if (getClass() != obj.getClass()) {
2190 UnprocessedVpnInterfaceData other = (UnprocessedVpnInterfaceData) obj;
2191 if (identifier == null) {
2192 if (other.identifier != null) {
2195 } else if (!identifier.equals(other.identifier)) {
2198 if (vpnInterface == null) {
2199 if (other.vpnInterface != null) {
2202 } else if (!vpnInterface.equals(other.vpnInterface)) {
2209 public void updateVpnInterfacesForUnProcessAdjancencies(String vpnName) {
2210 String primaryRd = vpnUtil.getVpnRd(vpnName);
2211 VpnInstanceOpDataEntry vpnInstanceOpData = vpnUtil.getVpnInstanceOpData(primaryRd);
2212 if (vpnInstanceOpData == null) {
2215 List<VpnToDpnList> vpnToDpnLists = vpnInstanceOpData.getVpnToDpnList();
2216 if (vpnToDpnLists == null || vpnToDpnLists.isEmpty()) {
2219 LOG.debug("Update the VpnInterfaces for Unprocessed Adjancencies for vpnName:{}", vpnName);
2220 vpnToDpnLists.forEach(vpnToDpnList -> {
2221 if (vpnToDpnList.getVpnInterfaces() == null) {
2224 vpnToDpnList.getVpnInterfaces().forEach(vpnInterface -> {
2226 InstanceIdentifier<VpnInterfaceOpDataEntry> existingVpnInterfaceId =
2227 VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterface.getInterfaceName(), vpnName);
2228 Optional<VpnInterfaceOpDataEntry> vpnInterfaceOptional = SingleTransactionDataBroker
2229 .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, existingVpnInterfaceId);
2230 if (!vpnInterfaceOptional.isPresent()) {
2233 List<Adjacency> configVpnAdjacencies = vpnUtil.getAdjacenciesForVpnInterfaceFromConfig(
2234 vpnInterface.getInterfaceName());
2235 if (configVpnAdjacencies == null) {
2236 LOG.debug("There is no adjacency available for vpnInterface:{}", vpnInterface);
2239 List<Adjacency> operationVpnAdjacencies = vpnInterfaceOptional.get()
2240 .augmentation(AdjacenciesOp.class).getAdjacency();
2241 // Due to insufficient rds, some of the extra route wont get processed when it is added.
2242 // The unprocessed adjacencies will be present in config vpn interface DS but will be missing
2243 // in operational DS. These unprocessed adjacencies will be handled below.
2244 // To obtain unprocessed adjacencies, filtering is done by which the missing adjacencies in
2245 // operational DS are retrieved which is used to call addNewAdjToVpnInterface method.
2246 configVpnAdjacencies.stream()
2247 .filter(adjacency -> operationVpnAdjacencies.stream()
2248 .noneMatch(operationalAdjacency ->
2249 operationalAdjacency.getIpAddress().equals(adjacency.getIpAddress())))
2250 .forEach(adjacency -> {
2251 LOG.debug("Processing the vpnInterface{} for the Ajacency:{}", vpnInterface, adjacency);
2252 jobCoordinator.enqueueJob("VPNINTERFACE-" + vpnInterface.getInterfaceName(),
2254 // TODO Deal with sequencing — the config tx must only submitted
2255 // if the oper tx goes in
2256 if (vpnUtil.isAdjacencyEligibleToVpn(adjacency, vpnName)) {
2257 List<ListenableFuture<Void>> futures = new ArrayList<>();
2259 txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx ->
2261 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
2262 confTx -> addNewAdjToVpnInterface(existingVpnInterfaceId,
2263 primaryRd, adjacency, vpnInterfaceOptional.get()
2264 .getDpnId(), operTx, confTx, confTx)))));
2267 return Collections.emptyList();
2271 } catch (ReadFailedException e) {
2272 LOG.error("updateVpnInterfacesForUnProcessAdjancencies: Failed to read data store for vpn {} rd {}",
2273 vpnName, primaryRd);
2279 private class PostVpnInterfaceWorker implements FutureCallback<Void> {
2280 private final String interfaceName;
2281 private final boolean add;
2282 private final String txnDestination;
2284 PostVpnInterfaceWorker(String interfaceName, boolean add, String transactionDest) {
2285 this.interfaceName = interfaceName;
2287 this.txnDestination = transactionDest;
2291 public void onSuccess(Void voidObj) {
2293 LOG.debug("VpnInterfaceManager: VrfEntries for {} stored into destination {} successfully",
2294 interfaceName, txnDestination);
2296 LOG.debug("VpnInterfaceManager: VrfEntries for {} removed successfully", interfaceName);
2301 public void onFailure(Throwable throwable) {
2303 LOG.error("VpnInterfaceManager: VrfEntries for {} failed to store into destination {}",
2304 interfaceName, txnDestination, throwable);
2306 LOG.error("VpnInterfaceManager: VrfEntries for {} removal failed", interfaceName, throwable);
2307 vpnUtil.unsetScheduledToRemoveForVpnInterface(interfaceName);