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.mdsalutil.NWUtil.isIpv4Address;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.util.concurrent.CheckedFuture;
15 import com.google.common.util.concurrent.FutureCallback;
16 import com.google.common.util.concurrent.Futures;
17 import com.google.common.util.concurrent.ListenableFuture;
18 import com.google.common.util.concurrent.MoreExecutors;
19 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
20 import java.math.BigInteger;
21 import java.net.InetAddress;
22 import java.net.UnknownHostException;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.concurrent.Callable;
29 import java.util.concurrent.CopyOnWriteArrayList;
30 import java.util.concurrent.ExecutionException;
31 import javax.annotation.PostConstruct;
32 import javax.inject.Inject;
33 import javax.inject.Singleton;
34 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
35 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
36 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
37 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
38 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
39 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
40 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
41 import org.opendaylight.genius.mdsalutil.ActionInfo;
42 import org.opendaylight.genius.mdsalutil.FlowEntity;
43 import org.opendaylight.genius.mdsalutil.InstructionInfo;
44 import org.opendaylight.genius.mdsalutil.MDSALUtil;
45 import org.opendaylight.genius.mdsalutil.MatchInfo;
46 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
47 import org.opendaylight.genius.mdsalutil.NwConstants;
48 import org.opendaylight.genius.mdsalutil.actions.ActionDrop;
49 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
50 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
51 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
52 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
53 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
54 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
55 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
56 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
57 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
58 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
59 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
60 import org.opendaylight.genius.utils.ServiceIndex;
61 import org.opendaylight.genius.utils.batching.SubTransaction;
62 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
63 import org.opendaylight.netvirt.elanmanager.api.IElanService;
64 import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
65 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
66 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
67 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
68 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
69 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
70 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesBuilder;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState.State;
101 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
102 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
103 import org.slf4j.Logger;
104 import org.slf4j.LoggerFactory;
108 public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry, VrfEntryListener> {
110 private static final Logger LOG = LoggerFactory.getLogger(VrfEntryListener.class);
111 private static final String FLOWID_PREFIX = "L3.";
112 private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16);
113 private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
114 private static final int IPV4_ADDR_PREFIX_LENGTH = 32;
115 private static final int LFIB_INTERVPN_PRIORITY = 15;
116 public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
117 private static final int DJC_MAX_RETRIES = 3;
118 private static final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
120 private final DataBroker dataBroker;
121 private final ManagedNewTransactionRunner txRunner;
122 private final IMdsalApiManager mdsalManager;
123 private final NexthopManager nextHopManager;
124 private final BgpRouteVrfEntryHandler bgpRouteVrfEntryHandler;
125 private final BaseVrfEntryHandler baseVrfEntryHandler;
126 private final RouterInterfaceVrfEntryHandler routerInterfaceVrfEntryHandler;
127 private final JobCoordinator jobCoordinator;
128 private final IElanService elanManager;
129 private final FibUtil fibUtil;
130 private final InterVpnLinkCache interVpnLinkCache;
131 private final List<AutoCloseable> closeables = new CopyOnWriteArrayList<>();
134 public VrfEntryListener(final DataBroker dataBroker, final IMdsalApiManager mdsalApiManager,
135 final NexthopManager nexthopManager,
136 final IElanService elanManager,
137 final BaseVrfEntryHandler vrfEntryHandler,
138 final BgpRouteVrfEntryHandler bgpRouteVrfEntryHandler,
139 final RouterInterfaceVrfEntryHandler routerInterfaceVrfEntryHandler,
140 final JobCoordinator jobCoordinator,
141 final FibUtil fibUtil,
142 final InterVpnLinkCache interVpnLinkCache) {
143 super(VrfEntry.class, VrfEntryListener.class);
144 this.dataBroker = dataBroker;
145 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
146 this.mdsalManager = mdsalApiManager;
147 this.nextHopManager = nexthopManager;
148 this.elanManager = elanManager;
149 this.baseVrfEntryHandler = vrfEntryHandler;
150 this.bgpRouteVrfEntryHandler = bgpRouteVrfEntryHandler;
151 this.routerInterfaceVrfEntryHandler = routerInterfaceVrfEntryHandler;
152 this.jobCoordinator = jobCoordinator;
153 this.fibUtil = fibUtil;
154 this.interVpnLinkCache = interVpnLinkCache;
160 LOG.info("{} init", getClass().getSimpleName());
161 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
165 @SuppressWarnings("checkstyle:IllegalCatch")
166 public void close() {
167 closeables.forEach(c -> {
170 } catch (Exception e) {
171 LOG.warn("Error closing {}", c, e);
177 protected VrfEntryListener getDataTreeChangeListener() {
178 return VrfEntryListener.this;
182 protected InstanceIdentifier<VrfEntry> getWildCardPath() {
183 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
187 protected void add(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
188 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
189 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
190 LOG.debug("ADD: Adding Fib Entry rd {} prefix {} route-paths {}",
191 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
192 addFibEntries(identifier, vrfEntry, rd);
193 LOG.info("ADD: Added Fib Entry rd {} prefix {} route-paths {}",
194 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
197 //This method is temporary. Eventually Factory design pattern will be used to get
198 // right VrfEntryhandle and invoke its methods.
199 private void addFibEntries(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry, String rd) {
200 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
201 bgpRouteVrfEntryHandler.createFlows(identifier, vrfEntry, rd);
204 if (VrfEntry.EncapType.Vxlan.equals(vrfEntry.getEncapType())) {
205 LOG.info("EVPN flows need to be programmed.");
206 EvpnVrfEntryHandler evpnVrfEntryHandler = new EvpnVrfEntryHandler(dataBroker, this, bgpRouteVrfEntryHandler,
207 nextHopManager, jobCoordinator, elanManager, fibUtil);
208 evpnVrfEntryHandler.createFlows(identifier, vrfEntry, rd);
209 closeables.add(evpnVrfEntryHandler);
212 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
213 if (routerInt != null) {
214 // ping responder for router interfaces
215 routerInterfaceVrfEntryHandler.createFlows(identifier, vrfEntry, rd);
218 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
219 createFibEntries(identifier, vrfEntry);
225 protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
226 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
227 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
228 LOG.debug("REMOVE: Removing Fib Entry rd {} prefix {} route-paths {}",
229 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
230 removeFibEntries(identifier, vrfEntry, rd);
231 LOG.info("REMOVE: Removed Fib Entry rd {} prefix {} route-paths {}",
232 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
235 //This method is temporary. Eventually Factory design pattern will be used to get
236 // right VrfEntryhandle and invoke its methods.
237 private void removeFibEntries(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry, String rd) {
238 if (VrfEntry.EncapType.Vxlan.equals(vrfEntry.getEncapType())) {
239 LOG.info("EVPN flows to be deleted");
240 EvpnVrfEntryHandler evpnVrfEntryHandler = new EvpnVrfEntryHandler(dataBroker, this, bgpRouteVrfEntryHandler,
241 nextHopManager, jobCoordinator, elanManager, fibUtil);
242 evpnVrfEntryHandler.removeFlows(identifier, vrfEntry, rd);
243 closeables.add(evpnVrfEntryHandler);
246 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
247 if (routerInt != null) {
248 // ping responder for router interfaces
249 routerInterfaceVrfEntryHandler.removeFlows(identifier, vrfEntry, rd);
252 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
253 deleteFibEntries(identifier, vrfEntry);
256 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
257 bgpRouteVrfEntryHandler.removeFlows(identifier, vrfEntry, rd);
263 // "Redundant nullcheck of originalRoutePath, which is known to be non-null" - the null checking for
264 // originalRoutePath is a little dicey - safest to keep the checking even if not needed.
265 @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE")
266 protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
267 Preconditions.checkNotNull(update, "VrfEntry should not be null or empty.");
268 final String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
269 LOG.debug("UPDATE: Updating Fib Entries to rd {} prefix {} route-paths {} origin {} old-origin {}", rd,
270 update.getDestPrefix(), update.getRoutePaths(), update.getOrigin(), original.getOrigin());
271 // Handle BGP Routes first
272 if (RouteOrigin.value(update.getOrigin()) == RouteOrigin.BGP) {
273 bgpRouteVrfEntryHandler.updateFlows(identifier, original, update, rd);
274 LOG.info("UPDATE: Updated BGP advertised Fib Entry with rd {} prefix {} route-paths {}",
275 rd, update.getDestPrefix(), update.getRoutePaths());
279 if (RouteOrigin.value(update.getOrigin()) == RouteOrigin.STATIC) {
280 List<RoutePaths> originalRoutePath = original.getRoutePaths();
281 List<RoutePaths> updateRoutePath = update.getRoutePaths();
282 LOG.info("UPDATE: Original route-path {} update route-path {} ", originalRoutePath, updateRoutePath);
284 //Updates need to be handled for extraroute even if original vrf entry route path is null or
285 //updated vrf entry route path is null. This can happen during tunnel events.
286 Optional<VpnInstanceOpDataEntry> optVpnInstance = fibUtil.getVpnInstanceOpData(rd);
287 List<String> usedRds = new ArrayList<>();
288 if (optVpnInstance.isPresent()) {
289 usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker,optVpnInstance.get().getVpnId(),
290 update.getDestPrefix());
292 // If original VRF Entry had nexthop null , but update VRF Entry
293 // has nexthop , route needs to be created on remote Dpns
294 if (originalRoutePath == null || originalRoutePath.isEmpty()
295 && updateRoutePath != null && !updateRoutePath.isEmpty() && usedRds.isEmpty()) {
296 // TODO(vivek): Though ugly, Not handling this code now, as each
297 // tep add event will invoke flow addition
298 LOG.trace("Original VRF entry NH is null for destprefix {}. And the prefix is not an extra route."
299 + " This event is IGNORED here.", update.getDestPrefix());
303 // If original VRF Entry had valid nexthop , but update VRF Entry
304 // has nexthop empty'ed out, route needs to be removed from remote Dpns
305 if (updateRoutePath == null || updateRoutePath.isEmpty()
306 && originalRoutePath != null && !originalRoutePath.isEmpty() && usedRds.isEmpty()) {
307 LOG.trace("Original VRF entry had valid NH for destprefix {}. And the prefix is not an extra route."
308 + "This event is IGNORED here.", update.getDestPrefix());
311 //Update the used rds and vpntoextraroute containers only for the deleted nextHops.
312 List<String> nextHopsRemoved = FibHelper.getNextHopListFromRoutePaths(original);
313 nextHopsRemoved.removeAll(FibHelper.getNextHopListFromRoutePaths(update));
314 WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
315 nextHopsRemoved.parallelStream()
316 .forEach(nextHopRemoved -> fibUtil.updateUsedRdAndVpnToExtraRoute(
317 writeOperTxn, nextHopRemoved, rd, update.getDestPrefix()));
318 CheckedFuture<Void, TransactionCommitFailedException> operFuture = writeOperTxn.submit();
321 } catch (InterruptedException | ExecutionException e) {
322 LOG.error("Exception encountered while submitting operational future for update vrfentry {}: "
326 createFibEntries(identifier, update);
327 LOG.info("UPDATE: Updated static Fib Entry with rd {} prefix {} route-paths {}",
328 rd, update.getDestPrefix(), update.getRoutePaths());
332 //Handle all other routes only on a cluster reboot
333 if (original.equals(update)) {
335 createFibEntries(identifier, update);
336 LOG.info("UPDATE: Updated Non-static Fib Entry with rd {} prefix {} route-paths {}",
337 rd, update.getDestPrefix(), update.getRoutePaths());
341 LOG.info("UPDATE: Ignoring update for FIB entry with rd {} prefix {} route-origin {} route-paths {}",
342 rd, update.getDestPrefix(), update.getOrigin(), update.getRoutePaths());
345 private void createFibEntries(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
346 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
347 List<SubTransaction> txnObjects = new ArrayList<>();
348 final VpnInstanceOpDataEntry vpnInstance =
349 fibUtil.getVpnInstance(vrfTableKey.getRouteDistinguisher());
350 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
351 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId()
352 + " has null vpnId!");
353 final Collection<VpnToDpnList> vpnToDpnList;
354 if (vrfEntry.getParentVpnRd() != null
355 && FibHelper.isControllerManagedNonSelfImportedRoute(RouteOrigin.value(vrfEntry.getOrigin()))) {
356 // This block MUST BE HIT only for PNF (Physical Network Function) FIB Entries.
357 VpnInstanceOpDataEntry parentVpnInstance = fibUtil.getVpnInstance(vrfEntry.getParentVpnRd());
358 vpnToDpnList = parentVpnInstance != null ? parentVpnInstance.getVpnToDpnList() :
359 vpnInstance.getVpnToDpnList();
360 LOG.info("createFibEntries: Processing creation of PNF FIB entry with rd {} prefix {}",
361 vrfEntry.getParentVpnRd(), vrfEntry.getDestPrefix());
363 vpnToDpnList = vpnInstance.getVpnToDpnList();
365 final Long vpnId = vpnInstance.getVpnId();
366 final String rd = vrfTableKey.getRouteDistinguisher();
367 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
368 if (subnetRoute != null) {
369 final long elanTag = subnetRoute.getElantag();
370 LOG.trace("SUBNETROUTE: createFibEntries: SubnetRoute augmented vrfentry found for rd {} prefix {}"
371 + " with elantag {}", rd, vrfEntry.getDestPrefix(), elanTag);
372 if (vpnToDpnList != null) {
373 jobCoordinator.enqueueJob(FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix()), () -> {
374 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
375 for (final VpnToDpnList curDpn : vpnToDpnList) {
376 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
377 installSubnetRouteInFib(curDpn.getDpnId(), elanTag, rd, vpnId, vrfEntry, tx);
378 installSubnetBroadcastAddrDropRule(curDpn.getDpnId(), rd, vpnId.longValue(),
379 vrfEntry, NwConstants.ADD_FLOW, tx);
382 List<ListenableFuture<Void>> futures = new ArrayList<>();
383 futures.add(tx.submit());
390 final List<BigInteger> localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry);
391 if (!localDpnIdList.isEmpty() && vpnToDpnList != null) {
392 jobCoordinator.enqueueJob(FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix()), () -> {
393 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
394 synchronized (vpnInstance.getVpnInstanceName().intern()) {
395 for (VpnToDpnList vpnDpn : vpnToDpnList) {
396 if (!localDpnIdList.contains(vpnDpn.getDpnId())) {
397 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
399 if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
400 bgpRouteVrfEntryHandler.createRemoteFibEntry(vpnDpn.getDpnId(),
401 vpnId, vrfTableKey.getRouteDistinguisher(), vrfEntry, tx, txnObjects);
403 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(),
404 vrfTableKey.getRouteDistinguisher(), vrfEntry, tx);
406 } catch (NullPointerException e) {
407 LOG.error("Failed to get create remote fib flows for prefix {} ",
408 vrfEntry.getDestPrefix(), e);
414 List<ListenableFuture<Void>> futures = new ArrayList<>();
415 futures.add(tx.submit());
420 Optional<String> optVpnUuid = fibUtil.getVpnNameFromRd(rd);
421 if (optVpnUuid.isPresent()) {
422 String vpnUuid = optVpnUuid.get();
423 InterVpnLinkDataComposite interVpnLink = interVpnLinkCache.getInterVpnLinkByVpnId(vpnUuid).orNull();
424 if (interVpnLink != null) {
425 LOG.debug("InterVpnLink {} found in Cache linking Vpn {}", interVpnLink.getInterVpnLinkName(), vpnUuid);
426 FibUtil.getFirstNextHopAddress(vrfEntry).ifPresent(routeNexthop -> {
427 if (interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid)) {
428 // This is an static route that points to the other endpoint of an InterVpnLink
429 // In that case, we should add another entry in FIB table pointing to LPortDispatcher table.
430 installIVpnLinkSwitchingFlows(interVpnLink, vpnUuid, vrfEntry, vpnId);
431 installInterVpnRouteInLFib(interVpnLink, vpnUuid, vrfEntry);
438 void refreshFibTables(String rd, String prefix) {
439 InstanceIdentifier<VrfEntry> vrfEntryId =
440 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd))
441 .child(VrfEntry.class, new VrfEntryKey(prefix)).build();
442 Optional<VrfEntry> vrfEntry = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
443 if (vrfEntry.isPresent()) {
444 createFibEntries(vrfEntryId, vrfEntry.get());
448 private Prefixes updateVpnReferencesInLri(LabelRouteInfo lri, String vpnInstanceName, boolean isPresentInList) {
449 LOG.debug("updating LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
450 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
451 prefixBuilder.setDpnId(lri.getDpnId());
452 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
453 prefixBuilder.setIpAddress(lri.getPrefix());
454 // Increment the refCount here
455 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
456 .child(LabelRouteInfo.class, new LabelRouteInfoKey(lri.getLabel())).build();
457 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri);
458 if (!isPresentInList) {
459 LOG.debug("vpnName {} is not present in LRI with label {}..", vpnInstanceName, lri.getLabel());
460 List<String> vpnInstanceNames = lri.getVpnInstanceList();
461 vpnInstanceNames.add(vpnInstanceName);
462 builder.setVpnInstanceList(vpnInstanceNames);
463 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build());
465 LOG.debug("vpnName {} is present in LRI with label {}..", vpnInstanceName, lri.getLabel());
467 return prefixBuilder.build();
470 void installSubnetRouteInFib(final BigInteger dpnId, final long elanTag, final String rd,
471 final long vpnId, final VrfEntry vrfEntry, WriteTransaction tx) {
472 Boolean wrTxPresent = true;
475 tx = dataBroker.newWriteOnlyTransaction();
477 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
478 List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
479 synchronized (label.toString().intern()) {
480 LabelRouteInfo lri = getLabelRouteInfo(label);
481 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
483 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
484 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
485 fibUtil.getVpnInstanceOpData(rd);
486 if (vpnInstanceOpDataEntryOptional.isPresent()) {
487 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
488 if (!lri.getVpnInstanceList().contains(vpnInstanceName)) {
489 updateVpnReferencesInLri(lri, vpnInstanceName, false);
493 LOG.debug("SUBNETROUTE: installSubnetRouteInFib: Fetched labelRouteInfo for label {} interface {}"
494 + " and got dpn {}", label, lri.getVpnInterfaceName(), lri.getDpnId());
498 final List<InstructionInfo> instructions = new ArrayList<>();
499 BigInteger subnetRouteMeta = BigInteger.valueOf(elanTag).shiftLeft(24)
500 .or(BigInteger.valueOf(vpnId).shiftLeft(1));
501 instructions.add(new InstructionWriteMetadata(subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE));
502 instructions.add(new InstructionGotoTable(NwConstants.L3_SUBNET_ROUTE_TABLE));
503 baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions,
504 NwConstants.ADD_FLOW, tx, null);
506 if (vrfEntry.getRoutePaths() != null) {
507 for (RoutePaths routePath : vrfEntry.getRoutePaths()) {
508 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
509 List<ActionInfo> actionsInfos = new ArrayList<>();
510 // reinitialize instructions list for LFIB Table
511 final List<InstructionInfo> LFIBinstructions = new ArrayList<>();
513 actionsInfos.add(new ActionPopMpls());
514 LFIBinstructions.add(new InstructionApplyActions(actionsInfos));
515 LFIBinstructions.add(new InstructionWriteMetadata(subnetRouteMeta,
516 MetaDataUtil.METADATA_MASK_SUBNET_ROUTE));
517 LFIBinstructions.add(new InstructionGotoTable(NwConstants.L3_SUBNET_ROUTE_TABLE));
519 makeLFibTableEntry(dpnId, routePath.getLabel(), LFIBinstructions, DEFAULT_FIB_FLOW_PRIORITY,
520 NwConstants.ADD_FLOW, tx);
529 private void installSubnetBroadcastAddrDropRule(final BigInteger dpnId, final String rd, final long vpnId,
530 final VrfEntry vrfEntry, int addOrRemove, WriteTransaction tx) {
531 List<MatchInfo> matches = new ArrayList<>();
533 LOG.debug("SUBNETROUTE: installSubnetBroadcastAddrDropRule: destPrefix {} rd {} vpnId {} dpnId {}",
534 vrfEntry.getDestPrefix(), rd, vpnId, dpnId);
535 String[] ipAddress = vrfEntry.getDestPrefix().split("/");
536 String subnetBroadcastAddr = FibUtil.getBroadcastAddressFromCidr(vrfEntry.getDestPrefix());
537 final int prefixLength = ipAddress.length == 1 ? 0 : Integer.parseInt(ipAddress[1]);
539 InetAddress destPrefix;
541 destPrefix = InetAddress.getByName(subnetBroadcastAddr);
542 } catch (UnknownHostException e) {
543 LOG.error("Failed to get destPrefix for prefix {} rd {} VpnId {} DPN {}",
544 vrfEntry.getDestPrefix(), rd, vpnId, dpnId, e);
548 // Match on VpnId and SubnetBroadCast IP address
549 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
550 matches.add(MatchEthernetType.IPV4);
552 if (prefixLength != 0) {
553 matches.add(new MatchIpv4Destination(subnetBroadcastAddr, Integer.toString(IPV4_ADDR_PREFIX_LENGTH)));
556 //Action is to drop the packet
557 List<InstructionInfo> dropInstructions = new ArrayList<>();
558 List<ActionInfo> actionsInfos = new ArrayList<>();
559 actionsInfos.add(new ActionDrop());
560 dropInstructions.add(new InstructionApplyActions(actionsInfos));
562 int priority = DEFAULT_FIB_FLOW_PRIORITY + IPV4_ADDR_PREFIX_LENGTH;
563 String flowRef = FibUtil.getFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, rd, priority, destPrefix);
564 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef, priority,
565 flowRef, 0, 0, COOKIE_TABLE_MISS, matches, dropInstructions);
567 Flow flow = flowEntity.getFlowBuilder().build();
568 String flowId = flowEntity.getFlowId();
569 FlowKey flowKey = new FlowKey(new FlowId(flowId));
570 Node nodeDpn = FibUtil.buildDpnNode(dpnId);
572 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
573 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
574 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
576 if (addOrRemove == NwConstants.ADD_FLOW) {
577 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true);
579 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
584 * For a given route, it installs a flow in LFIB that sets the lportTag of the other endpoint and sends to
585 * LportDispatcher table (via table 80)
587 private void installInterVpnRouteInLFib(final InterVpnLinkDataComposite interVpnLink, final String vpnName,
588 final VrfEntry vrfEntry) {
589 // INTERVPN routes are routes in a Vpn1 that have been leaked to Vpn2. In DC-GW, this Vpn2 route is pointing
590 // to a list of DPNs where Vpn2's VpnLink was instantiated. In these DPNs LFIB must be programmed so that the
591 // packet is commuted from Vpn2 to Vpn1.
592 String interVpnLinkName = interVpnLink.getInterVpnLinkName();
593 if (!interVpnLink.isActive()) {
594 LOG.warn("InterVpnLink {} is NOT ACTIVE. InterVpnLink flows for prefix={} wont be installed in LFIB",
595 interVpnLinkName, vrfEntry.getDestPrefix());
599 List<BigInteger> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnName);
600 Optional<Long> optLportTag = interVpnLink.getEndpointLportTagByVpnName(vpnName);
601 if (!optLportTag.isPresent()) {
602 LOG.warn("Could not retrieve lportTag for VPN {} endpoint in InterVpnLink {}", vpnName, interVpnLinkName);
606 Long lportTag = optLportTag.get();
607 Long label = FibUtil.getLabelFromRoutePaths(vrfEntry).orElse(null);
609 LOG.error("Could not find label in vrfEntry=[prefix={} routePaths={}]. LFIB entry for InterVpnLink skipped",
610 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
613 List<ActionInfo> actionsInfos = Collections.singletonList(new ActionPopMpls());
614 List<InstructionInfo> instructions = Arrays.asList(
615 new InstructionApplyActions(actionsInfos),
616 new InstructionWriteMetadata(MetaDataUtil.getMetaDataForLPortDispatcher(lportTag.intValue(),
617 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
618 NwConstants.L3VPN_SERVICE_INDEX)),
619 MetaDataUtil.getMetaDataMaskForLPortDispatcher()),
620 new InstructionGotoTable(NwConstants.L3_INTERFACE_TABLE));
621 List<String> interVpnNextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
623 for (BigInteger dpId : targetDpns) {
624 LOG.debug("Installing flow: VrfEntry=[prefix={} label={} nexthop={}] dpn {} for InterVpnLink {} in LFIB",
625 vrfEntry.getDestPrefix(), label, interVpnNextHopList, dpId, interVpnLink.getInterVpnLinkName());
627 makeLFibTableEntry(dpId, label, instructions, LFIB_INTERVPN_PRIORITY, NwConstants.ADD_FLOW,
634 * Installs the flows in FIB table that, for a given route, do the switching from one VPN to the other.
636 private void installIVpnLinkSwitchingFlows(final InterVpnLinkDataComposite interVpnLink, final String vpnUuid,
637 final VrfEntry vrfEntry, long vpnTag) {
638 Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
639 Preconditions.checkArgument(vrfEntry.getRoutePaths() != null
640 && vrfEntry.getRoutePaths().size() == 1);
641 String destination = vrfEntry.getDestPrefix();
642 String nextHop = vrfEntry.getRoutePaths().get(0).getNexthopAddress();
643 String interVpnLinkName = interVpnLink.getInterVpnLinkName();
645 // After having received a static route, we should check if the vpn is part of an inter-vpn-link.
646 // In that case, we should populate the FIB table of the VPN pointing to LPortDisptacher table
647 // using as metadata the LPortTag associated to that vpn in the inter-vpn-link.
648 if (interVpnLink.getState().or(State.Error) != State.Active) {
649 LOG.warn("Route to {} with nexthop={} cannot be installed because the interVpnLink {} is not active",
650 destination, nextHop, interVpnLinkName);
654 Optional<Long> optOtherEndpointLportTag = interVpnLink.getOtherEndpointLportTagByVpnName(vpnUuid);
655 if (!optOtherEndpointLportTag.isPresent()) {
656 LOG.warn("Could not find suitable LportTag for the endpoint opposite to vpn {} in interVpnLink {}",
657 vpnUuid, interVpnLinkName);
661 List<BigInteger> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnUuid);
662 if (targetDpns.isEmpty()) {
663 LOG.warn("Could not find DPNs for endpoint opposite to vpn {} in interVpnLink {}",
664 vpnUuid, interVpnLinkName);
668 String[] values = destination.split("/");
669 String destPrefixIpAddress = values[0];
670 int prefixLength = values.length == 1 ? 0 : Integer.parseInt(values[1]);
672 List<MatchInfo> matches = new ArrayList<>();
673 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnTag), MetaDataUtil.METADATA_MASK_VRFID));
674 matches.add(MatchEthernetType.IPV4);
676 if (prefixLength != 0) {
677 matches.add(new MatchIpv4Destination(destPrefixIpAddress, Integer.toString(prefixLength)));
680 List<Instruction> instructions =
681 Arrays.asList(new InstructionWriteMetadata(
682 MetaDataUtil.getMetaDataForLPortDispatcher(optOtherEndpointLportTag.get().intValue(),
683 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants
684 .L3VPN_SERVICE_INDEX)),
685 MetaDataUtil.getMetaDataMaskForLPortDispatcher()).buildInstruction(0),
686 new InstructionGotoTable(NwConstants.L3_INTERFACE_TABLE).buildInstruction(1));
688 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
689 String flowRef = getInterVpnFibFlowRef(interVpnLinkName, destination, nextHop);
690 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
691 COOKIE_VM_FIB_TABLE, matches, instructions);
693 LOG.trace("Installing flow in FIB table for vpn {} interVpnLink {} nextHop {} key {}",
694 vpnUuid, interVpnLink.getInterVpnLinkName(), nextHop, flowRef);
696 for (BigInteger dpId : targetDpns) {
698 LOG.debug("Installing flow: VrfEntry=[prefix={} route-paths={}] dpn {} for InterVpnLink {} in FIB",
699 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(),
700 dpId, interVpnLink.getInterVpnLinkName());
702 mdsalManager.installFlow(dpId, flowEntity);
706 private List<BigInteger> createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
707 List<BigInteger> returnLocalDpnId = new ArrayList<>();
708 String localNextHopIP = vrfEntry.getDestPrefix();
709 Prefixes localNextHopInfo = fibUtil.getPrefixToInterface(vpnId, localNextHopIP);
710 String vpnName = fibUtil.getVpnNameFromId(vpnId);
711 if (localNextHopInfo == null) {
712 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, localNextHopIP);
713 List<Routes> vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker,
714 vpnName, usedRds, localNextHopIP);
715 boolean localNextHopSeen = false;
716 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
717 for (Routes vpnExtraRoute : vpnExtraRoutes) {
719 if (isIpv4Address(vpnExtraRoute.getNexthopIpList().get(0))) {
720 ipPrefix = vpnExtraRoute.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX;
722 ipPrefix = vpnExtraRoute.getNexthopIpList().get(0) + NwConstants.IPV6PREFIX;
724 Prefixes localNextHopInfoLocal = fibUtil.getPrefixToInterface(vpnId,
726 if (localNextHopInfoLocal != null) {
727 localNextHopSeen = true;
729 checkCreateLocalFibEntry(localNextHopInfoLocal, localNextHopInfoLocal.getIpAddress(),
730 vpnId, rd, vrfEntry, vpnId, vpnExtraRoute, vpnExtraRoutes);
731 returnLocalDpnId.add(dpnId);
734 if (!localNextHopSeen && RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
735 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
736 if (optionalLabel.isPresent()) {
737 Long label = optionalLabel.get();
738 List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
739 synchronized (label.toString().intern()) {
740 LabelRouteInfo lri = getLabelRouteInfo(label);
741 if (isPrefixAndNextHopPresentInLri(localNextHopIP, nextHopAddressList, lri)) {
742 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
743 fibUtil.getVpnInstanceOpData(rd);
744 if (vpnInstanceOpDataEntryOptional.isPresent()) {
745 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
746 if (lri.getVpnInstanceList().contains(vpnInstanceName)) {
747 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, true);
748 localNextHopIP = lri.getPrefix();
750 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, false);
751 localNextHopIP = lri.getPrefix();
754 if (localNextHopInfo != null) {
755 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
756 label, localNextHopInfo.getVpnInterfaceName(), lri.getDpnId());
757 if (vpnExtraRoutes.isEmpty()) {
758 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP,
759 vpnId, rd, vrfEntry, lri.getParentVpnid(), null, vpnExtraRoutes);
760 returnLocalDpnId.add(dpnId);
762 for (Routes extraRoutes : vpnExtraRoutes) {
763 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo,
765 vpnId, rd, vrfEntry, lri.getParentVpnid(),
766 extraRoutes, vpnExtraRoutes);
767 returnLocalDpnId.add(dpnId);
775 if (returnLocalDpnId.isEmpty()) {
776 LOG.error("Local DPNID is empty for rd {}, vpnId {}, vrfEntry {}", rd, vpnId, vrfEntry);
779 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId,
780 rd, vrfEntry, vpnId, /*routes*/ null, /*vpnExtraRoutes*/ null);
782 returnLocalDpnId.add(dpnId);
785 return returnLocalDpnId;
788 private BigInteger checkCreateLocalFibEntry(Prefixes localNextHopInfo, String localNextHopIP,
789 final Long vpnId, final String rd,
790 final VrfEntry vrfEntry, Long parentVpnId,
791 Routes routes, List<Routes> vpnExtraRoutes) {
792 String vpnName = fibUtil.getVpnNameFromId(vpnId);
793 if (localNextHopInfo != null) {
796 final BigInteger dpnId = localNextHopInfo.getDpnId();
797 if (Prefixes.PrefixCue.Nat.equals(localNextHopInfo.getPrefixCue())) {
798 LOG.debug("checkCreateLocalFibEntry: NAT Prefix {} with vpnId {} rd {}. Skip local dpn {}"
799 + " FIB processing", vrfEntry.getDestPrefix(), vpnId, rd, dpnId);
802 if (Prefixes.PrefixCue.PhysNetFunc.equals(localNextHopInfo.getPrefixCue())) {
803 LOG.debug("checkCreateLocalFibEntry: PNF Prefix {} with vpnId {} rd {}. Skip local dpn {}"
804 + " FIB processing", vrfEntry.getDestPrefix(), vpnId, rd, dpnId);
807 String jobKey = FibUtil.getCreateLocalNextHopJobKey(vpnId, dpnId, vrfEntry.getDestPrefix());
808 String interfaceName = localNextHopInfo.getVpnInterfaceName();
809 String prefix = vrfEntry.getDestPrefix();
810 String gwMacAddress = vrfEntry.getGatewayMacAddress();
811 //The loadbalancing group is created only if the extra route has multiple nexthops
812 //to avoid loadbalancing the discovered routes
813 if (vpnExtraRoutes != null) {
814 if (isIpv4Address(routes.getNexthopIpList().get(0))) {
815 localNextHopIP = routes.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX;
817 localNextHopIP = routes.getNexthopIpList().get(0) + NwConstants.IPV6PREFIX;
819 if (vpnExtraRoutes.size() > 1) {
820 groupId = nextHopManager.createNextHopGroups(parentVpnId, rd, dpnId, vrfEntry, routes,
822 localGroupId = nextHopManager.getLocalNextHopGroup(parentVpnId, localNextHopIP);
823 } else if (routes.getNexthopIpList().size() > 1) {
824 groupId = nextHopManager.createNextHopGroups(parentVpnId, rd, dpnId, vrfEntry, routes,
826 localGroupId = groupId;
828 groupId = nextHopManager.getLocalNextHopGroup(parentVpnId, localNextHopIP);
829 localGroupId = groupId;
832 groupId = nextHopManager.createLocalNextHop(parentVpnId, dpnId, interfaceName, localNextHopIP, prefix,
833 gwMacAddress, jobKey);
834 localGroupId = groupId;
836 if (groupId == FibConstants.INVALID_GROUP_ID) {
837 LOG.error("Unable to create Group for local prefix {} on rd {} for vpninterface {} on Node {}",
838 prefix, rd, interfaceName, dpnId.toString());
839 return BigInteger.ZERO;
841 final List<InstructionInfo> instructions = Collections.singletonList(
842 new InstructionApplyActions(
843 Collections.singletonList(new ActionGroup(groupId))));
844 final List<InstructionInfo> lfibinstructions = Collections.singletonList(
845 new InstructionApplyActions(
846 Arrays.asList(new ActionPopMpls(), new ActionGroup(groupId))));
847 java.util.Optional<Long> optLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
848 List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
849 jobCoordinator.enqueueJob(jobKey, () -> {
850 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
851 baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions,
852 NwConstants.ADD_FLOW, tx, null);
853 if (!fibUtil.enforceVxlanDatapathSemanticsforInternalRouterVpn(localNextHopInfo.getSubnetId(),
855 optLabel.ifPresent(label -> {
856 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
857 LOG.debug("Installing LFIB and tunnel table entry on dpn {} for interface {} with label "
858 + "{}, rd {}, prefix {}, nexthop {}", dpnId,
859 localNextHopInfo.getVpnInterfaceName(), optLabel, rd, vrfEntry.getDestPrefix(),
861 makeLFibTableEntry(dpnId, label, lfibinstructions, DEFAULT_FIB_FLOW_PRIORITY,
862 NwConstants.ADD_FLOW, tx);
863 // If the extra-route is reachable from VMs attached to the same switch,
864 // then the tunnel table can point to the load balancing group.
865 // If it is reachable from VMs attached to different switches,
866 // then it should be pointing to one of the local group in order to avoid looping.
867 if (vrfEntry.getRoutePaths().size() == 1) {
868 makeTunnelTableEntry(dpnId, label, groupId, tx);
870 makeTunnelTableEntry(dpnId, label, localGroupId, tx);
873 LOG.debug("Route with rd {} prefix {} label {} nexthop {} for vpn {} is an imported "
874 + "route. LFib and Terminating table entries will not be created.",
875 rd, vrfEntry.getDestPrefix(), optLabel, nextHopAddressList, vpnId);
879 List<ListenableFuture<Void>> futures = new ArrayList<>();
880 futures.add(tx.submit());
885 LOG.error("localNextHopInfo received is null for prefix {} on rd {} on vpn {}", vrfEntry.getDestPrefix(), rd,
887 return BigInteger.ZERO;
890 private LabelRouteInfo getLabelRouteInfo(Long label) {
891 InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
892 .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build();
893 Optional<LabelRouteInfo> opResult = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid);
894 if (opResult.isPresent()) {
895 return opResult.get();
900 private boolean deleteLabelRouteInfo(LabelRouteInfo lri, String vpnInstanceName, WriteTransaction tx) {
905 LOG.debug("deleting LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
906 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
907 .child(LabelRouteInfo.class, new LabelRouteInfoKey(lri.getLabel())).build();
909 List<String> vpnInstancesList = lri.getVpnInstanceList() != null
910 ? lri.getVpnInstanceList() : new ArrayList<>();
911 if (vpnInstancesList.contains(vpnInstanceName)) {
912 LOG.debug("vpninstance {} name is present", vpnInstanceName);
913 vpnInstancesList.remove(vpnInstanceName);
915 if (vpnInstancesList.isEmpty()) {
916 LOG.debug("deleting LRI instance object for label {}", lri.getLabel());
918 tx.delete(LogicalDatastoreType.OPERATIONAL, lriId);
920 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId);
924 LOG.debug("updating LRI instance object for label {}", lri.getLabel());
925 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri).setVpnInstanceList(vpnInstancesList);
926 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build());
931 void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/,
932 WriteTransaction tx) {
933 List<ActionInfo> actionsInfos = Collections.singletonList(new ActionGroup(groupId));
935 createTerminatingServiceActions(dpId, (int) label, actionsInfos, tx);
937 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully",
938 dpId, label, groupId);
941 public void createTerminatingServiceActions(BigInteger destDpId, int label, List<ActionInfo> actionsInfos,
942 WriteTransaction tx) {
943 List<MatchInfo> mkMatches = new ArrayList<>();
945 LOG.debug("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}",
946 destDpId, label, actionsInfos);
949 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
950 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(label)));
952 List<InstructionInfo> mkInstructions = new ArrayList<>();
953 mkInstructions.add(new InstructionApplyActions(actionsInfos));
955 FlowEntity terminatingServiceTableFlowEntity =
956 MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
957 getTableMissFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE, label), 5,
958 String.format("%s:%d", "TST Flow Entry ", label),
959 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, mkInstructions);
961 FlowKey flowKey = new FlowKey(new FlowId(terminatingServiceTableFlowEntity.getFlowId()));
963 FlowBuilder flowbld = terminatingServiceTableFlowEntity.getFlowBuilder();
965 Node nodeDpn = FibUtil.buildDpnNode(terminatingServiceTableFlowEntity.getDpnId());
966 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
967 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
968 .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId()))
969 .child(Flow.class, flowKey).build();
970 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flowbld.build(),
971 WriteTransaction.CREATE_MISSING_PARENTS);
974 private void removeTunnelTableEntry(BigInteger dpId, long label, WriteTransaction tx) {
975 FlowEntity flowEntity;
976 LOG.debug("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId, label);
977 List<MatchInfo> mkMatches = new ArrayList<>();
979 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(label)));
980 flowEntity = MDSALUtil.buildFlowEntity(dpId,
981 NwConstants.INTERNAL_TUNNEL_TABLE,
982 getTableMissFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int) label),
983 5, String.format("%s:%d", "TST Flow Entry ", label), 0, 0,
984 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
985 Node nodeDpn = FibUtil.buildDpnNode(flowEntity.getDpnId());
986 FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getFlowId()));
987 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
988 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
989 .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build();
991 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
992 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully", dpId, label);
995 public List<BigInteger> deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
996 List<BigInteger> returnLocalDpnId = new ArrayList<>();
997 Prefixes localNextHopInfo = fibUtil.getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
998 String vpnName = fibUtil.getVpnNameFromId(vpnId);
999 boolean isExtraroute = false;
1000 if (localNextHopInfo == null) {
1001 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
1002 if (usedRds.size() > 1) {
1003 LOG.error("The extra route prefix {} is still present in some DPNs in vpn {} on rd {}",
1004 vrfEntry.getDestPrefix(), vpnName, rd);
1005 return returnLocalDpnId;
1007 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency
1009 Optional<Routes> extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker,
1010 vpnName, rd, vrfEntry.getDestPrefix());
1011 if (extraRouteOptional.isPresent()) {
1012 isExtraroute = true;
1013 Routes extraRoute = extraRouteOptional.get();
1015 if (isIpv4Address(extraRoute.getNexthopIpList().get(0))) {
1016 ipPrefix = extraRoute.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX;
1018 ipPrefix = extraRoute.getNexthopIpList().get(0) + NwConstants.IPV6PREFIX;
1020 localNextHopInfo = fibUtil.getPrefixToInterface(vpnId, ipPrefix);
1021 if (localNextHopInfo != null) {
1022 String localNextHopIP = localNextHopInfo.getIpAddress();
1023 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
1024 vpnId, rd, vrfEntry, isExtraroute, vpnId /*parentVpnId*/);
1025 if (!dpnId.equals(BigInteger.ZERO)) {
1026 LOG.trace("Deleting ECMP group for prefix {}, dpn {}", vrfEntry.getDestPrefix(), dpnId);
1027 nextHopManager.setupLoadBalancingNextHop(vpnId, dpnId,
1028 vrfEntry.getDestPrefix(), /*listBucketInfo*/ Collections.emptyList(),
1030 returnLocalDpnId.add(dpnId);
1033 LOG.error("localNextHopInfo unavailable while deleting prefix {} with rds {}, primary rd {} in "
1034 + "vpn {}", vrfEntry.getDestPrefix(), usedRds, rd, vpnName);
1038 if (localNextHopInfo == null) {
1039 /* Imported VRF entry */
1040 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1041 if (optionalLabel.isPresent()) {
1042 Long label = optionalLabel.get();
1043 List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
1044 LabelRouteInfo lri = getLabelRouteInfo(label);
1045 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
1046 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
1047 prefixBuilder.setDpnId(lri.getDpnId());
1048 BigInteger dpnId = checkDeleteLocalFibEntry(prefixBuilder.build(), nextHopAddressList.get(0),
1049 vpnId, rd, vrfEntry, isExtraroute, lri.getParentVpnid());
1050 if (!dpnId.equals(BigInteger.ZERO)) {
1051 returnLocalDpnId.add(dpnId);
1058 LOG.debug("Obtained prefix to interface for rd {} prefix {}", rd, vrfEntry.getDestPrefix());
1059 String localNextHopIP = localNextHopInfo.getIpAddress();
1060 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
1061 vpnId, rd, vrfEntry, isExtraroute, vpnId /*parentVpnId*/);
1062 if (!dpnId.equals(BigInteger.ZERO)) {
1063 returnLocalDpnId.add(dpnId);
1067 return returnLocalDpnId;
1070 private BigInteger checkDeleteLocalFibEntry(Prefixes localNextHopInfo, final String localNextHopIP,
1071 final Long vpnId, final String rd, final VrfEntry vrfEntry,
1072 boolean isExtraroute, final Long parentVpnId) {
1073 if (localNextHopInfo != null) {
1074 final BigInteger dpnId = localNextHopInfo.getDpnId();
1075 if (Prefixes.PrefixCue.Nat.equals(localNextHopInfo.getPrefixCue())) {
1076 LOG.debug("checkDeleteLocalFibEntry: NAT Prefix {} with vpnId {} rd {}. Skip local dpn {}"
1077 + " FIB processing", vrfEntry.getDestPrefix(), vpnId, rd, dpnId);
1080 if (Prefixes.PrefixCue.PhysNetFunc.equals(localNextHopInfo.getPrefixCue())) {
1081 LOG.debug("checkDeleteLocalFibEntry: PNF Prefix {} with vpnId {} rd {}. Skip local dpn {}"
1082 + " FIB processing", vrfEntry.getDestPrefix(), vpnId, rd, dpnId);
1086 jobCoordinator.enqueueJob(FibUtil.getCreateLocalNextHopJobKey(vpnId, dpnId,
1087 vrfEntry.getDestPrefix()), () -> {
1088 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1089 baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null,
1090 NwConstants.DEL_FLOW, tx, null);
1091 if (!fibUtil.enforceVxlanDatapathSemanticsforInternalRouterVpn(localNextHopInfo.getSubnetId(),
1093 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1094 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
1095 makeLFibTableEntry(dpnId, label, null /* instructions */, DEFAULT_FIB_FLOW_PRIORITY,
1096 NwConstants.DEL_FLOW, tx);
1097 removeTunnelTableEntry(dpnId, label, tx);
1101 List<ListenableFuture<Void>> futures = new ArrayList<>();
1102 futures.add(tx.submit());
1105 //TODO: verify below adjacency call need to be optimized (?)
1106 //In case of the removal of the extra route, the loadbalancing group is updated
1107 if (!isExtraroute) {
1108 baseVrfEntryHandler.deleteLocalAdjacency(dpnId, parentVpnId, localNextHopIP, vrfEntry.getDestPrefix());
1112 return BigInteger.ZERO;
1115 private void createRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, String rd,
1116 final VrfEntry vrfEntry, WriteTransaction tx) {
1117 Boolean wrTxPresent = true;
1119 wrTxPresent = false;
1120 tx = dataBroker.newWriteOnlyTransaction();
1123 String vpnName = fibUtil.getVpnNameFromId(vpnId);
1124 LOG.debug("createremotefibentry: adding route {} for rd {} on remoteDpnId {}",
1125 vrfEntry.getDestPrefix(), rd, remoteDpnId);
1127 List<AdjacencyResult> adjacencyResults = baseVrfEntryHandler.resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
1128 if (adjacencyResults.isEmpty()) {
1129 LOG.error("Could not get interface for route-paths: {} in vpn {} on DPN {}",
1130 vrfEntry.getRoutePaths(), rd, remoteDpnId);
1131 LOG.error("Failed to add Route: {} in vpn: {}", vrfEntry.getDestPrefix(), rd);
1135 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
1136 List<Routes> vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker,
1137 vpnName, usedRds, vrfEntry.getDestPrefix());
1138 // create loadbalancing groups for extra routes only when the extra route is present behind
1140 if (!vpnExtraRoutes.isEmpty() && (vpnExtraRoutes.size() > 1
1141 || vpnExtraRoutes.get(0).getNexthopIpList().size() > 1)) {
1142 List<InstructionInfo> instructions = new ArrayList<>();
1143 // Obtain the local routes for this particular dpn.
1144 java.util.Optional<Routes> routes = vpnExtraRoutes
1147 Prefixes prefixToInterface = fibUtil.getPrefixToInterface(vpnId,
1148 fibUtil.getIpPrefix(route.getNexthopIpList().get(0)));
1149 if (prefixToInterface == null) {
1152 return remoteDpnId.equals(prefixToInterface.getDpnId());
1154 long groupId = nextHopManager.createNextHopGroups(vpnId, rd, remoteDpnId, vrfEntry,
1155 routes.isPresent() ? routes.get() : null, vpnExtraRoutes);
1156 if (groupId == FibConstants.INVALID_GROUP_ID) {
1157 LOG.error("Unable to create Group for local prefix {} on rd {} on Node {}",
1158 vrfEntry.getDestPrefix(), rd, remoteDpnId.toString());
1161 List<ActionInfo> actionInfos =
1162 Collections.singletonList(new ActionGroup(groupId));
1163 instructions.add(new InstructionApplyActions(actionInfos));
1164 baseVrfEntryHandler.makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions,
1165 NwConstants.ADD_FLOW, tx, null);
1167 baseVrfEntryHandler.programRemoteFib(remoteDpnId, vpnId, vrfEntry, tx, rd, adjacencyResults, null);
1173 LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
1176 protected void cleanUpOpDataForFib(Long vpnId, String primaryRd, final VrfEntry vrfEntry) {
1177 /* Get interface info from prefix to interface mapping;
1178 Use the interface info to get the corresponding vpn interface op DS entry,
1179 remove the adjacency corresponding to this fib entry.
1180 If adjacency removed is the last adjacency, clean up the following:
1181 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
1182 - prefix to interface entry
1183 - vpn interface op DS
1185 LOG.debug("Cleanup of prefix {} in VPN {}", vrfEntry.getDestPrefix(), vpnId);
1186 Prefixes prefixInfo = fibUtil.getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
1187 if (prefixInfo == null) {
1188 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
1189 String usedRd = usedRds.isEmpty() ? primaryRd : usedRds.get(0);
1190 Routes extraRoute = baseVrfEntryHandler.getVpnToExtraroute(vpnId, usedRd, vrfEntry.getDestPrefix());
1191 if (extraRoute != null) {
1192 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1193 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
1194 if (nextHopIp != null) {
1196 if (isIpv4Address(nextHopIp)) {
1197 ipPrefix = nextHopIp + NwConstants.IPV4PREFIX;
1199 ipPrefix = nextHopIp + NwConstants.IPV6PREFIX;
1201 prefixInfo = fibUtil.getPrefixToInterface(vpnId, ipPrefix);
1202 checkCleanUpOpDataForFib(prefixInfo, vpnId, primaryRd, vrfEntry, extraRoute);
1206 if (prefixInfo == null) {
1207 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1208 if (optionalLabel.isPresent()) {
1209 Long label = optionalLabel.get();
1210 List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
1211 LabelRouteInfo lri = getLabelRouteInfo(label);
1212 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
1213 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
1214 prefixBuilder.setDpnId(lri.getDpnId());
1215 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
1216 prefixBuilder.setIpAddress(lri.getPrefix());
1217 prefixInfo = prefixBuilder.build();
1218 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
1219 label, prefixInfo.getVpnInterfaceName(), lri.getDpnId());
1220 checkCleanUpOpDataForFib(prefixInfo, vpnId, primaryRd, vrfEntry, extraRoute);
1225 checkCleanUpOpDataForFib(prefixInfo, vpnId, primaryRd, vrfEntry, null /*Routes*/);
1229 private void checkCleanUpOpDataForFib(final Prefixes prefixInfo, final Long vpnId, final String rd,
1230 final VrfEntry vrfEntry, final Routes extraRoute) {
1232 if (prefixInfo == null) {
1233 LOG.error("Cleanup VPN Data Failed as unable to find prefix Info for prefix {} VpnId {} rd {}",
1234 vrfEntry.getDestPrefix(), vpnId, rd);
1235 return; //Don't have any info for this prefix (shouldn't happen); need to return
1238 if (Prefixes.PrefixCue.Nat.equals(prefixInfo.getPrefixCue())) {
1239 LOG.debug("NAT Prefix {} with vpnId {} rd {}. Skip FIB processing",
1240 vrfEntry.getDestPrefix(), vpnId, rd);
1244 String ifName = prefixInfo.getVpnInterfaceName();
1245 jobCoordinator.enqueueJob("VPNINTERFACE-" + ifName,
1246 new CleanupVpnInterfaceWorker(prefixInfo, vpnId, rd, vrfEntry, extraRoute));
1249 private class CleanupVpnInterfaceWorker implements Callable<List<ListenableFuture<Void>>> {
1250 Prefixes prefixInfo;
1256 CleanupVpnInterfaceWorker(final Prefixes prefixInfo, final Long vpnId, final String rd,
1257 final VrfEntry vrfEntry, final Routes extraRoute) {
1258 this.prefixInfo = prefixInfo;
1261 this.vrfEntry = vrfEntry;
1262 this.extraRoute = extraRoute;
1266 public List<ListenableFuture<Void>> call() throws Exception {
1267 // If another renderer(for eg : CSS) needs to be supported, check can be performed here
1268 // to call the respective helpers.
1269 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
1270 //First Cleanup LabelRouteInfo
1271 //TODO(KIRAN) : Move the below block when addressing iRT/eRT for L3VPN Over VxLan
1272 LOG.debug("cleanupVpnInterfaceWorker: rd {} prefix {}", rd, prefixInfo.getIpAddress());
1273 if (VrfEntry.EncapType.Mplsgre.equals(vrfEntry.getEncapType())) {
1274 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
1275 List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
1276 synchronized (label.toString().intern()) {
1277 LabelRouteInfo lri = getLabelRouteInfo(label);
1278 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
1279 && nextHopAddressList.contains(lri.getNextHopIpList().get(0))) {
1280 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
1281 fibUtil.getVpnInstanceOpData(rd);
1282 String vpnInstanceName = "";
1283 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1284 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1286 boolean lriRemoved = deleteLabelRouteInfo(lri, vpnInstanceName, tx);
1288 String parentRd = lri.getParentVpnRd();
1289 fibUtil.releaseId(FibConstants.VPN_IDPOOL_NAME, FibUtil.getNextHopLabelKey(
1290 parentRd, vrfEntry.getDestPrefix()));
1293 fibUtil.releaseId(FibConstants.VPN_IDPOOL_NAME, FibUtil.getNextHopLabelKey(
1294 rd, vrfEntry.getDestPrefix()));
1299 String ifName = prefixInfo.getVpnInterfaceName();
1300 Optional<String> optVpnName = fibUtil.getVpnNameFromRd(rd);
1301 String vpnName = null;
1303 if (Prefixes.PrefixCue.PhysNetFunc.equals(prefixInfo.getPrefixCue())) {
1304 /*Get vpnId for rd = networkId since op vpnInterface will be pointing to rd = networkId
1306 Optional<String> vpnNameOpt = fibUtil.getVpnNameFromRd(vrfEntry.getParentVpnRd());
1307 if (vpnNameOpt.isPresent()) {
1308 vpnId = fibUtil.getVpnId(vpnNameOpt.get());
1311 if (optVpnName.isPresent()) {
1312 vpnName = optVpnName.get();
1313 Optional<VpnInterfaceOpDataEntry> opVpnInterface = MDSALUtil
1314 .read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1315 fibUtil.getVpnInterfaceOpDataEntryIdentifier(ifName, vpnName));
1316 if (opVpnInterface.isPresent()) {
1317 long associatedVpnId = fibUtil.getVpnId(vpnName);
1318 if (vpnId != associatedVpnId) {
1319 LOG.warn("Prefixes {} are associated with different vpn instance with id {} rather than {}",
1320 vrfEntry.getDestPrefix(), associatedVpnId, vpnId);
1321 LOG.warn("Not proceeding with Cleanup op data for prefix {}", vrfEntry.getDestPrefix());
1324 LOG.debug("Processing cleanup of prefix {} associated with vpn {}",
1325 vrfEntry.getDestPrefix(), associatedVpnId);
1329 if (extraRoute != null) {
1330 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
1331 //Only one used Rd present in case of removal event
1332 String usedRd = usedRds.get(0);
1333 if (optVpnName.isPresent()) {
1334 tx.delete(LogicalDatastoreType.OPERATIONAL,
1335 baseVrfEntryHandler.getVpnToExtrarouteIdentifier(vpnName, usedRd,
1336 vrfEntry.getDestPrefix()));
1337 tx.delete(LogicalDatastoreType.CONFIGURATION,
1338 VpnExtraRouteHelper.getUsedRdsIdentifier(vpnId, vrfEntry.getDestPrefix()));
1341 Optional<AdjacenciesOp> optAdjacencies =
1342 MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1343 FibUtil.getAdjListPathOp(ifName, vpnName));
1345 if (optAdjacencies.isPresent()) {
1346 numAdj = optAdjacencies.get().getAdjacency().size();
1348 //remove adjacency corr to prefix
1350 LOG.info("cleanUpOpDataForFib: remove adjacency for prefix: {} {} vpnName {}", vpnId,
1351 vrfEntry.getDestPrefix(), vpnName);
1352 tx.delete(LogicalDatastoreType.OPERATIONAL,
1353 FibUtil.getAdjacencyIdentifierOp(ifName, vpnName, vrfEntry.getDestPrefix()));
1355 //this is last adjacency (or) no more adjacency left for this vpn interface, so
1356 //clean up the vpn interface from DpnToVpn list
1357 LOG.info("Clean up vpn interface {} from dpn {} to vpn {} list.",
1358 ifName, prefixInfo.getDpnId(), rd);
1359 tx.delete(LogicalDatastoreType.OPERATIONAL,
1360 FibUtil.getVpnInterfaceOpDataEntryIdentifier(ifName, vpnName));
1366 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1367 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1368 final String rd = vrfTableKey.getRouteDistinguisher();
1369 final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(vrfTableKey.getRouteDistinguisher());
1370 if (vpnInstance == null) {
1371 LOG.error("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1374 final Collection<VpnToDpnList> vpnToDpnList;
1375 if (vrfEntry.getParentVpnRd() != null
1376 && FibHelper.isControllerManagedNonSelfImportedRoute(RouteOrigin.value(vrfEntry.getOrigin()))) {
1377 // This block MUST BE HIT only for PNF (Physical Network Function) FIB Entries.
1378 VpnInstanceOpDataEntry parentVpnInstance = fibUtil.getVpnInstance(vrfEntry.getParentVpnRd());
1379 vpnToDpnList = parentVpnInstance != null ? parentVpnInstance.getVpnToDpnList() :
1380 vpnInstance.getVpnToDpnList();
1381 LOG.info("deleteFibEntries: Processing deletion of PNF FIB entry with rd {} prefix {}",
1382 vrfEntry.getParentVpnRd(), vrfEntry.getDestPrefix());
1384 vpnToDpnList = vpnInstance.getVpnToDpnList();
1387 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1388 final java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1389 List<String> nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
1390 String vpnName = fibUtil.getVpnNameFromId(vpnInstance.getVpnId());
1391 if (subnetRoute != null) {
1392 long elanTag = subnetRoute.getElantag();
1393 LOG.trace("SUBNETROUTE: deleteFibEntries: SubnetRoute augmented vrfentry found for rd {} prefix {}"
1394 + " with elantag {}", rd, vrfEntry.getDestPrefix(), elanTag);
1395 if (vpnToDpnList != null) {
1396 jobCoordinator.enqueueJob(FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix()),
1397 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
1398 for (final VpnToDpnList curDpn : vpnToDpnList) {
1400 baseVrfEntryHandler.makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry,
1401 vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW, tx, null);
1402 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1403 optionalLabel.ifPresent(label -> makeLFibTableEntry(curDpn.getDpnId(), label, null,
1404 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx));
1407 installSubnetBroadcastAddrDropRule(curDpn.getDpnId(), rd, vpnInstance.getVpnId(),
1408 vrfEntry, NwConstants.DEL_FLOW, tx);
1412 optionalLabel.ifPresent(label -> {
1413 synchronized (label.toString().intern()) {
1414 LabelRouteInfo lri = getLabelRouteInfo(label);
1415 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
1416 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
1417 fibUtil.getVpnInstanceOpData(rd);
1418 String vpnInstanceName = "";
1419 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1420 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1422 boolean lriRemoved = this.deleteLabelRouteInfo(lri, vpnInstanceName, null);
1424 String parentRd = lri.getParentVpnRd();
1425 fibUtil.releaseId(FibConstants.VPN_IDPOOL_NAME, FibUtil.getNextHopLabelKey(
1426 parentRd, vrfEntry.getDestPrefix()));
1427 LOG.trace("SUBNETROUTE: deleteFibEntries: Released subnetroute label {} for rd {} prefix {}"
1428 + " as labelRouteInfo cleared", label, rd, vrfEntry.getDestPrefix());
1431 fibUtil.releaseId(FibConstants.VPN_IDPOOL_NAME, FibUtil.getNextHopLabelKey(
1432 rd, vrfEntry.getDestPrefix()));
1433 LOG.trace("SUBNETROUTE: deleteFibEntries: Released subnetroute label {} for rd {} prefix {}",
1434 label, rd, vrfEntry.getDestPrefix());
1441 final List<BigInteger> localDpnIdList = deleteLocalFibEntry(vpnInstance.getVpnId(),
1442 vrfTableKey.getRouteDistinguisher(), vrfEntry);
1443 if (vpnToDpnList != null) {
1444 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker,
1445 vpnInstance.getVpnId(), vrfEntry.getDestPrefix());
1447 Optional<Routes> extraRouteOptional;
1448 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
1449 if (usedRds != null && !usedRds.isEmpty()) {
1450 jobKey = FibUtil.getJobKeyForRdPrefix(usedRds.get(0), vrfEntry.getDestPrefix());
1451 if (usedRds.size() > 1) {
1452 LOG.error("The extra route prefix is still present in some DPNs");
1455 // The first rd is retrieved from usedrds as Only 1 rd would be present as extra route prefix
1456 //is not present in any other DPN
1457 extraRouteOptional = VpnExtraRouteHelper
1458 .getVpnExtraroutes(dataBroker, vpnName, usedRds.get(0), vrfEntry.getDestPrefix());
1461 jobKey = FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix());
1462 extraRouteOptional = Optional.absent();
1465 jobCoordinator.enqueueJob(jobKey,
1467 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1469 if (localDpnIdList.size() <= 0) {
1470 for (VpnToDpnList curDpn : vpnToDpnList) {
1471 baseVrfEntryHandler.deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(),
1472 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, tx);
1475 for (BigInteger localDpnId : localDpnIdList) {
1476 for (VpnToDpnList curDpn : vpnToDpnList) {
1477 if (!curDpn.getDpnId().equals(localDpnId)) {
1478 baseVrfEntryHandler.deleteRemoteRoute(localDpnId, curDpn.getDpnId(),
1479 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, tx);
1484 List<ListenableFuture<Void>> futures = new ArrayList<>();
1485 futures.add(tx.submit());
1487 }, DJC_MAX_RETRIES);
1490 //The flow/group entry has been deleted from config DS; need to clean up associated operational
1491 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
1492 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
1494 // Remove all fib entries configured due to interVpnLink, when nexthop is the opposite endPoint
1495 // of the interVpnLink.
1496 Optional<String> optVpnUuid = fibUtil.getVpnNameFromRd(rd);
1497 if (optVpnUuid.isPresent()) {
1498 String vpnUuid = optVpnUuid.get();
1499 FibUtil.getFirstNextHopAddress(vrfEntry).ifPresent(routeNexthop -> {
1500 Optional<InterVpnLinkDataComposite> optInterVpnLink = interVpnLinkCache.getInterVpnLinkByVpnId(vpnUuid);
1501 if (optInterVpnLink.isPresent()) {
1502 InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
1503 if (interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid)) {
1504 // This is route that points to the other endpoint of an InterVpnLink
1505 // In that case, we should look for the FIB table pointing to
1506 // LPortDispatcher table and remove it.
1507 removeInterVPNLinkRouteFlows(interVpnLink, vpnUuid, vrfEntry);
1515 private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions, int priority,
1516 int addOrRemove, WriteTransaction tx) {
1517 Boolean wrTxPresent = true;
1519 wrTxPresent = false;
1520 tx = dataBroker.newWriteOnlyTransaction();
1523 List<MatchInfo> matches = new ArrayList<>();
1524 matches.add(MatchEthernetType.MPLS_UNICAST);
1525 matches.add(new MatchMplsLabel(label));
1527 // Install the flow entry in L3_LFIB_TABLE
1528 String flowRef = FibUtil.getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, priority);
1530 FlowEntity flowEntity;
1531 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef, priority, flowRef, 0, 0,
1532 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
1533 Flow flow = flowEntity.getFlowBuilder().build();
1534 String flowId = flowEntity.getFlowId();
1535 FlowKey flowKey = new FlowKey(new FlowId(flowId));
1536 Node nodeDpn = FibUtil.buildDpnNode(dpId);
1537 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1538 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1539 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1541 if (addOrRemove == NwConstants.ADD_FLOW) {
1542 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, WriteTransaction.CREATE_MISSING_PARENTS);
1544 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1550 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} : key {} {} successfully",
1551 dpId, label, instructions, flowKey, NwConstants.ADD_FLOW == addOrRemove ? "ADDED" : "REMOVED");
1554 public void populateFibOnNewDpn(final BigInteger dpnId, final long vpnId, final String rd,
1555 final FutureCallback<List<Void>> callback) {
1556 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
1557 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1558 final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(rd);
1559 final Optional<VrfTables> vrfTable = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1560 List<SubTransaction> txnObjects = new ArrayList<>();
1561 if (!vrfTable.isPresent()) {
1562 LOG.info("populateFibOnNewDpn: dpn: {}: VRF Table not yet available for RD {}", dpnId, rd);
1563 if (callback != null) {
1564 List<ListenableFuture<Void>> futures = new ArrayList<>();
1565 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1566 Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor());
1571 jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, dpnId),
1573 List<ListenableFuture<Void>> futures = new ArrayList<>();
1574 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1575 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1576 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1577 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1578 if (subnetRoute != null) {
1579 long elanTag = subnetRoute.getElantag();
1580 installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
1581 installSubnetBroadcastAddrDropRule(dpnId, rd, vpnId, vrfEntry, NwConstants.ADD_FLOW, tx);
1584 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
1585 if (routerInt != null) {
1586 LOG.trace("Router augmented vrfentry found rd:{}, uuid:{}, ip:{}, mac:{}",
1587 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
1588 routerInterfaceVrfEntryHandler.installRouterFibEntry(vrfEntry, dpnId, vpnId,
1589 routerInt.getIpAddress(), new MacAddress(routerInt.getMacAddress()),
1590 NwConstants.ADD_FLOW);
1593 //Handle local flow creation for imports
1594 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
1595 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1596 if (optionalLabel.isPresent()) {
1597 List<String> nextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
1598 LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get());
1599 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList, lri)) {
1600 if (lri.getDpnId().equals(dpnId)) {
1601 createLocalFibEntry(vpnId, rd, vrfEntry);
1608 boolean shouldCreateRemoteFibEntry = shouldCreateFibEntryForVrfAndVpnIdOnDpn(vpnId,
1610 if (shouldCreateRemoteFibEntry) {
1611 LOG.trace("Will create remote FIB entry for vrfEntry {} on DPN {}",
1613 if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
1614 bgpRouteVrfEntryHandler.createRemoteFibEntry(dpnId, vpnId,
1615 vrfTable.get().getRouteDistinguisher(), vrfEntry, tx, txnObjects);
1617 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getRouteDistinguisher(),
1622 //TODO: if we have 100K entries in FIB, can it fit in one Tranasaction (?)
1623 futures.add(tx.submit());
1625 if (callback != null) {
1626 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1627 Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor());
1633 public void populateExternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1634 final String localNextHopIp, final String remoteNextHopIp) {
1635 LOG.trace("populateExternalRoutesOnDpn : dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} ",
1636 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1637 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1638 final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(rd);
1639 List<SubTransaction> txnObjects = new ArrayList<>();
1640 final Optional<VrfTables> vrfTable = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1641 if (vrfTable.isPresent()) {
1642 jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, dpnId),
1644 List<ListenableFuture<Void>> futures = new ArrayList<>();
1645 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1646 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
1647 vrfTable.get().getVrfEntry().stream()
1648 .filter(vrfEntry -> RouteOrigin.BGP == RouteOrigin.value(vrfEntry.getOrigin()))
1649 .forEach(bgpRouteVrfEntryHandler.getConsumerForCreatingRemoteFib(dpnId, vpnId,
1650 rd, remoteNextHopIp, vrfTable, writeCfgTxn, txnObjects));
1651 futures.add(writeCfgTxn.submit());
1658 public void manageRemoteRouteOnDPN(final boolean action,
1659 final BigInteger localDpnId,
1662 final String destPrefix,
1663 final String destTepIp,
1665 final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(rd);
1667 if (vpnInstance == null) {
1668 LOG.error("VpnInstance for rd {} not present for prefix {}", rd, destPrefix);
1672 jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, localDpnId),
1673 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
1674 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1675 VrfTablesKey vrfTablesKey = new VrfTablesKey(rd);
1676 VrfEntry vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1677 if (vrfEntry == null) {
1680 LOG.trace("manageRemoteRouteOnDPN :: action {}, DpnId {}, vpnId {}, rd {}, destPfx {}",
1681 action, localDpnId, vpnId, rd, destPrefix);
1682 List<RoutePaths> routePathList = vrfEntry.getRoutePaths();
1683 VrfEntry modVrfEntry;
1684 if (routePathList == null || routePathList.isEmpty()) {
1685 modVrfEntry = FibHelper.getVrfEntryBuilder(vrfEntry, label,
1686 Collections.singletonList(destTepIp),
1687 RouteOrigin.value(vrfEntry.getOrigin()), null /* parentVpnRd */).build();
1689 modVrfEntry = vrfEntry;
1693 LOG.trace("manageRemoteRouteOnDPN updated(add) vrfEntry :: {}", modVrfEntry);
1694 createRemoteFibEntry(localDpnId, vpnId, vrfTablesKey.getRouteDistinguisher(),
1697 LOG.trace("manageRemoteRouteOnDPN updated(remove) vrfEntry :: {}", modVrfEntry);
1698 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnInstance.getVpnId(),
1699 vrfEntry.getDestPrefix());
1700 if (usedRds.size() > 1) {
1701 LOG.debug("The extra route prefix is still present in some DPNs");
1704 //Is this fib route an extra route? If yes, get the nexthop which would be
1705 //an adjacency in the vpn
1706 Optional<Routes> extraRouteOptional = Optional.absent();
1707 if (usedRds.size() != 0) {
1708 extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker,
1709 fibUtil.getVpnNameFromId(vpnInstance.getVpnId()),
1710 usedRds.get(0), vrfEntry.getDestPrefix());
1712 baseVrfEntryHandler.deleteRemoteRoute(null, localDpnId, vpnId, vrfTablesKey, modVrfEntry,
1713 extraRouteOptional, tx);
1719 public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd,
1720 final FutureCallback<List<Void>> callback) {
1721 LOG.trace("cleanUpDpnForVpn: Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
1722 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1723 final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(rd);
1724 List<SubTransaction> txnObjects = new ArrayList<>();
1725 final Optional<VrfTables> vrfTable = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1726 jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, dpnId),
1728 List<ListenableFuture<Void>> futures = new ArrayList<>();
1729 if (vrfTable.isPresent()) {
1730 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1731 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1732 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1733 /* Handle subnet routes here */
1734 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1735 if (subnetRoute != null) {
1736 LOG.trace("SUBNETROUTE: cleanUpDpnForVpn: Cleaning subnetroute {} on dpn {}"
1737 + " for vpn {}", vrfEntry.getDestPrefix(), dpnId, rd);
1738 baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null,
1739 NwConstants.DEL_FLOW, tx, null);
1740 List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
1741 if (routePaths != null) {
1742 for (RoutePaths routePath : routePaths) {
1743 makeLFibTableEntry(dpnId, routePath.getLabel(), null,
1744 DEFAULT_FIB_FLOW_PRIORITY,
1745 NwConstants.DEL_FLOW, tx);
1746 LOG.trace("SUBNETROUTE: cleanUpDpnForVpn: Released subnetroute label {} for"
1747 + " rd {} prefix {}", routePath.getLabel(), rd,
1748 vrfEntry.getDestPrefix());
1751 installSubnetBroadcastAddrDropRule(dpnId, rd, vpnId, vrfEntry,
1752 NwConstants.DEL_FLOW, tx);
1755 // ping responder for router interfaces
1756 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
1757 if (routerInt != null) {
1758 LOG.trace("Router augmented vrfentry found for rd:{}, uuid:{}, ip:{}, mac:{}",
1759 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
1760 routerInterfaceVrfEntryHandler.installRouterFibEntry(vrfEntry, dpnId, vpnId,
1761 routerInt.getIpAddress(), new MacAddress(routerInt.getMacAddress()),
1762 NwConstants.DEL_FLOW);
1766 //Handle local flow deletion for imports
1767 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
1768 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1769 if (optionalLabel.isPresent()) {
1770 List<String> nextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry);
1771 LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get());
1772 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList, lri)) {
1773 if (lri.getDpnId().equals(dpnId)) {
1774 deleteLocalFibEntry(vpnId, rd, vrfEntry);
1781 // Passing null as we don't know the dpn
1782 // to which prefix is attached at this point
1783 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnInstance.getVpnId(),
1784 vrfEntry.getDestPrefix());
1785 String vpnName = fibUtil.getVpnNameFromId(vpnInstance.getVpnId());
1786 Optional<Routes> extraRouteOptional;
1787 //Is this fib route an extra route? If yes, get the nexthop which would be
1788 //an adjacency in the vpn
1789 if (usedRds != null && !usedRds.isEmpty()) {
1790 if (usedRds.size() > 1) {
1791 LOG.error("The extra route prefix is still present in some DPNs");
1794 extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, vpnName,
1795 usedRds.get(0), vrfEntry.getDestPrefix());
1799 extraRouteOptional = Optional.absent();
1801 if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
1802 bgpRouteVrfEntryHandler.deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(),
1803 vrfEntry, extraRouteOptional, tx, txnObjects);
1805 baseVrfEntryHandler.deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(),
1806 vrfEntry, extraRouteOptional, tx);
1809 futures.add(tx.submit());
1811 if (callback != null) {
1812 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1813 Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor());
1821 public void cleanUpExternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1822 final String localNextHopIp, final String remoteNextHopIp) {
1823 LOG.trace("cleanUpExternalRoutesOnDpn : cleanup remote routes on dpn {} for vpn {}, rd {}, "
1824 + " localNexthopIp {} , remoteNexhtHopIp {}",
1825 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1826 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1827 final VpnInstanceOpDataEntry vpnInstance = fibUtil.getVpnInstance(rd);
1828 List<SubTransaction> txnObjects = new ArrayList<>();
1829 final Optional<VrfTables> vrfTable = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1830 if (vrfTable.isPresent()) {
1831 jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, dpnId),
1833 List<ListenableFuture<Void>> futures = new ArrayList<>();
1834 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1835 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
1836 vrfTable.get().getVrfEntry().stream()
1837 .filter(vrfEntry -> RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP)
1838 .forEach(bgpRouteVrfEntryHandler.getConsumerForDeletingRemoteFib(dpnId, vpnId, rd,
1839 remoteNextHopIp, vrfTable, writeCfgTxn, txnObjects));
1840 futures.add(writeCfgTxn.submit());
1847 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
1848 InstanceIdentifierBuilder<VrfTables> idBuilder =
1849 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1850 return idBuilder.build();
1853 private String getInterVpnFibFlowRef(String interVpnLinkName, String prefix, String nextHop) {
1854 return FLOWID_PREFIX + interVpnLinkName + NwConstants.FLOWID_SEPARATOR + prefix + NwConstants
1855 .FLOWID_SEPARATOR + nextHop;
1858 private String getTableMissFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
1859 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR
1860 + tableMiss + FLOWID_PREFIX;
1863 private VrfEntry getVrfEntry(DataBroker broker, String rd, String ipPrefix) {
1864 InstanceIdentifier<VrfEntry> vrfEntryId = InstanceIdentifier.builder(FibEntries.class)
1865 .child(VrfTables.class, new VrfTablesKey(rd))
1866 .child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
1867 Optional<VrfEntry> vrfEntry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
1868 if (vrfEntry.isPresent()) {
1869 return vrfEntry.get();
1874 public void removeInterVPNLinkRouteFlows(final InterVpnLinkDataComposite interVpnLink,
1875 final String vpnName,
1876 final VrfEntry vrfEntry) {
1877 Preconditions.checkArgument(vrfEntry.getRoutePaths() != null && vrfEntry.getRoutePaths().size() == 1);
1879 String interVpnLinkName = interVpnLink.getInterVpnLinkName();
1880 List<BigInteger> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnName);
1882 if (targetDpns.isEmpty()) {
1883 LOG.warn("Could not find DPNs for VPN {} in InterVpnLink {}", vpnName, interVpnLinkName);
1887 java.util.Optional<String> optNextHop = FibUtil.getFirstNextHopAddress(vrfEntry);
1888 java.util.Optional<Long> optLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1892 optNextHop.ifPresent(nextHop -> {
1893 String flowRef = getInterVpnFibFlowRef(interVpnLinkName, vrfEntry.getDestPrefix(), nextHop);
1894 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
1895 Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef))
1896 .setTableId(NwConstants.L3_FIB_TABLE).setFlowName(flowRef).build();
1898 LOG.trace("Removing flow in FIB table for interVpnLink {} key {}", interVpnLinkName, flowRef);
1899 for (BigInteger dpId : targetDpns) {
1900 LOG.debug("Removing flow: VrfEntry=[prefix={} nexthop={}] dpn {} for InterVpnLink {} in FIB",
1901 vrfEntry.getDestPrefix(), nextHop, dpId, interVpnLinkName);
1903 mdsalManager.removeFlow(dpId, flow);
1909 optLabel.ifPresent(label -> {
1910 LOG.trace("Removing flow in FIB table for interVpnLink {}", interVpnLinkName);
1912 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1913 for (BigInteger dpId : targetDpns) {
1914 LOG.debug("Removing flow: VrfEntry=[prefix={} label={}] dpn {} for InterVpnLink {} in LFIB",
1915 vrfEntry.getDestPrefix(), label, dpId, interVpnLinkName);
1916 makeLFibTableEntry(dpId, label, /*instructions*/null, LFIB_INTERVPN_PRIORITY, NwConstants.DEL_FLOW, tx);
1922 private boolean isPrefixAndNextHopPresentInLri(String prefix,
1923 List<String> nextHopAddressList, LabelRouteInfo lri) {
1924 return lri != null && lri.getPrefix().equals(prefix)
1925 && nextHopAddressList.contains(lri.getNextHopIpList().get(0));
1928 private boolean shouldCreateFibEntryForVrfAndVpnIdOnDpn(Long vpnId, VrfEntry vrfEntry, BigInteger dpnId) {
1929 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1933 Prefixes prefix = fibUtil.getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
1934 if (prefix != null) {
1935 BigInteger prefixDpnId = prefix.getDpnId();
1936 if (dpnId.equals(prefixDpnId)) {
1937 LOG.trace("Should not create remote FIB entry for vrfEntry {} on DPN {}",