2 * Copyright © 2015, 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.fibmanager;
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
12 import static org.opendaylight.genius.mdsalutil.NWUtil.isIpv4Address;
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.Lists;
16 import com.google.common.util.concurrent.FutureCallback;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import com.google.common.util.concurrent.MoreExecutors;
20 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
21 import java.math.BigInteger;
22 import java.net.InetAddress;
23 import java.net.UnknownHostException;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.List;
30 import java.util.Objects;
31 import java.util.Optional;
32 import java.util.concurrent.Callable;
33 import java.util.concurrent.CopyOnWriteArrayList;
34 import java.util.concurrent.ExecutionException;
35 import java.util.concurrent.locks.ReentrantLock;
36 import javax.inject.Inject;
37 import javax.inject.Singleton;
38 import org.eclipse.jdt.annotation.NonNull;
39 import org.eclipse.jdt.annotation.Nullable;
40 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
41 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
42 import org.opendaylight.genius.infra.Datastore.Configuration;
43 import org.opendaylight.genius.infra.Datastore.Operational;
44 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
45 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
46 import org.opendaylight.genius.infra.RetryingManagedNewTransactionRunner;
47 import org.opendaylight.genius.infra.TransactionAdapter;
48 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
49 import org.opendaylight.genius.infra.TypedWriteTransaction;
50 import org.opendaylight.genius.mdsalutil.ActionInfo;
51 import org.opendaylight.genius.mdsalutil.FlowEntity;
52 import org.opendaylight.genius.mdsalutil.InstructionInfo;
53 import org.opendaylight.genius.mdsalutil.MDSALUtil;
54 import org.opendaylight.genius.mdsalutil.MatchInfo;
55 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
56 import org.opendaylight.genius.mdsalutil.NWUtil;
57 import org.opendaylight.genius.mdsalutil.NwConstants;
58 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
59 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
60 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
61 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
62 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
63 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
64 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
65 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
66 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
67 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
68 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
69 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
70 import org.opendaylight.genius.utils.JvmGlobalLocks;
71 import org.opendaylight.genius.utils.ServiceIndex;
72 import org.opendaylight.genius.utils.batching.SubTransaction;
73 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
74 import org.opendaylight.infrautils.utils.concurrent.Executors;
75 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
76 import org.opendaylight.mdsal.binding.api.DataBroker;
77 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
78 import org.opendaylight.netvirt.elanmanager.api.IElanService;
79 import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
80 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
81 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
82 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
83 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
84 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
85 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
86 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
87 import org.opendaylight.serviceutils.upgrade.UpgradeState;
88 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePathsKey;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesBuilder;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.Adjacency;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.AdjacencyBuilder;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState.State;
124 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
125 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
126 import org.opendaylight.yangtools.yang.common.Uint32;
127 import org.opendaylight.yangtools.yang.common.Uint64;
128 import org.slf4j.Logger;
129 import org.slf4j.LoggerFactory;
132 public class VrfEntryListener extends AbstractAsyncDataTreeChangeListener<VrfEntry> {
134 private static final Logger LOG = LoggerFactory.getLogger(VrfEntryListener.class);
135 private static final String FLOWID_PREFIX = "L3.";
136 private static final Uint64 COOKIE_VM_FIB_TABLE = Uint64.valueOf("8000003", 16).intern();
137 private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
138 private static final int IPV4_ADDR_PREFIX_LENGTH = 32;
139 private static final int LFIB_INTERVPN_PRIORITY = 15;
140 public static final Uint64 COOKIE_TUNNEL = Uint64.valueOf("9000000", 16).intern();
141 private static final int MAX_RETRIES = 3;
142 private static final Uint64 COOKIE_TABLE_MISS = Uint64.valueOf("8000004", 16).intern();
144 private final DataBroker dataBroker;
145 private final ManagedNewTransactionRunner txRunner;
146 private final RetryingManagedNewTransactionRunner retryingTxRunner;
147 private final IMdsalApiManager mdsalManager;
148 private final NexthopManager nextHopManager;
149 private final BgpRouteVrfEntryHandler bgpRouteVrfEntryHandler;
150 private final BaseVrfEntryHandler baseVrfEntryHandler;
151 private final RouterInterfaceVrfEntryHandler routerInterfaceVrfEntryHandler;
152 private final JobCoordinator jobCoordinator;
153 private final IElanService elanManager;
154 private final FibUtil fibUtil;
155 private final InterVpnLinkCache interVpnLinkCache;
156 private final List<AutoCloseable> closeables = new CopyOnWriteArrayList<>();
157 private final UpgradeState upgradeState;
158 private final DataTreeEventCallbackRegistrar eventCallbacks;
161 public VrfEntryListener(final DataBroker dataBroker, final IMdsalApiManager mdsalApiManager,
162 final NexthopManager nexthopManager,
163 final IElanService elanManager,
164 final BaseVrfEntryHandler vrfEntryHandler,
165 final BgpRouteVrfEntryHandler bgpRouteVrfEntryHandler,
166 final RouterInterfaceVrfEntryHandler routerInterfaceVrfEntryHandler,
167 final JobCoordinator jobCoordinator,
168 final FibUtil fibUtil,
169 final InterVpnLinkCache interVpnLinkCache,
170 final UpgradeState upgradeState,
171 final DataTreeEventCallbackRegistrar eventCallbacks) {
172 super(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(FibEntries.class)
173 .child(VrfTables.class).child(VrfEntry.class),
174 Executors.newListeningSingleThreadExecutor("VrfEntryListener", LOG));
175 this.dataBroker = dataBroker;
176 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
177 this.retryingTxRunner = new RetryingManagedNewTransactionRunner(dataBroker, MAX_RETRIES);
178 this.mdsalManager = mdsalApiManager;
179 this.nextHopManager = nexthopManager;
180 this.elanManager = elanManager;
181 this.baseVrfEntryHandler = vrfEntryHandler;
182 this.bgpRouteVrfEntryHandler = bgpRouteVrfEntryHandler;
183 this.routerInterfaceVrfEntryHandler = routerInterfaceVrfEntryHandler;
184 this.jobCoordinator = jobCoordinator;
185 this.fibUtil = fibUtil;
186 this.interVpnLinkCache = interVpnLinkCache;
187 this.upgradeState = upgradeState;
188 this.eventCallbacks = eventCallbacks;
192 LOG.info("{} init", getClass().getSimpleName());
196 @SuppressWarnings("checkstyle:IllegalCatch")
197 public void close() {
198 closeables.forEach(c -> {
201 } catch (Exception e) {
202 LOG.warn("Error closing {}", c, e);
205 Executors.shutdownAndAwaitTermination(getExecutorService());
209 public void add(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
210 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
211 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
212 LOG.debug("ADD: Adding Fib Entry rd {} prefix {} route-paths {}",
213 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
214 addFibEntries(identifier, vrfEntry, rd);
215 LOG.info("ADD: Added Fib Entry rd {} prefix {} route-paths {}",
216 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
219 //This method is temporary. Eventually Factory design pattern will be used to get
220 // right VrfEntryhandle and invoke its methods.
221 private void addFibEntries(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry, String rd) {
222 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
223 bgpRouteVrfEntryHandler.createFlows(identifier, vrfEntry, rd);
226 if (VrfEntry.EncapType.Vxlan.equals(vrfEntry.getEncapType())) {
227 LOG.info("EVPN flows need to be programmed.");
228 EvpnVrfEntryHandler evpnVrfEntryHandler = new EvpnVrfEntryHandler(dataBroker, this, bgpRouteVrfEntryHandler,
229 nextHopManager, jobCoordinator, fibUtil, upgradeState, eventCallbacks);
230 evpnVrfEntryHandler.createFlows(identifier, vrfEntry, rd);
231 closeables.add(evpnVrfEntryHandler);
234 RouterInterface routerInt = vrfEntry.augmentation(RouterInterface.class);
235 if (routerInt != null) {
236 // ping responder for router interfaces
237 routerInterfaceVrfEntryHandler.createFlows(vrfEntry, rd);
240 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
241 createFibEntries(identifier, vrfEntry);
247 public void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
248 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
249 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
250 LOG.debug("REMOVE: Removing Fib Entry rd {} prefix {} route-paths {}",
251 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
252 removeFibEntries(identifier, vrfEntry, rd);
253 LOG.info("REMOVE: Removed Fib Entry rd {} prefix {} route-paths {}",
254 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
257 //This method is temporary. Eventually Factory design pattern will be used to get
258 // right VrfEntryhandle and invoke its methods.
259 private void removeFibEntries(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry, String rd) {
260 if (VrfEntry.EncapType.Vxlan.equals(vrfEntry.getEncapType())) {
261 LOG.info("EVPN flows to be deleted");
262 EvpnVrfEntryHandler evpnVrfEntryHandler = new EvpnVrfEntryHandler(dataBroker, this, bgpRouteVrfEntryHandler,
263 nextHopManager, jobCoordinator, fibUtil, upgradeState, eventCallbacks);
264 evpnVrfEntryHandler.removeFlows(identifier, vrfEntry, rd);
265 closeables.add(evpnVrfEntryHandler);
268 RouterInterface routerInt = vrfEntry.augmentation(RouterInterface.class);
269 if (routerInt != null) {
270 // ping responder for router interfaces
271 routerInterfaceVrfEntryHandler.removeFlows(vrfEntry, rd);
274 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
275 deleteFibEntries(identifier, vrfEntry);
278 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
279 bgpRouteVrfEntryHandler.removeFlows(identifier, vrfEntry, rd);
285 // "Redundant nullcheck of originalRoutePath, which is known to be non-null" - the null checking for
286 // originalRoutePath is a little dicey - safest to keep the checking even if not needed.
287 @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE")
288 public void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
289 Preconditions.checkNotNull(update, "VrfEntry should not be null or empty.");
290 final String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
291 LOG.debug("UPDATE: Updating Fib Entries to rd {} prefix {} route-paths {} origin {} old-origin {}", rd,
292 update.getDestPrefix(), update.getRoutePaths(), update.getOrigin(), original.getOrigin());
293 // Handle BGP Routes first
294 if (RouteOrigin.value(update.getOrigin()) == RouteOrigin.BGP) {
295 bgpRouteVrfEntryHandler.updateFlows(identifier, original, update, rd);
296 LOG.info("UPDATE: Updated BGP advertised Fib Entry with rd {} prefix {} route-paths {}",
297 rd, update.getDestPrefix(), update.getRoutePaths());
301 if (RouteOrigin.value(update.getOrigin()) == RouteOrigin.STATIC) {
302 List<RoutePaths> originalRoutePath = new ArrayList<RoutePaths>(original.nonnullRoutePaths().values());
303 List<RoutePaths> updateRoutePath = new ArrayList<RoutePaths>(update.nonnullRoutePaths().values());
304 LOG.info("UPDATE: Original route-path {} update route-path {} ", originalRoutePath, updateRoutePath);
306 //Updates need to be handled for extraroute even if original vrf entry route path is null or
307 //updated vrf entry route path is null. This can happen during tunnel events.
308 Optional<VpnInstanceOpDataEntry> optVpnInstance = fibUtil.getVpnInstanceOpData(rd);
309 List<String> usedRds = new ArrayList<>();
310 if (optVpnInstance.isPresent()) {
311 usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker,optVpnInstance.get().getVpnId(),
312 update.getDestPrefix());
314 // If original VRF Entry had nexthop null , but update VRF Entry
315 // has nexthop , route needs to be created on remote Dpns
316 if (originalRoutePath == null || originalRoutePath.isEmpty()
317 && updateRoutePath != null && !updateRoutePath.isEmpty() && usedRds.isEmpty()) {
318 // TODO(vivek): Though ugly, Not handling this code now, as each
319 // tep add event will invoke flow addition
320 LOG.trace("Original VRF entry NH is null for destprefix {}. And the prefix is not an extra route."
321 + " This event is IGNORED here.", update.getDestPrefix());
325 // If original VRF Entry had valid nexthop , but update VRF Entry
326 // has nexthop empty'ed out, route needs to be removed from remote Dpns
327 if (updateRoutePath == null || updateRoutePath.isEmpty()
328 && originalRoutePath != null && !originalRoutePath.isEmpty() && usedRds.isEmpty()) {
329 LOG.trace("Original VRF entry had valid NH for destprefix {}. And the prefix is not an extra route."
330 + "This event is IGNORED here.", update.getDestPrefix());
333 //Update the used rds and vpntoextraroute containers only for the deleted nextHops.
334 List<String> nextHopsRemoved = FibHelper.getNextHopListFromRoutePaths(original);
335 nextHopsRemoved.removeAll(FibHelper.getNextHopListFromRoutePaths(update));
336 List<ListenableFuture<Void>> futures = new ArrayList<>();
337 ListenableFuture<Void> configFuture =
338 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, configTx ->
339 futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx ->
340 nextHopsRemoved.parallelStream()
341 .forEach(nextHopRemoved -> {
343 fibUtil.updateUsedRdAndVpnToExtraRoute(
344 configTx, operTx, nextHopRemoved, rd, update.getDestPrefix());
345 } catch (ExecutionException | InterruptedException e) {
346 throw new RuntimeException(e);
349 futures.add(configFuture);
350 Futures.addCallback(configFuture, new FutureCallback<Void>() {
352 public void onSuccess(Void result) {
353 createFibEntries(identifier, update);
354 LOG.info("UPDATE: Updated static Fib Entry with rd {} prefix {} route-paths {}",
355 rd, update.getDestPrefix(), update.getRoutePaths());
359 public void onFailure(Throwable throwable) {
360 LOG.error("Exception encountered while submitting operational future for update vrfentry {}",
363 }, MoreExecutors.directExecutor());
367 //Handle all other routes only on a cluster reboot
368 if (original.equals(update)) {
370 createFibEntries(identifier, update);
371 LOG.info("UPDATE: Updated Non-static Fib Entry with rd {} prefix {} route-paths {}",
372 rd, update.getDestPrefix(), update.getRoutePaths());
376 LOG.info("UPDATE: Ignoring update for FIB entry with rd {} prefix {} route-origin {} route-paths {}",
377 rd, update.getDestPrefix(), update.getOrigin(), update.getRoutePaths());
380 private void createFibEntries(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
381 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
382 List<SubTransaction> txnObjects = new ArrayList<>();
383 final VpnInstanceOpDataEntry vpnInstance =
384 fibUtil.getVpnInstance(vrfTableKey.getRouteDistinguisher());
385 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
386 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId()
387 + " has null vpnId!");
388 final Map<VpnToDpnListKey, VpnToDpnList> keyVpnToDpnListMap;
389 if (vrfEntry.getParentVpnRd() != null
390 && FibHelper.isControllerManagedNonSelfImportedRoute(RouteOrigin.value(vrfEntry.getOrigin()))) {
391 // This block MUST BE HIT only for PNF (Physical Network Function) FIB Entries.
392 VpnInstanceOpDataEntry parentVpnInstance = fibUtil.getVpnInstance(vrfEntry.getParentVpnRd());
393 keyVpnToDpnListMap = parentVpnInstance != null ? parentVpnInstance.nonnullVpnToDpnList() :
394 vpnInstance.getVpnToDpnList();
395 LOG.info("createFibEntries: Processing creation of PNF FIB entry with rd {} prefix {}",
396 vrfEntry.getParentVpnRd(), vrfEntry.getDestPrefix());
398 keyVpnToDpnListMap = vpnInstance.nonnullVpnToDpnList();
400 final Uint32 vpnId = vpnInstance.getVpnId();
401 final String rd = vrfTableKey.getRouteDistinguisher();
402 SubnetRoute subnetRoute = vrfEntry.augmentation(SubnetRoute.class);
403 if (subnetRoute != null) {
404 final long elanTag = subnetRoute.getElantag().toJava();
405 LOG.trace("SUBNETROUTE: createFibEntries: SubnetRoute augmented vrfentry found for rd {} prefix {}"
406 + " with elantag {}", rd, vrfEntry.getDestPrefix(), elanTag);
407 if (keyVpnToDpnListMap != null) {
408 jobCoordinator.enqueueJob(FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix()),
409 () -> Collections.singletonList(
410 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
411 for (final VpnToDpnList curDpn : keyVpnToDpnListMap.values()) {
412 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
413 installSubnetRouteInFib(curDpn.getDpnId(),
414 elanTag, rd, vpnId, vrfEntry, tx);
415 installSubnetBroadcastAddrDropRule(curDpn.getDpnId(), rd,
416 vpnId, vrfEntry, NwConstants.ADD_FLOW, tx);
423 // Get etherType value based on the IpPrefix address family type
426 etherType = NWUtil.getEtherTypeFromIpPrefix(vrfEntry.getDestPrefix());
427 } catch (IllegalArgumentException ex) {
428 LOG.error("Unable to get etherType for IP Prefix {}", vrfEntry.getDestPrefix());
432 final List<Uint64> localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(),
433 rd, vrfEntry, etherType);
434 if (!localDpnIdList.isEmpty() && keyVpnToDpnListMap != null) {
435 jobCoordinator.enqueueJob(FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix()),
436 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
437 final ReentrantLock lock = lockFor(vpnInstance);
440 for (VpnToDpnList vpnDpn : keyVpnToDpnListMap.values()) {
441 if (!localDpnIdList.contains(vpnDpn.getDpnId())) {
442 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
444 if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
445 bgpRouteVrfEntryHandler.createRemoteFibEntry(vpnDpn.getDpnId(),
446 vpnId, vrfTableKey.getRouteDistinguisher(), vrfEntry,
447 TransactionAdapter.toWriteTransaction(tx), txnObjects);
449 createRemoteFibEntry(vpnDpn.getDpnId(),
450 vpnInstance.getVpnId(),
451 vrfTableKey.getRouteDistinguisher(), vrfEntry, tx);
453 } catch (NullPointerException e) {
454 LOG.error("Failed to get create remote fib flows for prefix {} ",
455 vrfEntry.getDestPrefix(), e);
466 Optional<String> optVpnUuid = fibUtil.getVpnNameFromRd(rd);
467 if (optVpnUuid.isPresent()) {
468 String vpnUuid = optVpnUuid.get();
469 InterVpnLinkDataComposite interVpnLink = interVpnLinkCache.getInterVpnLinkByVpnId(vpnUuid).orElse(null);
470 if (interVpnLink != null) {
471 LOG.debug("InterVpnLink {} found in Cache linking Vpn {}", interVpnLink.getInterVpnLinkName(), vpnUuid);
472 FibUtil.getFirstNextHopAddress(vrfEntry).ifPresent(routeNexthop -> {
473 if (interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid)) {
474 // This is an static route that points to the other endpoint of an InterVpnLink
475 // In that case, we should add another entry in FIB table pointing to LPortDispatcher table.
476 installIVpnLinkSwitchingFlows(interVpnLink, vpnUuid, vrfEntry, vpnId);
477 installInterVpnRouteInLFib(interVpnLink, vpnUuid, vrfEntry, etherType);
484 void refreshFibTables(String rd, String prefix) {
485 InstanceIdentifier<VrfEntry> vrfEntryId =
486 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
487 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
488 Optional<VrfEntry> vrfEntry;
490 vrfEntry = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
492 } catch (ExecutionException | InterruptedException e) {
493 LOG.error("refreshFibTables: Exception while reading VrfEntry Ds for the prefix {} rd {}", prefix, rd, e);
496 if (vrfEntry.isPresent()) {
497 createFibEntries(vrfEntryId, vrfEntry.get());
501 private Prefixes updateVpnReferencesInLri(LabelRouteInfo lri, String vpnInstanceName, boolean isPresentInList) {
502 LOG.debug("updating LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
503 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
504 prefixBuilder.setDpnId(lri.getDpnId());
505 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
506 prefixBuilder.setIpAddress(lri.getPrefix());
507 // Increment the refCount here
508 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
509 .child(LabelRouteInfo.class, new LabelRouteInfoKey(lri.getLabel())).build();
510 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri);
511 if (!isPresentInList) {
512 LOG.debug("vpnName {} is not present in LRI with label {}..", vpnInstanceName, lri.getLabel());
513 List<String> vpnInstanceNames =
514 lri.getVpnInstanceList() != null ? new ArrayList<>(lri.getVpnInstanceList()) : new ArrayList<>();
515 vpnInstanceNames.add(vpnInstanceName);
516 builder.setVpnInstanceList(vpnInstanceNames);
517 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build());
519 LOG.debug("vpnName {} is present in LRI with label {}..", vpnInstanceName, lri.getLabel());
521 return prefixBuilder.build();
524 void installSubnetRouteInFib(final Uint64 dpnId, final long elanTag, final String rd,
525 final Uint32 vpnId, final VrfEntry vrfEntry, TypedWriteTransaction<Configuration> tx) {
527 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
528 newTx -> installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, newTx)), LOG,
529 "Error installing subnet route in FIB");
534 etherType = NWUtil.getEtherTypeFromIpPrefix(vrfEntry.getDestPrefix());
535 } catch (IllegalArgumentException ex) {
536 LOG.error("Unable to get etherType for IP Prefix {}", vrfEntry.getDestPrefix());
539 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
540 List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
541 final LabelRouteInfoKey lriKey = new LabelRouteInfoKey(label);
542 final ReentrantLock lock = lockFor(lriKey);
545 LabelRouteInfo lri = getLabelRouteInfo(lriKey);
546 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
548 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
549 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
550 fibUtil.getVpnInstanceOpData(rd);
551 if (vpnInstanceOpDataEntryOptional.isPresent()) {
552 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
553 if (!lri.getVpnInstanceList().contains(vpnInstanceName)) {
554 updateVpnReferencesInLri(lri, vpnInstanceName, false);
558 LOG.debug("SUBNETROUTE: installSubnetRouteInFib: Fetched labelRouteInfo for label {} interface {}"
559 + " and got dpn {}", label, lri.getVpnInterfaceName(), lri.getDpnId());
565 final List<InstructionInfo> instructions = new ArrayList<>();
566 Uint64 subnetRouteMeta = Uint64.valueOf(BigInteger.valueOf(elanTag).shiftLeft(24)
567 .or(BigInteger.valueOf(vpnId.longValue()).shiftLeft(1)));
568 instructions.add(new InstructionWriteMetadata(subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE));
569 instructions.add(new InstructionGotoTable(NwConstants.L3_SUBNET_ROUTE_TABLE));
570 baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions,
571 NwConstants.ADD_FLOW, TransactionAdapter.toWriteTransaction(tx), null);
572 if (vrfEntry.getRoutePaths() != null) {
573 for (RoutePaths routePath : vrfEntry.getRoutePaths().values()) {
574 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
575 List<ActionInfo> actionsInfos = new ArrayList<>();
576 // reinitialize instructions list for LFIB Table
577 final List<InstructionInfo> LFIBinstructions = new ArrayList<>();
578 actionsInfos.add(new ActionPopMpls(etherType));
579 LFIBinstructions.add(new InstructionApplyActions(actionsInfos));
580 LFIBinstructions.add(new InstructionWriteMetadata(subnetRouteMeta,
581 MetaDataUtil.METADATA_MASK_SUBNET_ROUTE));
582 LFIBinstructions.add(new InstructionGotoTable(NwConstants.L3_SUBNET_ROUTE_TABLE));
584 makeLFibTableEntry(dpnId, routePath.getLabel(), LFIBinstructions,
585 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
591 private void installSubnetBroadcastAddrDropRule(final Uint64 dpnId, final String rd, final Uint32 vpnId,
592 final VrfEntry vrfEntry, int addOrRemove, TypedWriteTransaction<Configuration> tx) {
593 List<MatchInfo> matches = new ArrayList<>();
595 LOG.debug("SUBNETROUTE: installSubnetBroadcastAddrDropRule: destPrefix {} rd {} vpnId {} dpnId {}",
596 vrfEntry.getDestPrefix(), rd, vpnId, dpnId);
597 String[] ipAddress = vrfEntry.getDestPrefix().split("/");
598 String subnetBroadcastAddr = FibUtil.getBroadcastAddressFromCidr(vrfEntry.getDestPrefix());
599 final int prefixLength = ipAddress.length == 1 ? 0 : Integer.parseInt(ipAddress[1]);
601 InetAddress destPrefix;
603 destPrefix = InetAddress.getByName(subnetBroadcastAddr);
604 } catch (UnknownHostException e) {
605 LOG.error("Failed to get destPrefix for prefix {} rd {} VpnId {} DPN {}",
606 vrfEntry.getDestPrefix(), rd, vpnId, dpnId, e);
610 // Match on VpnId and SubnetBroadCast IP address
611 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId.longValue()),
612 MetaDataUtil.METADATA_MASK_VRFID));
613 matches.add(MatchEthernetType.IPV4);
615 if (prefixLength != 0) {
616 matches.add(new MatchIpv4Destination(subnetBroadcastAddr, Integer.toString(IPV4_ADDR_PREFIX_LENGTH)));
619 //Action is to drop the packet
620 List<InstructionInfo> dropInstructions = new ArrayList<>();
621 List<ActionInfo> actionsInfos = new ArrayList<>();
622 actionsInfos.add(new ActionDrop());
623 dropInstructions.add(new InstructionApplyActions(actionsInfos));
625 int priority = DEFAULT_FIB_FLOW_PRIORITY + IPV4_ADDR_PREFIX_LENGTH;
626 String flowRef = FibUtil.getFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, rd, priority, destPrefix);
627 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef, priority,
628 flowRef, 0, 0, COOKIE_TABLE_MISS, matches, dropInstructions);
630 Flow flow = flowEntity.getFlowBuilder().build();
631 String flowId = flowEntity.getFlowId();
632 FlowKey flowKey = new FlowKey(new FlowId(flowId));
633 Node nodeDpn = FibUtil.buildDpnNode(dpnId);
635 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
636 .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
637 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
639 if (addOrRemove == NwConstants.ADD_FLOW) {
640 tx.mergeParentStructurePut(flowInstanceId,flow);
642 tx.delete(flowInstanceId);
647 * For a given route, it installs a flow in LFIB that sets the lportTag of the other endpoint and sends to
648 * LportDispatcher table (via table 80)
650 private void installInterVpnRouteInLFib(final InterVpnLinkDataComposite interVpnLink, final String vpnName,
651 final VrfEntry vrfEntry, int etherType) {
652 // INTERVPN routes are routes in a Vpn1 that have been leaked to Vpn2. In DC-GW, this Vpn2 route is pointing
653 // to a list of DPNs where Vpn2's VpnLink was instantiated. In these DPNs LFIB must be programmed so that the
654 // packet is commuted from Vpn2 to Vpn1.
655 String interVpnLinkName = interVpnLink.getInterVpnLinkName();
656 if (!interVpnLink.isActive()) {
657 LOG.warn("InterVpnLink {} is NOT ACTIVE. InterVpnLink flows for prefix={} wont be installed in LFIB",
658 interVpnLinkName, vrfEntry.getDestPrefix());
662 Optional<Uint32> optLportTag = interVpnLink.getEndpointLportTagByVpnName(vpnName);
663 if (!optLportTag.isPresent()) {
664 LOG.warn("Could not retrieve lportTag for VPN {} endpoint in InterVpnLink {}", vpnName, interVpnLinkName);
668 Long lportTag = optLportTag.get().toJava();
669 Uint32 label = FibUtil.getLabelFromRoutePaths(vrfEntry).orElse(null);
671 LOG.error("Could not find label in vrfEntry=[prefix={} routePaths={}]. LFIB entry for InterVpnLink skipped",
672 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
675 List<ActionInfo> actionsInfos = Collections.singletonList(new ActionPopMpls(etherType));
676 List<InstructionInfo> instructions = Arrays.asList(
677 new InstructionApplyActions(actionsInfos),
678 new InstructionWriteMetadata(MetaDataUtil.getMetaDataForLPortDispatcher(lportTag.intValue(),
679 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
680 NwConstants.L3VPN_SERVICE_INDEX)),
681 MetaDataUtil.getMetaDataMaskForLPortDispatcher()),
682 new InstructionGotoTable(NwConstants.L3_INTERFACE_TABLE));
683 List<String> interVpnNextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
684 List<Uint64> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnName);
686 for (Uint64 dpId : targetDpns) {
687 LOG.debug("Installing flow: VrfEntry=[prefix={} label={} nexthop={}] dpn {} for InterVpnLink {} in LFIB",
688 vrfEntry.getDestPrefix(), label, interVpnNextHopList, dpId, interVpnLink.getInterVpnLinkName());
690 makeLFibTableEntry(dpId, label, instructions, LFIB_INTERVPN_PRIORITY, NwConstants.ADD_FLOW,
697 * Installs the flows in FIB table that, for a given route, do the switching from one VPN to the other.
699 private void installIVpnLinkSwitchingFlows(final InterVpnLinkDataComposite interVpnLink, final String vpnUuid,
700 final VrfEntry vrfEntry, Uint32 vpnTag) {
701 Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
702 Preconditions.checkArgument(vrfEntry.getRoutePaths() != null
703 && vrfEntry.getRoutePaths().size() == 1);
704 String destination = vrfEntry.getDestPrefix();
705 String nextHop = new ArrayList<RoutePaths>(vrfEntry.getRoutePaths().values()).get(0).getNexthopAddress();
706 String interVpnLinkName = interVpnLink.getInterVpnLinkName();
708 // After having received a static route, we should check if the vpn is part of an inter-vpn-link.
709 // In that case, we should populate the FIB table of the VPN pointing to LPortDisptacher table
710 // using as metadata the LPortTag associated to that vpn in the inter-vpn-link.
711 if (interVpnLink.getState().orElse(State.Error) != State.Active) {
712 LOG.warn("Route to {} with nexthop={} cannot be installed because the interVpnLink {} is not active",
713 destination, nextHop, interVpnLinkName);
717 Optional<Uint32> optOtherEndpointLportTag = interVpnLink.getOtherEndpointLportTagByVpnName(vpnUuid);
718 if (!optOtherEndpointLportTag.isPresent()) {
719 LOG.warn("Could not find suitable LportTag for the endpoint opposite to vpn {} in interVpnLink {}",
720 vpnUuid, interVpnLinkName);
724 List<Uint64> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnUuid);
725 if (targetDpns.isEmpty()) {
726 LOG.warn("Could not find DPNs for endpoint opposite to vpn {} in interVpnLink {}",
727 vpnUuid, interVpnLinkName);
731 String[] values = destination.split("/");
732 String destPrefixIpAddress = values[0];
733 int prefixLength = values.length == 1 ? 0 : Integer.parseInt(values[1]);
735 List<MatchInfo> matches = new ArrayList<>();
736 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnTag.longValue()),
737 MetaDataUtil.METADATA_MASK_VRFID));
738 matches.add(MatchEthernetType.IPV4);
740 if (prefixLength != 0) {
741 matches.add(new MatchIpv4Destination(destPrefixIpAddress, Integer.toString(prefixLength)));
744 List<Instruction> instructions =
745 Arrays.asList(new InstructionWriteMetadata(
746 MetaDataUtil.getMetaDataForLPortDispatcher(optOtherEndpointLportTag.get().intValue(),
747 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants
748 .L3VPN_SERVICE_INDEX)),
749 MetaDataUtil.getMetaDataMaskForLPortDispatcher()).buildInstruction(0),
750 new InstructionGotoTable(NwConstants.L3_INTERFACE_TABLE).buildInstruction(1));
751 Map<InstructionKey, Instruction> instructionsMap = new HashMap<InstructionKey, Instruction>();
752 int instructionKey = 0;
753 for (Instruction instructionObj : instructions) {
754 instructionsMap.put(new InstructionKey(++instructionKey), instructionObj);
757 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
758 String flowRef = getInterVpnFibFlowRef(interVpnLinkName, destination, nextHop);
759 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
760 COOKIE_VM_FIB_TABLE, matches, instructionsMap);
762 LOG.trace("Installing flow in FIB table for vpn {} interVpnLink {} nextHop {} key {}",
763 vpnUuid, interVpnLink.getInterVpnLinkName(), nextHop, flowRef);
765 for (Uint64 dpId : targetDpns) {
767 LOG.debug("Installing flow: VrfEntry=[prefix={} route-paths={}] dpn {} for InterVpnLink {} in FIB",
768 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(),
769 dpId, interVpnLink.getInterVpnLinkName());
771 mdsalManager.installFlow(dpId, flowEntity);
775 private List<Uint64> createLocalFibEntry(Uint32 vpnId, String rd, VrfEntry vrfEntry, int etherType) {
776 List<Uint64> returnLocalDpnId = new ArrayList<>();
777 String localNextHopIP = vrfEntry.getDestPrefix();
778 Prefixes localNextHopInfo = fibUtil.getPrefixToInterface(vpnId, localNextHopIP);
779 String vpnName = fibUtil.getVpnNameFromId(vpnId);
780 if (localNextHopInfo == null) {
781 boolean localNextHopSeen = false;
782 List<Routes> vpnExtraRoutes = null;
783 //Synchronized to prevent missing bucket action due to race condition between refreshFib and
784 // add/updateFib threads on missing nexthop in VpnToExtraroutes
785 // FIXME: use an Identifier structure?
786 final ReentrantLock lock = JvmGlobalLocks.getLockForString(localNextHopIP + FibConstants.SEPARATOR + rd);
789 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, localNextHopIP);
790 vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker,
791 vpnName, usedRds, localNextHopIP);
792 if (LOG.isDebugEnabled()) {
793 LOG.debug("Creating Local fib entry with vpnName {} usedRds {} localNextHopIP {} vpnExtraRoutes {}",
794 vpnName, usedRds, localNextHopIP, vpnExtraRoutes);
797 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
798 for (Routes vpnExtraRoute : vpnExtraRoutes) {
800 if (isIpv4Address(vpnExtraRoute.getNexthopIpList().get(0))) {
801 ipPrefix = vpnExtraRoute.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX;
803 ipPrefix = vpnExtraRoute.getNexthopIpList().get(0) + NwConstants.IPV6PREFIX;
805 Prefixes localNextHopInfoLocal = fibUtil.getPrefixToInterface(vpnId,
807 if (localNextHopInfoLocal != null) {
808 localNextHopSeen = true;
810 checkCreateLocalFibEntry(localNextHopInfoLocal, localNextHopInfoLocal.getIpAddress(),
811 vpnId, rd, vrfEntry, vpnExtraRoute, vpnExtraRoutes, etherType,
812 /*parentVpnId*/ null);
813 returnLocalDpnId.add(dpnId);
819 if (!localNextHopSeen && RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
820 java.util.Optional<Uint32> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
821 if (optionalLabel.isPresent()) {
822 Uint32 label = optionalLabel.get();
823 List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
824 final LabelRouteInfoKey lriKey = new LabelRouteInfoKey(label);
825 final ReentrantLock labelLock = lockFor(lriKey);
828 LabelRouteInfo lri = getLabelRouteInfo(lriKey);
829 Uint32 parentVpnId = lri.getParentVpnid();
830 if (isPrefixAndNextHopPresentInLri(localNextHopIP, nextHopAddressList, lri)) {
831 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
832 fibUtil.getVpnInstanceOpData(rd);
833 if (vpnInstanceOpDataEntryOptional.isPresent()) {
834 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
835 if (lri.getVpnInstanceList() != null && lri.getVpnInstanceList().contains(
837 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, true);
838 localNextHopIP = lri.getPrefix();
840 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, false);
841 localNextHopIP = lri.getPrefix();
844 if (localNextHopInfo != null) {
845 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
846 label, localNextHopInfo.getVpnInterfaceName(), lri.getDpnId());
847 if (vpnExtraRoutes.isEmpty()) {
848 Uint64 dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP,
849 vpnId, rd, vrfEntry, null, vpnExtraRoutes, etherType, parentVpnId);
850 returnLocalDpnId.add(dpnId);
852 for (Routes extraRoutes : vpnExtraRoutes) {
853 Uint64 dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP,
854 vpnId, rd, vrfEntry, extraRoutes, vpnExtraRoutes, etherType,
856 returnLocalDpnId.add(dpnId);
866 if (returnLocalDpnId.isEmpty()) {
867 LOG.error("Local DPNID is empty for rd {}, vpnId {}, vrfEntry {}", rd, vpnId, vrfEntry);
870 Uint64 dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId,
871 rd, vrfEntry, /*routes*/ null, /*vpnExtraRoutes*/ null, etherType,
872 /*parentVpnId*/ null);
874 returnLocalDpnId.add(dpnId);
877 return returnLocalDpnId;
880 private Uint64 checkCreateLocalFibEntry(Prefixes localNextHopInfo, String localNextHopIP,
881 final Uint32 vpnId, final String rd,
882 final VrfEntry vrfEntry,
883 @Nullable Routes routes, @Nullable List<Routes> vpnExtraRoutes,
884 int etherType, Uint32 parentVpnId) {
885 String vpnName = fibUtil.getVpnNameFromId(vpnId);
886 if (localNextHopInfo != null) {
889 final Uint64 dpnId = localNextHopInfo.getDpnId();
890 if (Prefixes.PrefixCue.Nat.equals(localNextHopInfo.getPrefixCue())) {
891 LOG.debug("checkCreateLocalFibEntry: NAT Prefix {} with vpnId {} rd {}. Skip local dpn {}"
892 + " FIB processing", vrfEntry.getDestPrefix(), vpnId, rd, dpnId);
895 if (Prefixes.PrefixCue.PhysNetFunc.equals(localNextHopInfo.getPrefixCue())) {
896 LOG.debug("checkCreateLocalFibEntry: PNF Prefix {} with vpnId {} rd {}. Skip local dpn {}"
897 + " FIB processing", vrfEntry.getDestPrefix(), vpnId, rd, dpnId);
900 if (!isVpnPresentInDpn(rd, dpnId)) {
901 LOG.error("checkCreateLocalFibEntry: The VPN with id {} rd {} is not available on dpn {}",
902 vpnId, rd, dpnId.toString());
905 String interfaceName = localNextHopInfo.getVpnInterfaceName();
906 String prefix = vrfEntry.getDestPrefix();
907 String gwMacAddress = vrfEntry.getGatewayMacAddress();
908 //The loadbalancing group is created only if the extra route has multiple nexthops
909 //to avoid loadbalancing the discovered routes
910 if (RouteOrigin.STATIC.getValue().equals(vrfEntry.getOrigin()) && vpnExtraRoutes != null
912 if (vpnExtraRoutes.size() > 1) {
913 groupId = nextHopManager.createNextHopGroups(vpnId, rd, dpnId, vrfEntry, routes, vpnExtraRoutes);
914 localGroupId = nextHopManager.getLocalSelectGroup(vpnId, vrfEntry.getDestPrefix());
916 groupId = nextHopManager.createNextHopGroups(vpnId, rd, dpnId, vrfEntry, routes, vpnExtraRoutes);
917 localGroupId = groupId;
920 groupId = nextHopManager.createLocalNextHop(vpnId, dpnId, interfaceName, localNextHopIP, prefix,
921 gwMacAddress, parentVpnId);
922 localGroupId = groupId;
924 if (groupId == FibConstants.INVALID_GROUP_ID) {
925 LOG.error("Unable to create Group for local prefix {} on rd {} for vpninterface {} on Node {}",
926 prefix, rd, interfaceName, dpnId.toString());
929 final List<InstructionInfo> instructions = Collections.singletonList(
930 new InstructionApplyActions(
931 Collections.singletonList(new ActionGroup(groupId))));
932 final List<InstructionInfo> lfibinstructions = Collections.singletonList(
933 new InstructionApplyActions(
934 Arrays.asList(new ActionPopMpls(etherType), new ActionGroup(localGroupId))));
935 java.util.Optional<Uint32> optLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
936 List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
937 String jobKey = FibUtil.getCreateLocalNextHopJobKey(vpnId, dpnId, vrfEntry.getDestPrefix());
938 jobCoordinator.enqueueJob(jobKey,
939 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
940 baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions,
941 NwConstants.ADD_FLOW, TransactionAdapter.toWriteTransaction(tx), null);
942 if (FibUtil.isBgpVpn(vpnName, rd)) {
943 optLabel.ifPresent(label -> {
944 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
946 "Installing LFIB and tunnel table entry on dpn {} for interface {} with label "
947 + "{}, rd {}, prefix {}, nexthop {}", dpnId,
948 localNextHopInfo.getVpnInterfaceName(), optLabel, rd, vrfEntry.getDestPrefix(),
950 makeLFibTableEntry(dpnId, label, lfibinstructions, DEFAULT_FIB_FLOW_PRIORITY,
951 NwConstants.ADD_FLOW, tx);
952 makeTunnelTableEntry(dpnId, label, localGroupId, tx);
954 LOG.debug("Route with rd {} prefix {} label {} nexthop {} for vpn {} is an imported "
955 + "route. LFib and Terminating table entries will not be created.",
956 rd, vrfEntry.getDestPrefix(), optLabel, nextHopAddressList, vpnId);
963 LOG.error("localNextHopInfo received is null for prefix {} on rd {} on vpn {}", vrfEntry.getDestPrefix(), rd,
968 private boolean isVpnPresentInDpn(String rd, Uint64 dpnId) {
969 InstanceIdentifier<VpnToDpnList> id = VpnHelper.getVpnToDpnListIdentifier(rd, dpnId);
970 Optional<VpnToDpnList> dpnInVpn;
972 dpnInVpn = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
973 } catch (ExecutionException | InterruptedException e) {
974 LOG.error("isVpnPresentInDpn: Exception while reading VpnToDpnList Ds for the rd {} dpnId {}", rd,
978 return dpnInVpn.isPresent();
982 private LabelRouteInfo getLabelRouteInfo(Uint32 label) {
983 return getLabelRouteInfo(new LabelRouteInfoKey(label));
987 private LabelRouteInfo getLabelRouteInfo(LabelRouteInfoKey label) {
988 InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
989 .child(LabelRouteInfo.class, label).build();
990 Optional<LabelRouteInfo> opResult = null;
992 opResult = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
994 } catch (ExecutionException | InterruptedException e) {
995 LOG.error("refreshFibTables: Exception while reading LabelRouteInfo Ds for the label {}", label, e);
998 if (opResult.isPresent()) {
999 return opResult.get();
1004 private boolean deleteLabelRouteInfo(LabelRouteInfo lri, String vpnInstanceName,
1005 @Nullable TypedWriteTransaction<Operational> tx) {
1010 LOG.debug("deleting LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
1011 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
1012 .child(LabelRouteInfo.class, new LabelRouteInfoKey(lri.getLabel())).build();
1014 List<String> vpnInstancesList = lri.getVpnInstanceList() != null
1015 ? new ArrayList<>(lri.getVpnInstanceList()) : new ArrayList<>();
1016 if (vpnInstancesList.contains(vpnInstanceName)) {
1017 LOG.debug("vpninstance {} name is present", vpnInstanceName);
1018 vpnInstancesList.remove(vpnInstanceName);
1020 if (vpnInstancesList.isEmpty()) {
1021 LOG.debug("deleting LRI instance object for label {}", lri.getLabel());
1025 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId);
1029 LOG.debug("updating LRI instance object for label {}", lri.getLabel());
1030 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri).setVpnInstanceList(vpnInstancesList);
1031 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build());
1036 void makeTunnelTableEntry(Uint64 dpId, Uint32 label, long groupId/*String egressInterfaceName*/,
1037 TypedWriteTransaction<Configuration> tx) {
1038 List<ActionInfo> actionsInfos = Collections.singletonList(new ActionGroup(groupId));
1040 createTerminatingServiceActions(dpId, label, actionsInfos, tx);
1042 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully",
1043 dpId, label, groupId);
1046 public void createTerminatingServiceActions(Uint64 destDpId, Uint32 label, List<ActionInfo> actionsInfos,
1047 TypedWriteTransaction<Configuration> tx) {
1048 List<MatchInfo> mkMatches = new ArrayList<>();
1050 LOG.debug("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}",
1051 destDpId, label, actionsInfos);
1053 // Matching metadata
1054 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
1055 mkMatches.add(new MatchTunnelId(Uint64.valueOf(label.longValue())));
1057 List<InstructionInfo> mkInstructions = new ArrayList<>();
1058 mkInstructions.add(new InstructionApplyActions(actionsInfos));
1060 FlowEntity terminatingServiceTableFlowEntity =
1061 MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1062 getTableMissFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE, label),
1063 FibConstants.DEFAULT_VPN_INTERNAL_TUNNEL_TABLE_PRIORITY,
1064 String.format("%s:%s", "TST Flow Entry ", label), 0, 0,
1065 Uint64.valueOf(COOKIE_TUNNEL.longValue() + label.longValue()),
1066 mkMatches, mkInstructions);
1068 FlowKey flowKey = new FlowKey(new FlowId(terminatingServiceTableFlowEntity.getFlowId()));
1070 FlowBuilder flowbld = terminatingServiceTableFlowEntity.getFlowBuilder();
1072 Node nodeDpn = FibUtil.buildDpnNode(terminatingServiceTableFlowEntity.getDpnId());
1073 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1074 .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
1075 .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId()))
1076 .child(Flow.class, flowKey).build();
1077 tx.mergeParentStructurePut(flowInstanceId, flowbld.build());
1080 private void removeTunnelTableEntry(Uint64 dpId, Uint32 label, TypedWriteTransaction<Configuration> tx) {
1081 FlowEntity flowEntity;
1082 LOG.debug("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId, label);
1083 List<MatchInfo> mkMatches = new ArrayList<>();
1084 // Matching metadata
1085 mkMatches.add(new MatchTunnelId(Uint64.valueOf(label.longValue())));
1086 flowEntity = MDSALUtil.buildFlowEntity(dpId,
1087 NwConstants.INTERNAL_TUNNEL_TABLE,
1088 getTableMissFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, label),
1089 FibConstants.DEFAULT_VPN_INTERNAL_TUNNEL_TABLE_PRIORITY,
1090 String.format("%s:%s", "TST Flow Entry ", label), 0, 0,
1091 Uint64.valueOf(COOKIE_TUNNEL.longValue() + label.longValue()), mkMatches, null);
1092 Node nodeDpn = FibUtil.buildDpnNode(flowEntity.getDpnId());
1093 FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getFlowId()));
1094 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1095 .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
1096 .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build();
1098 tx.delete(flowInstanceId);
1099 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully", dpId, label);
1102 public List<Uint64> deleteLocalFibEntry(Uint32 vpnId, String rd, VrfEntry vrfEntry) {
1103 List<Uint64> returnLocalDpnId = new ArrayList<>();
1104 Prefixes localNextHopInfo = fibUtil.getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
1105 String vpnName = fibUtil.getVpnNameFromId(vpnId);
1106 boolean shouldUpdateNonEcmpLocalNextHop = true;
1107 if (localNextHopInfo == null) {
1108 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
1109 if (usedRds.size() > 1) {
1110 LOG.error("The extra route prefix {} is still present in some DPNs in vpn {} on rd {}",
1111 vrfEntry.getDestPrefix(), vpnName, rd);
1112 return returnLocalDpnId;
1114 String vpnRd = !usedRds.isEmpty() ? usedRds.get(0) : rd;
1115 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency
1117 Optional<Routes> extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker,
1118 vpnName, vpnRd, vrfEntry.getDestPrefix());
1119 if (extraRouteOptional.isPresent()) {
1120 Routes extraRoute = extraRouteOptional.get();
1122 if (isIpv4Address(extraRoute.getNexthopIpList().get(0))) {
1123 ipPrefix = extraRoute.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX;
1125 ipPrefix = extraRoute.getNexthopIpList().get(0) + NwConstants.IPV6PREFIX;
1127 if (extraRoute.getNexthopIpList().size() > 1) {
1128 shouldUpdateNonEcmpLocalNextHop = false;
1130 localNextHopInfo = fibUtil.getPrefixToInterface(vpnId, ipPrefix);
1131 if (localNextHopInfo != null) {
1132 String localNextHopIP = localNextHopInfo.getIpAddress();
1133 Uint64 dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP, vpnName, vpnId, rd,
1134 vrfEntry, shouldUpdateNonEcmpLocalNextHop);
1135 if (!dpnId.equals(Uint64.ZERO)) {
1136 LOG.trace("Deleting ECMP group for prefix {}, dpn {}", vrfEntry.getDestPrefix(), dpnId);
1137 nextHopManager.deleteLoadBalancingNextHop(vpnId, dpnId, vrfEntry.getDestPrefix());
1138 returnLocalDpnId.add(dpnId);
1141 LOG.error("localNextHopInfo unavailable while deleting prefix {} with rds {}, primary rd {} in "
1142 + "vpn {}", vrfEntry.getDestPrefix(), usedRds, rd, vpnName);
1146 if (localNextHopInfo == null) {
1147 /* Imported VRF entry */
1148 java.util.Optional<Uint32> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1149 if (optionalLabel.isPresent()) {
1150 Uint32 label = optionalLabel.get();
1151 List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
1152 LabelRouteInfo lri = getLabelRouteInfo(label);
1153 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
1154 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
1155 prefixBuilder.setDpnId(lri.getDpnId());
1156 Uint64 dpnId = checkDeleteLocalFibEntry(prefixBuilder.build(), nextHopAddressList.get(0),
1157 vpnName, vpnId, rd, vrfEntry, shouldUpdateNonEcmpLocalNextHop);
1158 if (!dpnId.equals(Uint64.ZERO)) {
1159 returnLocalDpnId.add(dpnId);
1166 LOG.debug("Obtained prefix to interface for rd {} prefix {}", rd, vrfEntry.getDestPrefix());
1167 String localNextHopIP = localNextHopInfo.getIpAddress();
1168 Uint64 dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP, vpnName, vpnId, rd, vrfEntry,
1169 shouldUpdateNonEcmpLocalNextHop);
1170 if (!dpnId.equals(Uint64.ZERO)) {
1171 returnLocalDpnId.add(dpnId);
1175 return returnLocalDpnId;
1178 private Uint64 checkDeleteLocalFibEntry(Prefixes localNextHopInfo, final String localNextHopIP,
1179 final String vpnName, final Uint32 vpnId, final String rd, final VrfEntry vrfEntry,
1180 boolean shouldUpdateNonEcmpLocalNextHop) {
1181 if (localNextHopInfo != null) {
1182 final Uint64 dpnId = localNextHopInfo.getDpnId();
1183 if (Prefixes.PrefixCue.Nat.equals(localNextHopInfo.getPrefixCue())) {
1184 LOG.debug("checkDeleteLocalFibEntry: NAT Prefix {} with vpnId {} rd {}. Skip local dpn {}"
1185 + " FIB processing", vrfEntry.getDestPrefix(), vpnId, rd, dpnId);
1188 if (Prefixes.PrefixCue.PhysNetFunc.equals(localNextHopInfo.getPrefixCue())) {
1189 LOG.debug("checkDeleteLocalFibEntry: PNF Prefix {} with vpnId {} rd {}. Skip local dpn {}"
1190 + " FIB processing", vrfEntry.getDestPrefix(), vpnId, rd, dpnId);
1194 jobCoordinator.enqueueJob(FibUtil.getCreateLocalNextHopJobKey(vpnId, dpnId, vrfEntry.getDestPrefix()),
1195 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1196 baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null,
1197 NwConstants.DEL_FLOW, TransactionAdapter.toWriteTransaction(tx), null);
1198 if (FibUtil.isBgpVpn(vpnName, rd)) {
1199 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1200 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
1201 makeLFibTableEntry(dpnId, label, null /* instructions */, DEFAULT_FIB_FLOW_PRIORITY,
1202 NwConstants.DEL_FLOW, tx);
1203 removeTunnelTableEntry(dpnId, label, tx);
1208 //TODO: verify below adjacency call need to be optimized (?)
1209 //In case of the removal of the extra route, the loadbalancing group is updated
1210 if (shouldUpdateNonEcmpLocalNextHop) {
1211 baseVrfEntryHandler.deleteLocalAdjacency(dpnId, vpnId, localNextHopIP, vrfEntry.getDestPrefix());
1218 private void createRemoteFibEntry(final Uint64 remoteDpnId, final Uint32 vpnId, String rd,
1219 final VrfEntry vrfEntry, TypedWriteTransaction<Configuration> tx) {
1221 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1222 newTx -> createRemoteFibEntry(remoteDpnId, vpnId, rd, vrfEntry, newTx)), LOG,
1223 "Error creating remote FIB entry");
1227 String vpnName = fibUtil.getVpnNameFromId(vpnId);
1228 LOG.debug("createremotefibentry: adding route {} for rd {} on remoteDpnId {}", vrfEntry.getDestPrefix(), rd,
1231 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.STATIC) {
1232 programRemoteFibEntry(remoteDpnId, vpnId, rd, vrfEntry, tx);
1235 // Handling static VRF entries
1236 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
1237 List<Routes> vpnExtraRoutes =
1238 VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker, vpnName, usedRds, vrfEntry.getDestPrefix());
1239 if (!vpnExtraRoutes.isEmpty()) {
1240 programRemoteFibWithLoadBalancingGroups(remoteDpnId, vpnId, rd, vrfEntry, vpnExtraRoutes);
1242 // Program in case of other static VRF entries like floating IPs
1243 programRemoteFibEntry(remoteDpnId, vpnId, rd, vrfEntry, tx);
1247 // Allow deprecated TransactionRunner calls for now
1248 @SuppressWarnings("ForbidCertainMethod")
1249 private void programRemoteFibWithLoadBalancingGroups(final Uint64 remoteDpnId, final Uint32 vpnId, String rd,
1250 final VrfEntry vrfEntry, List<Routes> vpnExtraRoutes) {
1251 // create loadbalancing groups for extra routes only when the extra route is
1252 // present behind multiple VMs
1253 // Obtain the local routes for this particular dpn.
1254 java.util.Optional<Routes> routes = vpnExtraRoutes.stream().filter(route -> {
1255 Prefixes prefixToInterface =
1256 fibUtil.getPrefixToInterface(vpnId, FibUtil.getIpPrefix(route.getNexthopIpList().get(0)));
1257 if (prefixToInterface == null) {
1260 return remoteDpnId.equals(prefixToInterface.getDpnId());
1262 long groupId = nextHopManager.createNextHopGroups(vpnId, rd, remoteDpnId, vrfEntry,
1263 routes.isPresent() ? routes.get() : null, vpnExtraRoutes);
1264 if (groupId == FibConstants.INVALID_GROUP_ID) {
1265 LOG.error("Unable to create Group for local prefix {} on rd {} on Node {}", vrfEntry.getDestPrefix(), rd,
1269 List<ActionInfo> actionInfos = Collections.singletonList(new ActionGroup(groupId));
1270 List<InstructionInfo> instructions = Lists.newArrayList(new InstructionApplyActions(actionInfos));
1271 String jobKey = FibUtil.getCreateRemoteNextHopJobKey(vpnId, remoteDpnId, vrfEntry.getDestPrefix());
1272 jobCoordinator.enqueueJob(jobKey,
1273 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(txn -> {
1274 baseVrfEntryHandler.makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions,
1275 NwConstants.ADD_FLOW, txn, null);
1278 LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
1281 private void programRemoteFibEntry(final Uint64 remoteDpnId, final Uint32 vpnId, String rd,
1282 final VrfEntry vrfEntry, TypedWriteTransaction<Configuration> tx) {
1283 List<AdjacencyResult> adjacencyResults = baseVrfEntryHandler.resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
1284 if (adjacencyResults.isEmpty()) {
1285 LOG.error("Could not get interface for route-paths: {} in vpn {} on DPN {}", vrfEntry.getRoutePaths(), rd,
1287 LOG.error("Failed to add Route: {} in vpn: {}", vrfEntry.getDestPrefix(), rd);
1290 baseVrfEntryHandler.programRemoteFib(remoteDpnId, vpnId, vrfEntry, TransactionAdapter.toWriteTransaction(tx),
1291 rd, adjacencyResults, null);
1292 LOG.debug("Successfully programmed FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
1295 protected void cleanUpOpDataForFib(Uint32 vpnId, String primaryRd, final VrfEntry vrfEntry) {
1296 /* Get interface info from prefix to interface mapping;
1297 Use the interface info to get the corresponding vpn interface op DS entry,
1298 remove the adjacency corresponding to this fib entry.
1299 If adjacency removed is the last adjacency, clean up the following:
1300 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
1301 - prefix to interface entry
1302 - vpn interface op DS
1304 LOG.debug("Cleanup of prefix {} in VPN {}", vrfEntry.getDestPrefix(), vpnId);
1305 Prefixes prefixInfo = fibUtil.getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
1306 if (prefixInfo == null) {
1307 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
1308 String usedRd = usedRds.isEmpty() ? primaryRd : usedRds.get(0);
1309 Routes extraRoute = baseVrfEntryHandler.getVpnToExtraroute(vpnId, usedRd, vrfEntry.getDestPrefix());
1310 if (extraRoute != null && extraRoute.getNexthopIpList() != null) {
1311 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1312 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
1313 if (nextHopIp != null) {
1315 if (isIpv4Address(nextHopIp)) {
1316 ipPrefix = nextHopIp + NwConstants.IPV4PREFIX;
1318 ipPrefix = nextHopIp + NwConstants.IPV6PREFIX;
1320 prefixInfo = fibUtil.getPrefixToInterface(vpnId, ipPrefix);
1321 checkCleanUpOpDataForFib(prefixInfo, vpnId, primaryRd, vrfEntry, extraRoute);
1325 if (prefixInfo == null) {
1326 java.util.Optional<Uint32> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1327 if (optionalLabel.isPresent()) {
1328 Uint32 label = optionalLabel.get();
1329 List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
1330 LabelRouteInfo lri = getLabelRouteInfo(label);
1331 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
1332 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
1333 prefixBuilder.setDpnId(lri.getDpnId());
1334 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
1335 prefixBuilder.setIpAddress(lri.getPrefix());
1336 prefixInfo = prefixBuilder.build();
1337 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
1338 label, prefixInfo.getVpnInterfaceName(), lri.getDpnId());
1339 checkCleanUpOpDataForFib(prefixInfo, vpnId, primaryRd, vrfEntry, extraRoute);
1344 checkCleanUpOpDataForFib(prefixInfo, vpnId, primaryRd, vrfEntry, null /*Routes*/);
1348 private void checkCleanUpOpDataForFib(final Prefixes prefixInfo, final Uint32 vpnId, final String rd,
1349 final VrfEntry vrfEntry, @Nullable final Routes extraRoute) {
1351 if (prefixInfo == null) {
1352 LOG.error("Cleanup VPN Data Failed as unable to find prefix Info for prefix {} VpnId {} rd {}",
1353 vrfEntry.getDestPrefix(), vpnId, rd);
1354 return; //Don't have any info for this prefix (shouldn't happen); need to return
1357 if (Prefixes.PrefixCue.Nat.equals(prefixInfo.getPrefixCue())) {
1358 LOG.debug("NAT Prefix {} with vpnId {} rd {}. Skip FIB processing",
1359 vrfEntry.getDestPrefix(), vpnId, rd);
1363 String ifName = prefixInfo.getVpnInterfaceName();
1364 jobCoordinator.enqueueJob("VPNINTERFACE-" + ifName,
1365 new CleanupVpnInterfaceWorker(prefixInfo, vpnId, rd, vrfEntry, extraRoute));
1368 private class CleanupVpnInterfaceWorker implements Callable<List<? extends ListenableFuture<?>>> {
1369 Prefixes prefixInfo;
1375 CleanupVpnInterfaceWorker(final Prefixes prefixInfo, final Uint32 vpnId, final String rd,
1376 final VrfEntry vrfEntry, final Routes extraRoute) {
1377 this.prefixInfo = prefixInfo;
1380 this.vrfEntry = vrfEntry;
1381 this.extraRoute = extraRoute;
1385 public List<ListenableFuture<Void>> call() {
1386 // If another renderer(for eg : CSS) needs to be supported, check can be performed here
1387 // to call the respective helpers.
1388 return Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> {
1389 //First Cleanup LabelRouteInfo
1390 //TODO(KIRAN) : Move the below block when addressing iRT/eRT for L3VPN Over VxLan
1391 LOG.debug("cleanupVpnInterfaceWorker: rd {} prefix {}", rd, prefixInfo.getIpAddress());
1392 if (VrfEntry.EncapType.Mplsgre.equals(vrfEntry.getEncapType())) {
1393 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
1394 List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
1395 final LabelRouteInfoKey lriKey = new LabelRouteInfoKey(label);
1396 final ReentrantLock lock = lockFor(lriKey);
1399 LabelRouteInfo lri = getLabelRouteInfo(lriKey);
1400 if (lri != null && Objects.equals(lri.getPrefix(), vrfEntry.getDestPrefix())
1401 && nextHopAddressList.contains(lri.getNextHopIpList().get(0))) {
1402 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
1403 fibUtil.getVpnInstanceOpData(rd);
1404 String vpnInstanceName = "";
1405 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1406 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1408 boolean lriRemoved = deleteLabelRouteInfo(lri, vpnInstanceName, tx);
1410 String parentRd = lri.getParentVpnRd();
1411 fibUtil.releaseId(FibConstants.VPN_IDPOOL_NAME, FibUtil.getNextHopLabelKey(
1412 parentRd, vrfEntry.getDestPrefix()));
1415 fibUtil.releaseId(FibConstants.VPN_IDPOOL_NAME, FibUtil.getNextHopLabelKey(
1416 rd, vrfEntry.getDestPrefix()));
1423 String ifName = prefixInfo.getVpnInterfaceName();
1424 Optional<String> optVpnName = fibUtil.getVpnNameFromRd(rd);
1425 String vpnName = null;
1427 if (Prefixes.PrefixCue.PhysNetFunc.equals(prefixInfo.getPrefixCue())) {
1428 // Get vpnId for rd = networkId since op vpnInterface will be pointing to rd = networkId
1429 Optional<String> vpnNameOpt = fibUtil.getVpnNameFromRd(vrfEntry.getParentVpnRd());
1430 if (vpnNameOpt.isPresent()) {
1431 vpnId = fibUtil.getVpnId(vpnNameOpt.get());
1434 if (optVpnName.isPresent()) {
1435 vpnName = optVpnName.get();
1436 Optional<VpnInterfaceOpDataEntry> opVpnInterface = tx
1437 .read(FibUtil.getVpnInterfaceOpDataEntryIdentifier(ifName, vpnName)).get();
1438 if (opVpnInterface.isPresent()) {
1439 Uint32 associatedVpnId = fibUtil.getVpnId(vpnName);
1440 if (!Objects.equals(vpnId, associatedVpnId)) {
1441 LOG.warn("Prefixes {} are associated with different vpn instance with id {} rather than {}",
1442 vrfEntry.getDestPrefix(), associatedVpnId, vpnId);
1443 LOG.warn("Not proceeding with Cleanup op data for prefix {}", vrfEntry.getDestPrefix());
1446 LOG.debug("Processing cleanup of prefix {} associated with vpn {}",
1447 vrfEntry.getDestPrefix(), associatedVpnId);
1451 if (extraRoute != null) {
1452 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
1453 //Only one used Rd present in case of removal event
1454 String usedRd = usedRds.get(0);
1455 if (optVpnName.isPresent()) {
1456 tx.delete(BaseVrfEntryHandler.getVpnToExtrarouteIdentifier(vpnName, usedRd,
1457 vrfEntry.getDestPrefix()));
1458 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, configTx ->
1459 configTx.delete(VpnExtraRouteHelper.getUsedRdsIdentifier(vpnId, vrfEntry.getDestPrefix())));
1462 handleAdjacencyAndVpnOpInterfaceDeletion(vrfEntry, ifName, vpnName, tx);
1468 * Check all the adjacency in VpnInterfaceOpData and decide whether to delete the entire interface or only adj.
1469 * Remove Adjacency from VPNInterfaceOpData.
1470 * if Adjacency != primary.
1471 * if Adjacency == primary , then mark it for deletion.
1472 * Remove entire VPNinterfaceOpData Entry.
1473 * if sie of Adjacency <= 2 and all are marked for deletion , delete the entire VPNinterface Op entry.
1474 * @param vrfEntry - VrfEntry removed
1475 * @param ifName - Interface name from VRFentry
1476 * @param vpnName - VPN name of corresponding VRF
1477 * @param tx - ReadWrite Tx
1479 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
1480 justification = "https://github.com/spotbugs/spotbugs/issues/811")
1481 private void handleAdjacencyAndVpnOpInterfaceDeletion(VrfEntry vrfEntry, String ifName, String vpnName,
1482 TypedReadWriteTransaction<Operational> tx)
1483 throws ExecutionException, InterruptedException {
1484 InstanceIdentifier<Adjacency> adjacencyIid =
1485 FibUtil.getAdjacencyIdentifierOp(ifName, vpnName, vrfEntry.getDestPrefix());
1486 Optional<Adjacency> adjacencyOptional = tx.read(adjacencyIid).get();
1487 if (adjacencyOptional.isPresent()) {
1488 if (adjacencyOptional.get().getAdjacencyType() != Adjacency.AdjacencyType.PrimaryAdjacency) {
1489 tx.delete(FibUtil.getAdjacencyIdentifierOp(ifName, vpnName, vrfEntry.getDestPrefix()));
1491 tx.merge(adjacencyIid,
1492 new AdjacencyBuilder(adjacencyOptional.get()).setMarkedForDeletion(true).build());
1496 Optional<AdjacenciesOp> optAdjacencies = tx.read(FibUtil.getAdjListPathOp(ifName, vpnName)).get();
1498 if (!optAdjacencies.isPresent() || optAdjacencies.get().getAdjacency() == null) {
1502 @NonNull List<Adjacency> adjacencies
1503 = new ArrayList<Adjacency>(optAdjacencies.get().nonnullAdjacency().values());
1504 if (adjacencies.size() <= 2
1505 && adjacencies.stream().allMatch(adjacency ->
1506 adjacency.getAdjacencyType() == Adjacency.AdjacencyType.PrimaryAdjacency
1507 && adjacency.isMarkedForDeletion() != null
1508 && adjacency.isMarkedForDeletion()
1510 LOG.info("Clean up vpn interface {} to vpn {} list.", ifName, vpnName);
1511 tx.delete(FibUtil.getVpnInterfaceOpDataEntryIdentifier(ifName, vpnName));
1515 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1516 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1517 final String rd = vrfTableKey.getRouteDistinguisher();
1518 final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(vrfTableKey.getRouteDistinguisher());
1519 if (vpnInstance == null) {
1520 LOG.error("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1523 final Map<VpnToDpnListKey, VpnToDpnList> keyVpnToDpnListMap;
1524 if (vrfEntry.getParentVpnRd() != null
1525 && FibHelper.isControllerManagedNonSelfImportedRoute(RouteOrigin.value(vrfEntry.getOrigin()))) {
1526 // This block MUST BE HIT only for PNF (Physical Network Function) FIB Entries.
1527 VpnInstanceOpDataEntry parentVpnInstance = fibUtil.getVpnInstance(vrfEntry.getParentVpnRd());
1528 keyVpnToDpnListMap = parentVpnInstance != null ? parentVpnInstance.getVpnToDpnList() :
1529 vpnInstance.getVpnToDpnList();
1530 LOG.info("deleteFibEntries: Processing deletion of PNF FIB entry with rd {} prefix {}",
1531 vrfEntry.getParentVpnRd(), vrfEntry.getDestPrefix());
1533 keyVpnToDpnListMap = vpnInstance.getVpnToDpnList();
1536 SubnetRoute subnetRoute = vrfEntry.augmentation(SubnetRoute.class);
1537 final java.util.Optional<Uint32> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1538 List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
1539 String vpnName = fibUtil.getVpnNameFromId(vpnInstance.getVpnId());
1540 if (subnetRoute != null) {
1541 long elanTag = subnetRoute.getElantag().toJava();
1542 LOG.trace("SUBNETROUTE: deleteFibEntries: SubnetRoute augmented vrfentry found for rd {} prefix {}"
1543 + " with elantag {}", rd, vrfEntry.getDestPrefix(), elanTag);
1544 if (keyVpnToDpnListMap != null) {
1545 jobCoordinator.enqueueJob(FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix()),
1546 () -> Collections.singletonList(
1547 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1548 for (final VpnToDpnList curDpn : keyVpnToDpnListMap.values()) {
1550 baseVrfEntryHandler.makeConnectedRoute(curDpn.getDpnId(),
1551 vpnInstance.getVpnId(),
1552 vrfEntry, vrfTableKey.getRouteDistinguisher(), null,
1553 NwConstants.DEL_FLOW, TransactionAdapter.toWriteTransaction(tx), null);
1554 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1555 optionalLabel.ifPresent(label -> makeLFibTableEntry(curDpn.getDpnId(),
1556 label, null, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx));
1559 installSubnetBroadcastAddrDropRule(curDpn.getDpnId(), rd,
1560 vpnInstance.getVpnId(),
1561 vrfEntry, NwConstants.DEL_FLOW, tx);
1565 optionalLabel.ifPresent(label -> {
1566 final LabelRouteInfoKey lriKey = new LabelRouteInfoKey(label);
1567 final ReentrantLock lock = lockFor(lriKey);
1570 LabelRouteInfo lri = getLabelRouteInfo(lriKey);
1571 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
1572 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
1573 fibUtil.getVpnInstanceOpData(rd);
1574 String vpnInstanceName = "";
1575 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1576 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1578 boolean lriRemoved = this.deleteLabelRouteInfo(lri, vpnInstanceName, null);
1580 String parentRd = lri.getParentVpnRd();
1581 fibUtil.releaseId(FibConstants.VPN_IDPOOL_NAME, FibUtil.getNextHopLabelKey(
1582 parentRd, vrfEntry.getDestPrefix()));
1583 LOG.trace("SUBNETROUTE: deleteFibEntries: Released subnetroute label {} for rd {} prefix {}"
1584 + " as labelRouteInfo cleared", label, rd, vrfEntry.getDestPrefix());
1587 fibUtil.releaseId(FibConstants.VPN_IDPOOL_NAME, FibUtil.getNextHopLabelKey(
1588 rd, vrfEntry.getDestPrefix()));
1589 LOG.trace("SUBNETROUTE: deleteFibEntries: Released subnetroute label {} for rd {} prefix {}",
1590 label, rd, vrfEntry.getDestPrefix());
1599 final List<Uint64> localDpnIdList = deleteLocalFibEntry(vpnInstance.getVpnId(),
1600 vrfTableKey.getRouteDistinguisher(), vrfEntry);
1601 if (keyVpnToDpnListMap != null) {
1602 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker,
1603 vpnInstance.getVpnId(), vrfEntry.getDestPrefix());
1605 Optional<Routes> extraRouteOptional;
1606 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
1607 if (usedRds != null && !usedRds.isEmpty()) {
1608 if (usedRds.size() > 1) {
1609 LOG.error("The extra route prefix is still present in some DPNs");
1612 // The first rd is retrieved from usedrds as Only 1 rd would be present as extra route prefix
1613 //is not present in any other DPN
1614 extraRouteOptional = VpnExtraRouteHelper
1615 .getVpnExtraroutes(dataBroker, vpnName, usedRds.get(0), vrfEntry.getDestPrefix());
1618 extraRouteOptional = Optional.empty();
1621 jobCoordinator.enqueueJob(FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix()),
1622 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1623 if (localDpnIdList.size() <= 0) {
1624 for (VpnToDpnList curDpn : keyVpnToDpnListMap.values()) {
1625 baseVrfEntryHandler.deleteRemoteRoute(Uint64.ZERO, curDpn.getDpnId(),
1626 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional,
1627 TransactionAdapter.toWriteTransaction(tx));
1630 for (Uint64 localDpnId : localDpnIdList) {
1631 for (VpnToDpnList curDpn : keyVpnToDpnListMap.values()) {
1632 if (!Objects.equals(curDpn.getDpnId(), localDpnId)) {
1633 baseVrfEntryHandler.deleteRemoteRoute(localDpnId, curDpn.getDpnId(),
1634 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional,
1635 TransactionAdapter.toWriteTransaction(tx));
1640 if (extraRouteOptional.isPresent()) {
1641 //Remove select groups only for extra-routes
1642 nextHopManager.removeNextHopPointer(nextHopManager
1643 .getRemoteSelectGroupKey(vpnInstance.getVpnId(), vrfEntry.getDestPrefix()));
1644 nextHopManager.removeNextHopPointer(nextHopManager
1645 .getLocalSelectGroupKey(vpnInstance.getVpnId(), vrfEntry.getDestPrefix()));
1650 //The flow/group entry has been deleted from config DS; need to clean up associated operational
1651 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
1652 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
1654 // Remove all fib entries configured due to interVpnLink, when nexthop is the opposite endPoint
1655 // of the interVpnLink.
1656 Optional<String> optVpnUuid = fibUtil.getVpnNameFromRd(rd);
1657 if (optVpnUuid.isPresent()) {
1658 String vpnUuid = optVpnUuid.get();
1659 FibUtil.getFirstNextHopAddress(vrfEntry).ifPresent(routeNexthop -> {
1660 Optional<InterVpnLinkDataComposite> optInterVpnLink = interVpnLinkCache.getInterVpnLinkByVpnId(vpnUuid);
1661 if (optInterVpnLink.isPresent()) {
1662 InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
1663 if (interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid)) {
1664 // This is route that points to the other endpoint of an InterVpnLink
1665 // In that case, we should look for the FIB table pointing to
1666 // LPortDispatcher table and remove it.
1667 removeInterVPNLinkRouteFlows(interVpnLink, vpnUuid, vrfEntry);
1675 private void makeLFibTableEntry(Uint64 dpId, Uint32 label, @Nullable List<InstructionInfo> instructions,
1676 int priority, int addOrRemove, TypedWriteTransaction<Configuration> tx) {
1678 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
1679 newTx -> makeLFibTableEntry(dpId, label, instructions, priority, addOrRemove, newTx)), LOG,
1680 "Error making LFIB table entry");
1684 List<MatchInfo> matches = new ArrayList<>();
1685 matches.add(MatchEthernetType.MPLS_UNICAST);
1686 matches.add(new MatchMplsLabel(label.longValue()));
1688 // Install the flow entry in L3_LFIB_TABLE
1689 String flowRef = FibUtil.getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, priority);
1691 FlowEntity flowEntity;
1692 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef, priority, flowRef, 0, 0,
1693 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
1694 Flow flow = flowEntity.getFlowBuilder().build();
1695 String flowId = flowEntity.getFlowId();
1696 FlowKey flowKey = new FlowKey(new FlowId(flowId));
1697 Node nodeDpn = FibUtil.buildDpnNode(dpId);
1698 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1699 .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
1700 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1702 if (addOrRemove == NwConstants.ADD_FLOW) {
1703 tx.mergeParentStructurePut(flowInstanceId, flow);
1705 tx.delete(flowInstanceId);
1708 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} : key {} {} successfully",
1709 dpId, label, instructions, flowKey, NwConstants.ADD_FLOW == addOrRemove ? "ADDED" : "REMOVED");
1712 public void populateFibOnNewDpn(final Uint64 dpnId, final Uint32 vpnId, final String rd,
1713 final FutureCallback<List<Void>> callback) {
1714 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
1715 jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, dpnId),
1717 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1718 final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(rd);
1719 final Optional<VrfTables> vrfTable = MDSALUtil.read(dataBroker,
1720 LogicalDatastoreType.CONFIGURATION, id);
1721 List<ListenableFuture<Void>> futures = new ArrayList<>();
1722 if (!vrfTable.isPresent()) {
1723 LOG.info("populateFibOnNewDpn: dpn: {}: VRF Table not yet available for RD {}", dpnId, rd);
1724 if (callback != null) {
1725 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1726 Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor());
1731 final ReentrantLock lock = lockFor(vpnInstance);
1734 futures.add(retryingTxRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
1735 for (final VrfEntry vrfEntry : vrfTable.get().nonnullVrfEntry().values()) {
1736 SubnetRoute subnetRoute = vrfEntry.augmentation(SubnetRoute.class);
1737 if (subnetRoute != null) {
1738 long elanTag = subnetRoute.getElantag().toJava();
1739 installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
1740 installSubnetBroadcastAddrDropRule(dpnId, rd, vpnId, vrfEntry, NwConstants.ADD_FLOW,
1744 RouterInterface routerInt = vrfEntry.augmentation(RouterInterface.class);
1745 if (routerInt != null) {
1746 LOG.trace("Router augmented vrfentry found rd:{}, uuid:{}, ip:{}, mac:{}",
1747 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
1748 routerInterfaceVrfEntryHandler.installRouterFibEntry(vrfEntry, dpnId, vpnId,
1749 routerInt.getIpAddress(), new MacAddress(routerInt.getMacAddress()),
1750 NwConstants.ADD_FLOW);
1753 //Handle local flow creation for imports
1754 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
1755 java.util.Optional<Uint32> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1756 if (optionalLabel.isPresent()) {
1757 List<String> nextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
1758 LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get());
1759 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList, lri)) {
1760 if (Objects.equals(lri.getDpnId(), dpnId)) {
1762 int etherType = NWUtil.getEtherTypeFromIpPrefix(
1763 vrfEntry.getDestPrefix());
1764 createLocalFibEntry(vpnId, rd, vrfEntry, etherType);
1765 } catch (IllegalArgumentException ex) {
1766 LOG.warn("Unable to get etherType for IP Prefix {}",
1767 vrfEntry.getDestPrefix());
1774 boolean shouldCreateRemoteFibEntry = shouldCreateFibEntryForVrfAndVpnIdOnDpn(vpnId,
1776 if (shouldCreateRemoteFibEntry) {
1777 LOG.trace("Will create remote FIB entry for vrfEntry {} on DPN {}", vrfEntry, dpnId);
1778 if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
1779 List<SubTransaction> txnObjects = new ArrayList<>();
1780 bgpRouteVrfEntryHandler.createRemoteFibEntry(dpnId, vpnId,
1781 vrfTable.get().getRouteDistinguisher(), vrfEntry,
1782 TransactionAdapter.toWriteTransaction(tx), txnObjects);
1784 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getRouteDistinguisher(),
1790 if (callback != null) {
1791 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1792 Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor());
1801 public void populateExternalRoutesOnDpn(final Uint64 dpnId, final Uint32 vpnId, final String rd,
1802 final String localNextHopIp, final String remoteNextHopIp) {
1803 LOG.trace("populateExternalRoutesOnDpn : dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} ",
1804 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1805 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1806 final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(rd);
1807 List<SubTransaction> txnObjects = new ArrayList<>();
1808 final Optional<VrfTables> vrfTable;
1810 vrfTable = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1811 } catch (ExecutionException | InterruptedException e) {
1812 LOG.error("populateExternalRoutesOnDpn: Exception while reading the VrfTable for the rd {}", rd, e);
1815 if (vrfTable.isPresent()) {
1816 jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, dpnId),
1817 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1818 final ReentrantLock lock = lockFor(vpnInstance);
1821 vrfTable.get().nonnullVrfEntry().values().stream()
1822 .filter(vrfEntry -> RouteOrigin.BGP == RouteOrigin.value(vrfEntry.getOrigin()))
1823 .forEach(bgpRouteVrfEntryHandler.getConsumerForCreatingRemoteFib(dpnId, vpnId,
1824 rd, remoteNextHopIp, vrfTable, TransactionAdapter.toWriteTransaction(tx), txnObjects));
1832 public void manageRemoteRouteOnDPN(final boolean action,
1833 final Uint64 localDpnId,
1836 final String destPrefix,
1837 final String destTepIp,
1838 final Uint32 label) {
1839 final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(rd);
1841 if (vpnInstance == null) {
1842 LOG.error("VpnInstance for rd {} not present for prefix {}", rd, destPrefix);
1846 jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, localDpnId),
1847 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1848 final ReentrantLock lock = lockFor(vpnInstance);
1851 VrfTablesKey vrfTablesKey = new VrfTablesKey(rd);
1852 VrfEntry vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1853 if (vrfEntry == null) {
1856 LOG.trace("manageRemoteRouteOnDPN :: action {}, DpnId {}, vpnId {}, rd {}, destPfx {}",
1857 action, localDpnId, vpnId, rd, destPrefix);
1858 Map<RoutePathsKey, RoutePaths> keyRoutePathsMap = vrfEntry.getRoutePaths();
1859 VrfEntry modVrfEntry;
1860 if (keyRoutePathsMap == null || keyRoutePathsMap.isEmpty()) {
1861 modVrfEntry = FibHelper.getVrfEntryBuilder(vrfEntry, label,
1862 Collections.singletonList(destTepIp),
1863 RouteOrigin.value(vrfEntry.getOrigin()), null /* parentVpnRd */).build();
1865 modVrfEntry = vrfEntry;
1869 LOG.trace("manageRemoteRouteOnDPN updated(add) vrfEntry :: {}", modVrfEntry);
1870 createRemoteFibEntry(localDpnId, vpnId, vrfTablesKey.getRouteDistinguisher(),
1873 LOG.trace("manageRemoteRouteOnDPN updated(remove) vrfEntry :: {}", modVrfEntry);
1874 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker,
1875 vpnInstance.getVpnId(), vrfEntry.getDestPrefix());
1876 if (usedRds.size() > 1) {
1877 LOG.debug("The extra route prefix is still present in some DPNs");
1880 //Is this fib route an extra route? If yes, get the nexthop which would be
1881 //an adjacency in the vpn
1882 Optional<Routes> extraRouteOptional = Optional.empty();
1883 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.STATIC && usedRds.size() != 0) {
1884 extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker,
1885 fibUtil.getVpnNameFromId(vpnInstance.getVpnId()),
1886 usedRds.get(0), vrfEntry.getDestPrefix());
1888 baseVrfEntryHandler.deleteRemoteRoute(null, localDpnId, vpnId, vrfTablesKey, modVrfEntry,
1889 extraRouteOptional, TransactionAdapter.toWriteTransaction(tx));
1897 public void cleanUpDpnForVpn(final Uint64 dpnId, final Uint32 vpnId, final String rd,
1898 final FutureCallback<List<Void>> callback) {
1899 LOG.trace("cleanUpDpnForVpn: Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
1900 jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, dpnId),
1902 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1903 final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(rd);
1904 List<SubTransaction> txnObjects = new ArrayList<>();
1905 final Optional<VrfTables> vrfTable = MDSALUtil.read(dataBroker,
1906 LogicalDatastoreType.CONFIGURATION, id);
1907 List<ListenableFuture<Void>> futures = new ArrayList<>();
1908 if (!vrfTable.isPresent()) {
1909 LOG.error("cleanUpDpnForVpn: VRF Table not available for RD {}", rd);
1910 if (callback != null) {
1911 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1912 Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor());
1916 final ReentrantLock lock = lockFor(vpnInstance);
1919 futures.add(retryingTxRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
1920 String vpnName = fibUtil.getVpnNameFromId(vpnInstance.getVpnId());
1921 for (final VrfEntry vrfEntry : vrfTable.get().nonnullVrfEntry().values()) {
1922 /* parentRd is only filled for external PNF cases where the interface on the external
1923 * network VPN are used to cleanup the flows. For all other cases, use "rd" for
1924 * #fibUtil.isInterfacePresentInDpn().
1926 String parentRd = vrfEntry.getParentVpnRd() != null ? vrfEntry.getParentVpnRd()
1928 /* Handle subnet routes here */
1929 SubnetRoute subnetRoute = vrfEntry.augmentation(SubnetRoute.class);
1930 if (subnetRoute != null && !fibUtil
1931 .isInterfacePresentInDpn(parentRd, dpnId)) {
1932 LOG.trace("SUBNETROUTE: cleanUpDpnForVpn: Cleaning subnetroute {} on dpn {}"
1933 + " for vpn {}", vrfEntry.getDestPrefix(), dpnId, rd);
1934 baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null,
1935 NwConstants.DEL_FLOW, TransactionAdapter.toWriteTransaction(tx), null);
1936 Map<RoutePathsKey, RoutePaths> keyRoutePathsMap = vrfEntry.getRoutePaths();
1937 if (keyRoutePathsMap != null) {
1938 for (RoutePaths routePath : keyRoutePathsMap.values()) {
1939 makeLFibTableEntry(dpnId, routePath.getLabel(), null,
1940 DEFAULT_FIB_FLOW_PRIORITY,
1941 NwConstants.DEL_FLOW, tx);
1942 LOG.trace("SUBNETROUTE: cleanUpDpnForVpn: Released subnetroute label {}"
1943 + " for rd {} prefix {}", routePath.getLabel(), rd,
1944 vrfEntry.getDestPrefix());
1947 installSubnetBroadcastAddrDropRule(dpnId, rd, vpnId, vrfEntry,
1948 NwConstants.DEL_FLOW, tx);
1951 // ping responder for router interfaces
1952 RouterInterface routerInt = vrfEntry.augmentation(RouterInterface.class);
1953 if (routerInt != null) {
1954 LOG.trace("Router augmented vrfentry found for rd:{}, uuid:{}, ip:{}, mac:{}",
1955 rd, routerInt.getUuid(), routerInt.getIpAddress(),
1956 routerInt.getMacAddress());
1957 routerInterfaceVrfEntryHandler.installRouterFibEntry(vrfEntry, dpnId, vpnId,
1958 routerInt.getIpAddress(), new MacAddress(routerInt.getMacAddress()),
1959 NwConstants.DEL_FLOW);
1962 //Handle local flow deletion for imports
1963 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
1964 java.util.Optional<Uint32> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1965 if (optionalLabel.isPresent()) {
1966 List<String> nextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
1967 LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get());
1968 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList,
1969 lri) && Objects.equals(lri.getDpnId(), dpnId)) {
1970 deleteLocalFibEntry(vpnId, rd, vrfEntry);
1974 // Passing null as we don't know the dpn
1975 // to which prefix is attached at this point
1976 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker,
1977 vpnInstance.getVpnId(), vrfEntry.getDestPrefix());
1978 Optional<Routes> extraRouteOptional;
1979 //Is this fib route an extra route? If yes, get the nexthop which would be
1980 //an adjacency in the vpn
1981 if (usedRds != null && !usedRds.isEmpty()) {
1982 if (usedRds.size() > 1) {
1983 LOG.error("The extra route prefix is still present in some DPNs");
1986 extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, vpnName,
1987 usedRds.get(0), vrfEntry.getDestPrefix());
1991 extraRouteOptional = Optional.empty();
1993 if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
1994 bgpRouteVrfEntryHandler.deleteRemoteRoute(null, dpnId, vpnId,
1995 vrfTable.get().key(), vrfEntry, extraRouteOptional,
1996 TransactionAdapter.toWriteTransaction(tx), txnObjects);
1998 if (subnetRoute == null || !fibUtil
1999 .isInterfacePresentInDpn(parentRd, dpnId)) {
2000 baseVrfEntryHandler.deleteRemoteRoute(null, dpnId, vpnId,
2001 vrfTable.get().key(), vrfEntry, extraRouteOptional,
2002 TransactionAdapter.toWriteTransaction(tx));
2010 if (callback != null) {
2011 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
2012 Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor());
2018 public void cleanUpExternalRoutesOnDpn(final Uint64 dpnId, final Uint32 vpnId, final String rd,
2019 final String localNextHopIp, final String remoteNextHopIp) {
2020 LOG.trace("cleanUpExternalRoutesOnDpn : cleanup remote routes on dpn {} for vpn {}, rd {}, "
2021 + " localNexthopIp {} , remoteNexhtHopIp {}",
2022 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
2023 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
2024 final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(rd);
2025 List<SubTransaction> txnObjects = new ArrayList<>();
2026 final Optional<VrfTables> vrfTable;
2028 vrfTable = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2029 } catch (ExecutionException | InterruptedException e) {
2030 LOG.error("getVrfEntry: Exception while reading VrfTable for the rd {} vpnId {}", rd, vpnId, e);
2033 if (vrfTable.isPresent()) {
2034 jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, dpnId),
2036 final ReentrantLock lock = lockFor(vpnInstance);
2039 return Collections.singletonList(
2040 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
2041 tx -> vrfTable.get().nonnullVrfEntry().values().stream()
2042 .filter(vrfEntry -> RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP)
2043 .forEach(bgpRouteVrfEntryHandler.getConsumerForDeletingRemoteFib(dpnId, vpnId,
2044 remoteNextHopIp, vrfTable, TransactionAdapter.toWriteTransaction(tx),
2053 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
2054 InstanceIdentifierBuilder<VrfTables> idBuilder =
2055 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
2056 return idBuilder.build();
2059 private String getInterVpnFibFlowRef(String interVpnLinkName, String prefix, String nextHop) {
2060 return FLOWID_PREFIX + interVpnLinkName + NwConstants.FLOWID_SEPARATOR + prefix + NwConstants
2061 .FLOWID_SEPARATOR + nextHop;
2064 private String getTableMissFlowRef(Uint64 dpnId, short tableId, Uint32 tableMiss) {
2065 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR
2066 + tableMiss + FLOWID_PREFIX;
2070 private VrfEntry getVrfEntry(DataBroker broker, String rd, String ipPrefix) {
2071 InstanceIdentifier<VrfEntry> vrfEntryId = InstanceIdentifier.builder(FibEntries.class)
2072 .child(VrfTables.class, new VrfTablesKey(rd))
2073 .child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2074 Optional<VrfEntry> vrfEntry;
2076 vrfEntry = SingleTransactionDataBroker.syncReadOptional(broker, LogicalDatastoreType.CONFIGURATION,
2078 } catch (ExecutionException | InterruptedException e) {
2079 LOG.error("getVrfEntry: Exception while reading VrfEntry for the prefix {} rd {}", ipPrefix, rd, e);
2082 if (vrfEntry.isPresent()) {
2083 return vrfEntry.get();
2088 public void removeInterVPNLinkRouteFlows(final InterVpnLinkDataComposite interVpnLink,
2089 final String vpnName,
2090 final VrfEntry vrfEntry) {
2091 Preconditions.checkArgument(vrfEntry.getRoutePaths() != null && vrfEntry.getRoutePaths().size() == 1);
2093 String interVpnLinkName = interVpnLink.getInterVpnLinkName();
2094 List<Uint64> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnName);
2096 if (targetDpns.isEmpty()) {
2097 LOG.warn("Could not find DPNs for VPN {} in InterVpnLink {}", vpnName, interVpnLinkName);
2101 java.util.Optional<String> optNextHop = FibUtil.getFirstNextHopAddress(vrfEntry);
2102 java.util.Optional<Uint32> optLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
2106 optNextHop.ifPresent(nextHop -> {
2107 String flowRef = getInterVpnFibFlowRef(interVpnLinkName, vrfEntry.getDestPrefix(), nextHop);
2108 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
2109 Flow flow = new FlowBuilder().withKey(flowKey).setId(new FlowId(flowRef))
2110 .setTableId(NwConstants.L3_FIB_TABLE).setFlowName(flowRef).build();
2112 LOG.trace("Removing flow in FIB table for interVpnLink {} key {}", interVpnLinkName, flowRef);
2113 for (Uint64 dpId : targetDpns) {
2114 LOG.debug("Removing flow: VrfEntry=[prefix={} nexthop={}] dpn {} for InterVpnLink {} in FIB",
2115 vrfEntry.getDestPrefix(), nextHop, dpId, interVpnLinkName);
2117 mdsalManager.removeFlow(dpId, flow);
2123 optLabel.ifPresent(label -> {
2124 LOG.trace("Removing flow in FIB table for interVpnLink {}", interVpnLinkName);
2126 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
2127 for (Uint64 dpId : targetDpns) {
2128 LOG.debug("Removing flow: VrfEntry=[prefix={} label={}] dpn {} for InterVpnLink {} in LFIB",
2129 vrfEntry.getDestPrefix(), label, dpId, interVpnLinkName);
2130 makeLFibTableEntry(dpId, label, /*instructions*/null, LFIB_INTERVPN_PRIORITY,
2131 NwConstants.DEL_FLOW, tx);
2133 }), LOG, "Error removing flows");
2137 private static boolean isPrefixAndNextHopPresentInLri(String prefix,
2138 List<String> nextHopAddressList, LabelRouteInfo lri) {
2139 return lri != null && Objects.equals(lri.getPrefix(), prefix)
2140 && nextHopAddressList.contains(lri.getNextHopIpList().get(0));
2143 private boolean shouldCreateFibEntryForVrfAndVpnIdOnDpn(Uint32 vpnId, VrfEntry vrfEntry, Uint64 dpnId) {
2144 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
2148 Prefixes prefix = fibUtil.getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
2149 if (prefix != null) {
2150 Uint64 prefixDpnId = prefix.getDpnId();
2151 if (dpnId.equals(prefixDpnId)) {
2152 LOG.trace("Should not create remote FIB entry for vrfEntry {} on DPN {}",
2160 private static ReentrantLock lockFor(final VpnInstanceOpDataEntry vpnInstance) {
2161 // FIXME: use vpnInstance.key() instead?
2162 return JvmGlobalLocks.getLockForString(vpnInstance.getVpnInstanceName());
2165 private static ReentrantLock lockFor(LabelRouteInfoKey label) {
2166 return JvmGlobalLocks.getLockFor(label);