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 java.util.stream.Collectors.toList;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
18 import java.math.BigInteger;
19 import java.net.Inet4Address;
20 import java.net.InetAddress;
21 import java.net.UnknownHostException;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collection;
25 import java.util.Collections;
26 import java.util.List;
27 import java.util.concurrent.BlockingQueue;
28 import java.util.concurrent.Callable;
29 import java.util.concurrent.LinkedBlockingQueue;
30 import java.util.function.Consumer;
32 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
33 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
34 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
35 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
36 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
37 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
38 import org.opendaylight.genius.mdsalutil.ActionInfo;
39 import org.opendaylight.genius.mdsalutil.FlowEntity;
40 import org.opendaylight.genius.mdsalutil.InstructionInfo;
41 import org.opendaylight.genius.mdsalutil.MDSALUtil;
42 import org.opendaylight.genius.mdsalutil.MatchInfo;
43 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
44 import org.opendaylight.genius.mdsalutil.NwConstants;
45 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
46 import org.opendaylight.genius.mdsalutil.actions.ActionMoveSourceDestinationEth;
47 import org.opendaylight.genius.mdsalutil.actions.ActionMoveSourceDestinationIp;
48 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
49 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
50 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
51 import org.opendaylight.genius.mdsalutil.actions.ActionPushMpls;
52 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
53 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetDestination;
54 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
55 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldMplsLabel;
56 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
57 import org.opendaylight.genius.mdsalutil.actions.ActionSetIcmpType;
58 import org.opendaylight.genius.mdsalutil.actions.ActionSetSourceIp;
59 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
60 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
61 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
62 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
63 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
64 import org.opendaylight.genius.mdsalutil.matches.MatchIcmpv4;
65 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
66 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
67 import org.opendaylight.genius.mdsalutil.matches.MatchIpv6Destination;
68 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
69 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
70 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
71 import org.opendaylight.genius.utils.ServiceIndex;
72 import org.opendaylight.genius.utils.batching.ActionableResource;
73 import org.opendaylight.genius.utils.batching.ActionableResourceImpl;
74 import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
75 import org.opendaylight.genius.utils.batching.ResourceHandler;
76 import org.opendaylight.genius.utils.batching.SubTransaction;
77 import org.opendaylight.genius.utils.batching.SubTransactionImpl;
78 import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
79 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
80 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
81 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
82 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.IVpnLinkService;
83 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
84 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
85 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
86 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroutes;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesBuilder;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.Vpn;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.VpnKey;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.ExtraRoutes;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.ExtraRoutesKey;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.RoutesKey;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState.State;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
138 import org.opendaylight.yangtools.yang.binding.DataObject;
139 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
140 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
141 import org.slf4j.Logger;
142 import org.slf4j.LoggerFactory;
144 public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry, VrfEntryListener>
145 implements AutoCloseable, ResourceHandler {
147 private static final Logger LOG = LoggerFactory.getLogger(VrfEntryListener.class);
148 private static final String FLOWID_PREFIX = "L3.";
149 private static final int BATCH_SIZE = 1000;
150 private static final int PERIODICITY = 500;
151 private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16);
152 private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
153 private static final int LFIB_INTERVPN_PRIORITY = 15;
154 public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
156 private final DataBroker dataBroker;
157 private final IMdsalApiManager mdsalManager;
158 private final NexthopManager nextHopManager;
159 private final OdlInterfaceRpcService interfaceManager;
160 private final IdManagerService idManager;
161 private final IVpnLinkService ivpnLinkService;
162 List<SubTransaction> transactionObjects;
164 private static Integer batchSize;
165 private static Integer batchInterval;
167 private static BlockingQueue<ActionableResource> vrfEntryBufferQ = new LinkedBlockingQueue<>();
168 private final ResourceBatchingManager resourceBatchingManager;
170 public VrfEntryListener(final DataBroker dataBroker, final IMdsalApiManager mdsalApiManager,
171 final NexthopManager nexthopManager, final OdlInterfaceRpcService interfaceManager,
172 final IdManagerService idManager, final IVpnLinkService ivpnLinkService) {
173 super(VrfEntry.class, VrfEntryListener.class);
174 this.dataBroker = dataBroker;
175 this.mdsalManager = mdsalApiManager;
176 this.nextHopManager = nexthopManager;
177 this.interfaceManager = interfaceManager;
178 this.idManager = idManager;
179 this.ivpnLinkService = ivpnLinkService;
181 batchSize = Integer.getInteger("batch.size", BATCH_SIZE);
182 batchInterval = Integer.getInteger("batch.wait.time", PERIODICITY);
183 resourceBatchingManager = ResourceBatchingManager.getInstance();
184 resourceBatchingManager.registerBatchableResource("FIB-VRFENTRY", vrfEntryBufferQ, this);
185 transactionObjects = new ArrayList<>();
188 public void start() {
189 LOG.info("{} start", getClass().getSimpleName());
190 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
194 protected VrfEntryListener getDataTreeChangeListener() {
195 return VrfEntryListener.this;
199 protected InstanceIdentifier<VrfEntry> getWildCardPath() {
200 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
204 public DataBroker getResourceBroker() {
208 public NexthopManager getNextHopManager() {
209 return this.nextHopManager;
213 protected void add(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
214 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
215 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
216 LOG.debug("ADD: Adding Fib Entry rd {} prefix {} route-paths {}",
217 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
218 if (vrfEntry.getEncapType().equals(VrfEntry.EncapType.Vxlan)) {
219 LOG.info("EVPN flows need to be programmed.");
220 EVPNVrfEntryProcessor evpnVrfEntryProcessor = new EVPNVrfEntryProcessor(identifier,
221 vrfEntry, dataBroker, this);
222 evpnVrfEntryProcessor.installFlows();
224 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
225 createFibEntries(identifier, vrfEntry);
227 ActionableResource actResource = new ActionableResourceImpl(rd + vrfEntry.getDestPrefix());
228 actResource.setAction(ActionableResource.CREATE);
229 actResource.setInstanceIdentifier(identifier);
230 actResource.setInstance(vrfEntry);
231 vrfEntryBufferQ.add(actResource);
234 leakRouteIfNeeded(identifier, vrfEntry, NwConstants.ADD_FLOW);
235 LOG.info("ADD: Added Fib Entry rd {} prefix {} route-paths {}",
236 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
240 protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
241 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
242 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
243 LOG.debug("REMOVE: Removing Fib Entry rd {} prefix {} route-paths {}",
244 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
245 if (vrfEntry.getEncapType().equals(VrfEntry.EncapType.Vxlan)) {
246 LOG.info("EVPN flows to be deleted");
247 EVPNVrfEntryProcessor evpnVrfEntryProcessor = new EVPNVrfEntryProcessor(identifier, vrfEntry,
249 evpnVrfEntryProcessor.removeFlows();
251 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
252 deleteFibEntries(identifier, vrfEntry);
254 ActionableResource actResource = new ActionableResourceImpl(rd + vrfEntry.getDestPrefix());
255 actResource.setAction(ActionableResource.DELETE);
256 actResource.setInstanceIdentifier(identifier);
257 actResource.setInstance(vrfEntry);
258 vrfEntryBufferQ.add(actResource);
261 leakRouteIfNeeded(identifier, vrfEntry, NwConstants.DEL_FLOW);
262 LOG.info("REMOVE: Removed Fib Entry rd {} prefix {} route-paths {}",
263 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
267 protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
268 Preconditions.checkNotNull(update, "VrfEntry should not be null or empty.");
270 final String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
271 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
272 LOG.debug("UPDATE: Updating Fib Entries to rd {} prefix {} route-paths {}",
273 rd, update.getDestPrefix(), update.getRoutePaths());
274 // Handle BGP Routes first
275 if (RouteOrigin.value(update.getOrigin()) == RouteOrigin.BGP) {
276 ActionableResource actResource = new ActionableResourceImpl(rd + update.getDestPrefix());
277 actResource.setAction(ActionableResource.UPDATE);
278 actResource.setInstanceIdentifier(identifier);
279 actResource.setInstance(update);
280 actResource.setOldInstance(original);
281 vrfEntryBufferQ.add(actResource);
282 LOG.info("UPDATE: Updated Fib Entries to rd {} prefix {} route-paths {}",
283 rd, update.getDestPrefix(), update.getRoutePaths());
287 // Handle Vpn Interface driven Routes next (ie., STATIC and LOCAL)
288 if (FibHelper.isControllerManagedVpnInterfaceRoute(RouteOrigin.value(update.getOrigin()))) {
289 List<RoutePaths> originalRoutePath = original.getRoutePaths();
290 List<RoutePaths> updateRoutePath = update.getRoutePaths();
291 LOG.info("UPDATE: Original route-path {} update route-path {} ", originalRoutePath, updateRoutePath);
293 // If original VRF Entry had nexthop null , but update VRF Entry
294 // has nexthop , route needs to be created on remote Dpns
295 if (((originalRoutePath == null) || (originalRoutePath.isEmpty())
296 && (updateRoutePath != null) && (!updateRoutePath.isEmpty()))) {
297 // TODO(vivek): Though ugly, Not handling this code now, as each
298 // tep add event will invoke flow addition
299 LOG.trace("Original VRF entry NH is null for destprefix {}. This event is IGNORED here.",
300 update.getDestPrefix());
304 // If original VRF Entry had valid nexthop , but update VRF Entry
305 // has nexthop empty'ed out, route needs to be removed from remote Dpns
306 if (((updateRoutePath == null) || (updateRoutePath.isEmpty())
307 && (originalRoutePath != null) && (!originalRoutePath.isEmpty()))) {
308 LOG.trace("Original VRF entry had valid NH for destprefix {}. This event is IGNORED here.",
309 update.getDestPrefix());
312 createFibEntries(identifier, update);
313 LOG.info("UPDATE: Updated Fib Entries to rd {} prefix {} route-paths {}",
314 rd, update.getDestPrefix(), update.getRoutePaths());
318 /* Handl all other route origins */
319 createFibEntries(identifier, update);
321 LOG.info("UPDATE: Updated Fib Entries to rd {} prefix {} route-paths {}",
322 rd, update.getDestPrefix(), update.getRoutePaths());
326 public void update(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier,
327 Object original, Object update, List<SubTransaction> transactionObjects) {
328 this.transactionObjects = transactionObjects;
329 if ((original instanceof VrfEntry) && (update instanceof VrfEntry)) {
330 createFibEntries(tx, identifier, (VrfEntry) update);
335 public void create(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier,
336 Object vrfEntry, List<SubTransaction> transactionObjects) {
337 this.transactionObjects = transactionObjects;
338 if (vrfEntry instanceof VrfEntry) {
339 createFibEntries(tx, identifier, (VrfEntry) vrfEntry);
344 public void delete(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier,
345 Object vrfEntry, List<SubTransaction> transactionObjects) {
346 this.transactionObjects = transactionObjects;
347 if (vrfEntry instanceof VrfEntry) {
348 deleteFibEntries(tx, identifier, (VrfEntry) vrfEntry);
353 public int getBatchSize() {
358 public int getBatchInterval() {
359 return batchInterval;
363 public LogicalDatastoreType getDatastoreType() {
364 return LogicalDatastoreType.CONFIGURATION;
367 private void createFibEntries(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
368 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
370 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
371 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
372 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId()
373 + " has null vpnId!");
374 final Collection<VpnToDpnList> vpnToDpnList;
375 if (vrfEntry.getParentVpnRd() != null
376 && FibHelper.isControllerManagedNonSelfImportedRoute(RouteOrigin.value(vrfEntry.getOrigin()))) {
377 VpnInstanceOpDataEntry parentVpnInstance = getVpnInstance(vrfEntry.getParentVpnRd());
378 vpnToDpnList = parentVpnInstance != null ? parentVpnInstance.getVpnToDpnList() :
379 vpnInstance.getVpnToDpnList();
381 vpnToDpnList = vpnInstance.getVpnToDpnList();
384 final Long vpnId = vpnInstance.getVpnId();
385 final String rd = vrfTableKey.getRouteDistinguisher();
386 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
387 if (subnetRoute != null) {
388 final long elanTag = subnetRoute.getElantag();
389 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
390 rd, vrfEntry.getDestPrefix(), elanTag);
391 if (vpnToDpnList != null) {
392 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
393 dataStoreCoordinator.enqueueJob("FIB-" + rd + "-" + vrfEntry.getDestPrefix(), () -> {
394 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
395 for (final VpnToDpnList curDpn : vpnToDpnList) {
396 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
397 installSubnetRouteInFib(curDpn.getDpnId(), elanTag, rd, vpnId, vrfEntry, tx);
400 List<ListenableFuture<Void>> futures = new ArrayList<>();
401 futures.add(tx.submit());
407 // ping responder for router interfaces
408 if (installRouterFibEntries(vrfEntry, vpnToDpnList, vpnId, NwConstants.ADD_FLOW)) {
412 final List<BigInteger> localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry);
413 if (!localDpnIdList.isEmpty()) {
414 if (vpnToDpnList != null) {
415 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
416 dataStoreCoordinator.enqueueJob("FIB-" + rd + "-" + vrfEntry.getDestPrefix(), () -> {
417 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
418 for (VpnToDpnList vpnDpn : vpnToDpnList) {
419 if (!localDpnIdList.contains(vpnDpn.getDpnId())) {
420 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
421 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry,
426 List<ListenableFuture<Void>> futures = new ArrayList<>();
427 futures.add(tx.submit());
433 Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(dataBroker, rd);
434 if (optVpnUuid.isPresent()) {
435 Optional<InterVpnLinkDataComposite> optInterVpnLink =
436 InterVpnLinkCache.getInterVpnLinkByVpnId(optVpnUuid.get());
437 LOG.debug("InterVpnLink {} found in Cache: {}", optVpnUuid.get(), optInterVpnLink.isPresent());
438 if (optInterVpnLink.isPresent()) {
439 InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
440 String vpnUuid = optVpnUuid.get();
441 FibUtil.getFirstNextHopAddress(vrfEntry).ifPresent(routeNexthop -> {
442 if (interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid)) {
443 // This is an static route that points to the other endpoint of an InterVpnLink
444 // In that case, we should add another entry in FIB table pointing to LPortDispatcher table.
445 installIVpnLinkSwitchingFlows(interVpnLink, vpnUuid, vrfEntry, vpnId);
446 installInterVpnRouteInLFib(rd, vrfEntry);
454 Please note that the following createFibEntries will be invoked only for BGP Imported Routes.
455 The invocation of the following method is via create() callback from the MDSAL Batching Infrastructure
456 provided by ResourceBatchingManager
458 private void createFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> vrfEntryIid,
459 final VrfEntry vrfEntry) {
460 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
462 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
463 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
464 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId()
465 + " has null vpnId!");
467 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
468 if (vpnToDpnList != null) {
469 for (VpnToDpnList vpnDpn : vpnToDpnList) {
470 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
471 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, writeTx);
477 // FIXME: Refactoring needed here.
478 // This kind of logic must be taken to an 'upper' layer like BgpManager or VpnManager
479 private void leakRouteIfNeeded(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry,
481 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
482 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
484 String prefix = vrfEntry.getDestPrefix();
485 List<String> nextHopsList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
486 // Label is used only for logging in subsequent method calls.
487 //TODO : This label is not needed here. Can be removed. Hence using a default value.
488 Long label = FibUtil.getLabelFromRoutePaths(vrfEntry).orElse(0L);
489 String rd = vrfTableKey.getRouteDistinguisher();
490 LOG.trace("leakRouteIfNeeded: srcVpnRd={} prefix={} nhList={} label={}", rd, prefix, nextHopsList, label);
492 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
493 if (vpnInstance == null) {
494 LOG.error("VPN Instance not available for route with prefix {} label {} nextHop {} RD {}. Returning...",
495 prefix, label, nextHopsList, rd);
498 String vpnUuid = vpnInstance.getVpnInstanceName();
499 if (vpnUuid == null || vpnUuid.isEmpty()) {
500 LOG.warn("Could not find suitable VPN UUID for rd={}. vrfEntry=[prefix={} nhList={} label={}]",
501 rd, prefix, nextHopsList, label);
505 ivpnLinkService.leakRouteIfNeeded(vpnUuid, prefix, nextHopsList, label.intValue(),
506 RouteOrigin.value(vrfEntry.getOrigin()), addOrRemove);
509 private Prefixes updateVpnReferencesInLri(LabelRouteInfo lri, String vpnInstanceName, boolean isPresentInList) {
510 LOG.debug("updating LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
511 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
512 prefixBuilder.setDpnId(lri.getDpnId());
513 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
514 prefixBuilder.setIpAddress(lri.getPrefix());
515 // Increment the refCount here
516 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
517 .child(LabelRouteInfo.class, new LabelRouteInfoKey(lri.getLabel())).build();
518 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri);
519 if (!isPresentInList) {
520 LOG.debug("vpnName {} is not present in LRI with label {}..", vpnInstanceName, lri.getLabel());
521 List<String> vpnInstanceNames = lri.getVpnInstanceList();
522 vpnInstanceNames.add(vpnInstanceName);
523 builder.setVpnInstanceList(vpnInstanceNames);
524 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(),
525 FibUtil.DEFAULT_CALLBACK);
527 LOG.debug("vpnName {} is present in LRI with label {}..", vpnInstanceName, lri.getLabel());
529 return prefixBuilder.build();
532 private void installSubnetRouteInFib(final BigInteger dpnId, final long elanTag, final String rd,
533 final long vpnId, final VrfEntry vrfEntry, WriteTransaction tx) {
534 Boolean wrTxPresent = true;
537 tx = dataBroker.newWriteOnlyTransaction();
539 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
540 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
541 synchronized (label.toString().intern()) {
542 LabelRouteInfo lri = getLabelRouteInfo(label);
543 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
545 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
546 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
547 FibUtil.getVpnInstanceOpData(dataBroker, rd);
548 if (vpnInstanceOpDataEntryOptional.isPresent()) {
549 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
550 if (!lri.getVpnInstanceList().contains(vpnInstanceName)) {
551 updateVpnReferencesInLri(lri, vpnInstanceName, false);
555 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
556 label, lri.getVpnInterfaceName(), lri.getDpnId());
560 final List<InstructionInfo> instructions = new ArrayList<>();
561 BigInteger subnetRouteMeta = ((BigInteger.valueOf(elanTag)).shiftLeft(24))
562 .or((BigInteger.valueOf(vpnId).shiftLeft(1)));
563 instructions.add(new InstructionWriteMetadata(subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE));
564 instructions.add(new InstructionGotoTable(NwConstants.L3_SUBNET_ROUTE_TABLE));
565 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
567 for (RoutePaths routePath : vrfEntry.getRoutePaths()) {
568 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
569 List<ActionInfo> actionsInfos = new ArrayList<>();
570 // reinitialize instructions list for LFIB Table
571 final List<InstructionInfo> LFIBinstructions = new ArrayList<>();
573 actionsInfos.add(new ActionPopMpls());
574 LFIBinstructions.add(new InstructionApplyActions(actionsInfos));
575 LFIBinstructions.add(new InstructionWriteMetadata(subnetRouteMeta,
576 MetaDataUtil.METADATA_MASK_SUBNET_ROUTE));
577 LFIBinstructions.add(new InstructionGotoTable(NwConstants.L3_SUBNET_ROUTE_TABLE));
579 makeLFibTableEntry(dpnId, routePath.getLabel(), LFIBinstructions, DEFAULT_FIB_FLOW_PRIORITY,
580 NwConstants.ADD_FLOW, tx);
589 * For a given route, it installs a flow in LFIB that sets the lportTag of the other endpoint and sends to
590 * LportDispatcher table (via table 80)
592 private void installInterVpnRouteInLFib(final String rd, final VrfEntry vrfEntry) {
593 // INTERVPN routes are routes in a Vpn1 that have been leaked to Vpn2. In DC-GW, this Vpn2 route is pointing
594 // to a list of DPNs where Vpn2's VpnLink was instantiated. In these DPNs LFIB must be programmed so that the
595 // packet is commuted from Vpn2 to Vpn1.
596 Optional<String> vpnNameOpc = FibUtil.getVpnNameFromRd(dataBroker, rd);
597 if (!vpnNameOpc.isPresent()) {
598 LOG.warn("Could not find VpnInstanceName for Route-Distinguisher {}", rd);
602 String vpnName = vpnNameOpc.get();
603 List<InterVpnLink> interVpnLinks = FibUtil.getAllInterVpnLinks(dataBroker);
604 boolean interVpnLinkFound = false;
605 for (InterVpnLink interVpnLink : interVpnLinks) {
606 boolean vpnIs1stEndpoint = interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName);
607 boolean vpnIs2ndEndpoint = !vpnIs1stEndpoint
608 && interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnName);
609 if (vpnIs1stEndpoint || vpnIs2ndEndpoint) {
610 interVpnLinkFound = true;
612 Optional<InterVpnLinkState> vpnLinkState =
613 FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName());
614 if (!vpnLinkState.isPresent()
615 || !vpnLinkState.get().getState().equals(InterVpnLinkState.State.Active)) {
616 LOG.warn("InterVpnLink {}, linking VPN {} and {}, is not in Active state",
617 interVpnLink.getName(), interVpnLink.getFirstEndpoint().getVpnUuid().getValue(),
618 interVpnLink.getSecondEndpoint().getVpnUuid().getValue());
622 List<BigInteger> targetDpns = vpnIs1stEndpoint ? vpnLinkState.get().getFirstEndpointState().getDpId()
623 : vpnLinkState.get().getSecondEndpointState().getDpId();
624 Long lportTag = vpnIs1stEndpoint ? vpnLinkState.get().getSecondEndpointState().getLportTag()
625 : vpnLinkState.get().getFirstEndpointState().getLportTag();
627 LOG.trace("Installing flow in LFIB table for interVpnLink {}", interVpnLink.getName());
629 for (BigInteger dpId : targetDpns) {
630 List<ActionInfo> actionsInfos = Collections.singletonList(new ActionPopMpls());
632 List<InstructionInfo> instructions =
633 Arrays.asList(new InstructionApplyActions(actionsInfos),
634 new InstructionWriteMetadata(
635 MetaDataUtil.getMetaDataForLPortDispatcher(lportTag.intValue(),
636 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
637 NwConstants.L3VPN_SERVICE_INDEX)),
638 MetaDataUtil.getMetaDataMaskForLPortDispatcher()),
639 new InstructionGotoTable(NwConstants.L3_INTERFACE_TABLE));
641 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(interVpnRoutePathLabel -> {
642 List<String> interVpnNextHopList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
643 LOG.debug("Installing flow: VrfEntry=[prefix={} label={} nexthop={}] dpn {} for "
644 + "InterVpnLink {} in LFIB",
645 vrfEntry.getDestPrefix(), interVpnRoutePathLabel, interVpnNextHopList,
646 dpId, interVpnLink.getName());
648 makeLFibTableEntry(dpId, interVpnRoutePathLabel, instructions, LFIB_INTERVPN_PRIORITY,
649 NwConstants.ADD_FLOW, null);
657 if (!interVpnLinkFound) {
658 LOG.warn("VrfEntry=[prefix={} route-paths={}] for VPN {} has origin INTERVPN but "
659 + "no InterVpnLink could be found",
660 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(), rd);
666 * Installs the flows in FIB table that, for a given route, do the switching from one VPN to the other.
668 private void installIVpnLinkSwitchingFlows(final InterVpnLinkDataComposite interVpnLink, final String vpnUuid,
669 final VrfEntry vrfEntry, long vpnTag) {
670 Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
671 Preconditions.checkArgument(vrfEntry.getRoutePaths() != null
672 && vrfEntry.getRoutePaths().size() == 1);
673 String destination = vrfEntry.getDestPrefix();
674 String nextHop = vrfEntry.getRoutePaths().get(0).getNexthopAddress();
675 String interVpnLinkName = interVpnLink.getInterVpnLinkName();
677 // After having received a static route, we should check if the vpn is part of an inter-vpn-link.
678 // In that case, we should populate the FIB table of the VPN pointing to LPortDisptacher table
679 // using as metadata the LPortTag associated to that vpn in the inter-vpn-link.
680 if (interVpnLink.getState().or(State.Error) != State.Active) {
681 LOG.warn("Route to {} with nexthop={} cannot be installed because the interVpnLink {} is not active",
682 destination, nextHop, interVpnLinkName);
686 Optional<Long> optOtherEndpointLportTag = interVpnLink.getOtherEndpointLportTagByVpnName(vpnUuid);
687 if (!optOtherEndpointLportTag.isPresent()) {
688 LOG.warn("Could not find suitable LportTag for the endpoint opposite to vpn {} in interVpnLink {}",
689 vpnUuid, interVpnLinkName);
693 List<BigInteger> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnUuid);
694 if (targetDpns.isEmpty()) {
695 LOG.warn("Could not find DPNs for endpoint opposite to vpn {} in interVpnLink {}",
696 vpnUuid, interVpnLinkName);
700 String[] values = destination.split("/");
701 String destPrefixIpAddress = values[0];
702 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
704 List<MatchInfo> matches = new ArrayList<>();
705 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnTag), MetaDataUtil.METADATA_MASK_VRFID));
706 matches.add(MatchEthernetType.IPV4);
708 if (prefixLength != 0) {
709 matches.add(new MatchIpv4Destination(destPrefixIpAddress, Integer.toString(prefixLength)));
712 List<Instruction> instructions =
713 Arrays.asList(new InstructionWriteMetadata(
714 MetaDataUtil.getMetaDataForLPortDispatcher(optOtherEndpointLportTag.get().intValue(),
715 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants
716 .L3VPN_SERVICE_INDEX)),
717 MetaDataUtil.getMetaDataMaskForLPortDispatcher()).buildInstruction(0),
718 new InstructionGotoTable(NwConstants.L3_INTERFACE_TABLE).buildInstruction(1));
720 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
721 String flowRef = getInterVpnFibFlowRef(interVpnLinkName, destination, nextHop);
722 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
723 COOKIE_VM_FIB_TABLE, matches, instructions);
725 LOG.trace("Installing flow in FIB table for vpn {} interVpnLink {} nextHop {} key {}",
726 vpnUuid, interVpnLink.getInterVpnLinkName(), nextHop, flowRef);
728 for (BigInteger dpId : targetDpns) {
730 LOG.debug("Installing flow: VrfEntry=[prefix={} route-paths={}] dpn {} for InterVpnLink {} in FIB",
731 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(),
732 dpId, interVpnLink.getInterVpnLinkName());
734 mdsalManager.installFlow(dpId, flowEntity);
739 // TODO Clean up the exception handling
740 @SuppressWarnings("checkstyle:IllegalCatch")
741 private <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
742 InstanceIdentifier<T> path) {
744 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
746 Optional<T> result = Optional.absent();
748 result = tx.read(datastoreType, path).get();
749 } catch (Exception e) {
750 throw new RuntimeException(e);
756 private List<BigInteger> getDpnIdForPrefix(DataBroker broker, Long vpnId, String rd, VrfEntry vrfEntry) {
757 List<BigInteger> returnLocalDpnId = new ArrayList<>();
758 Prefixes localNextHopInfo = FibUtil.getPrefixToInterface(broker, vpnId, vrfEntry.getDestPrefix());
760 if (localNextHopInfo == null) {
761 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
762 Optional<Routes> extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker,
763 FibUtil.getVpnNameFromId(dataBroker, vpnId), rd, vrfEntry.getDestPrefix());
764 if (extraRouteOptional.isPresent()) {
765 Routes extraRoute = extraRouteOptional.get();
766 for (String nextHopIp : extraRoute.getNexthopIpList()) {
767 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
768 if (nextHopIp != null) {
769 localNextHopInfo = FibUtil.getPrefixToInterface(broker, vpnId, nextHopIp
770 + NwConstants.IPV4PREFIX);
771 if (localNextHopInfo != null) {
772 returnLocalDpnId.add(localNextHopInfo.getDpnId());
778 returnLocalDpnId.add(localNextHopInfo.getDpnId());
781 return returnLocalDpnId;
784 private List<BigInteger> createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
785 List<BigInteger> returnLocalDpnId = new ArrayList<>();
786 Prefixes localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
787 String localNextHopIP = vrfEntry.getDestPrefix();
788 String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnId);
789 if (localNextHopInfo == null) {
790 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
791 List<Routes> vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker,
792 vpnName, usedRds, localNextHopIP);
793 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
794 vpnExtraRoutes.stream().forEach(extraRoute -> {
795 Prefixes localNextHopInfoLocal = FibUtil.getPrefixToInterface(dataBroker,
796 vpnId, extraRoute.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX);
797 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfoLocal, vrfEntry.getDestPrefix(),
798 vpnId, rd, vrfEntry, vpnId, extraRoute, vpnExtraRoutes);
799 returnLocalDpnId.add(dpnId);
801 if (localNextHopInfo == null) {
802 /* imported routes case */
803 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
804 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
805 if (optionalLabel.isPresent()) {
806 Long label = optionalLabel.get();
807 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
808 synchronized (label.toString().intern()) {
809 LabelRouteInfo lri = getLabelRouteInfo(label);
810 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
811 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
812 FibUtil.getVpnInstanceOpData(dataBroker, rd);
813 if (vpnInstanceOpDataEntryOptional.isPresent()) {
814 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
815 if (lri.getVpnInstanceList().contains(vpnInstanceName)) {
816 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, true);
817 localNextHopIP = lri.getPrefix();
819 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, false);
820 localNextHopIP = lri.getPrefix();
823 if (localNextHopInfo != null) {
824 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
825 label, localNextHopInfo.getVpnInterfaceName(), lri.getDpnId());
826 if (vpnExtraRoutes == null || vpnExtraRoutes.isEmpty()) {
827 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP,
828 vpnId, rd, vrfEntry, lri.getParentVpnid(), null, vpnExtraRoutes);
829 returnLocalDpnId.add(dpnId);
831 for (Routes extraRoutes : vpnExtraRoutes) {
832 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo,
834 vpnId, rd, vrfEntry, lri.getParentVpnid(),
835 extraRoutes, vpnExtraRoutes);
836 returnLocalDpnId.add(dpnId);
845 if (returnLocalDpnId.isEmpty()) {
846 LOG.error("Local DPNID is empty for rd {}, vpnId {}, vrfEntry {}", rd, vpnId, vrfEntry);
849 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId,
850 rd, vrfEntry, vpnId, /*routes*/ null, /*vpnExtraRoutes*/ null);
851 returnLocalDpnId.add(dpnId);
853 return returnLocalDpnId;
856 private BigInteger checkCreateLocalFibEntry(Prefixes localNextHopInfo, String localNextHopIP,
857 final Long vpnId, final String rd,
858 final VrfEntry vrfEntry, Long parentVpnId,
859 Routes routes, List<Routes> vpnExtraRoutes) {
860 String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnId);
861 if (localNextHopInfo != null) {
864 final BigInteger dpnId = localNextHopInfo.getDpnId();
865 if (Boolean.TRUE.equals(localNextHopInfo.isNatPrefix())) {
866 LOG.debug("NAT Prefix {} with vpnId {} rd {}. Skip local dpn {} FIB processing",
867 vrfEntry.getDestPrefix(), vpnId, rd, dpnId);
870 String jobKey = FibUtil.getCreateLocalNextHopJobKey(vpnId, dpnId, vrfEntry.getDestPrefix());
871 if (routes != null) {
872 groupId = nextHopManager.createNextHopGroups(parentVpnId, rd, dpnId, vrfEntry, routes,
874 localGroupId = nextHopManager.getLocalNextHopGroup(parentVpnId,
875 routes.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX);
877 groupId = nextHopManager.createLocalNextHop(parentVpnId, dpnId,
878 localNextHopInfo.getVpnInterfaceName(), localNextHopIP, vrfEntry.getDestPrefix(),
879 vrfEntry.getGatewayMacAddress(), jobKey);
880 localGroupId = groupId;
882 if (groupId == FibConstants.INVALID_GROUP_ID) {
883 LOG.error("Unable to create Group for local prefix {} on rd {} for vpninterface {} on Node {}",
884 vrfEntry.getDestPrefix(), rd, localNextHopInfo.getVpnInterfaceName(), dpnId.toString());
885 return BigInteger.ZERO;
887 final List<InstructionInfo> instructions = Collections.singletonList(
888 new InstructionApplyActions(
889 Collections.singletonList(new ActionGroup(groupId))));
890 final List<InstructionInfo> lfibinstructions = Collections.singletonList(
891 new InstructionApplyActions(
892 Arrays.asList(new ActionPopMpls(), new ActionGroup(groupId))));
893 java.util.Optional<Long> optLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
894 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
895 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
896 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
897 dpnId, localNextHopInfo.getVpnInterfaceName(), optLabel);
899 LOG.debug("Route with rd {} prefix {} label {} nexthop {} for vpn {} is an imported route. "
900 + "LFib and Terminating table entries will not be created.",
901 rd, vrfEntry.getDestPrefix(), optLabel, nextHopAddressList, vpnId);
903 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
905 dataStoreCoordinator.enqueueJob(jobKey,
907 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
908 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
909 optLabel.ifPresent(label -> {
910 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
911 makeLFibTableEntry(dpnId, label, lfibinstructions,
912 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
913 makeTunnelTableEntry(dpnId, label, localGroupId, tx);
917 List<ListenableFuture<Void>> futures = new ArrayList<>();
918 futures.add(tx.submit());
923 LOG.error("localNextHopInfo received is null for prefix {} on rd {} on vpn {}",
924 vrfEntry.getDestPrefix(), rd, vpnName);
925 return BigInteger.ZERO;
928 private boolean isVpnPresentInDpn(String rd, BigInteger dpnId) {
929 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
930 return FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id).isPresent();
933 private LabelRouteInfo getLabelRouteInfo(Long label) {
934 InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
935 .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build();
936 Optional<LabelRouteInfo> opResult = read(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid);
937 if (opResult.isPresent()) {
938 return opResult.get();
943 private boolean deleteLabelRouteInfo(LabelRouteInfo lri, String vpnInstanceName, WriteTransaction tx) {
944 LOG.debug("deleting LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
945 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
946 .child(LabelRouteInfo.class, new LabelRouteInfoKey(lri.getLabel())).build();
950 List<String> vpnInstancesList = lri.getVpnInstanceList() != null
951 ? lri.getVpnInstanceList() : new ArrayList<>();
952 if (vpnInstancesList.contains(vpnInstanceName)) {
953 LOG.debug("vpninstance {} name is present", vpnInstanceName);
954 vpnInstancesList.remove(vpnInstanceName);
956 if (vpnInstancesList.size() == 0) {
957 LOG.debug("deleting LRI instance object for label {}", lri.getLabel());
959 tx.delete(LogicalDatastoreType.OPERATIONAL, lriId);
961 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId);
965 LOG.debug("updating LRI instance object for label {}", lri.getLabel());
966 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri).setVpnInstanceList(vpnInstancesList);
967 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(),
968 FibUtil.DEFAULT_CALLBACK);
973 void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/,
974 WriteTransaction tx) {
975 List<ActionInfo> actionsInfos = Collections.singletonList(new ActionGroup(groupId));
977 createTerminatingServiceActions(dpId, (int) label, actionsInfos, tx);
979 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully",
980 dpId, label, groupId);
983 public void createTerminatingServiceActions(BigInteger destDpId, int label, List<ActionInfo> actionsInfos,
984 WriteTransaction tx) {
985 List<MatchInfo> mkMatches = new ArrayList<>();
987 LOG.debug("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}",
988 destDpId, label, actionsInfos);
991 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
992 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(label)));
994 List<InstructionInfo> mkInstructions = new ArrayList<>();
995 mkInstructions.add(new InstructionApplyActions(actionsInfos));
997 FlowEntity terminatingServiceTableFlowEntity =
998 MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
999 getTableMissFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE, label), 5,
1000 String.format("%s:%d", "TST Flow Entry ", label),
1001 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, mkInstructions);
1003 FlowKey flowKey = new FlowKey(new FlowId(terminatingServiceTableFlowEntity.getFlowId()));
1005 FlowBuilder flowbld = terminatingServiceTableFlowEntity.getFlowBuilder();
1007 Node nodeDpn = buildDpnNode(terminatingServiceTableFlowEntity.getDpnId());
1008 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1009 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1010 .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId()))
1011 .child(Flow.class, flowKey).build();
1012 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flowbld.build(), true);
1015 private void removeTunnelTableEntry(BigInteger dpId, long label, WriteTransaction tx) {
1016 FlowEntity flowEntity;
1017 LOG.debug("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId, label);
1018 List<MatchInfo> mkMatches = new ArrayList<>();
1019 // Matching metadata
1020 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(label)));
1021 flowEntity = MDSALUtil.buildFlowEntity(dpId,
1022 NwConstants.INTERNAL_TUNNEL_TABLE,
1023 getTableMissFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int) label),
1024 5, String.format("%s:%d", "TST Flow Entry ", label), 0, 0,
1025 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
1026 Node nodeDpn = buildDpnNode(flowEntity.getDpnId());
1027 FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getFlowId()));
1028 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1029 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1030 .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build();
1032 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1033 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully", dpId, label);
1036 public List<BigInteger> deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
1037 List<BigInteger> returnLocalDpnId = new ArrayList<>();
1038 Prefixes localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
1039 String localNextHopIP = vrfEntry.getDestPrefix();
1040 String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnId);
1042 if (localNextHopInfo == null) {
1043 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
1044 if (usedRds.size() > 1) {
1045 LOG.error("The extra route prefix {} is still present in some DPNs in vpn {} on rd {}",
1046 vrfEntry.getDestPrefix(), vpnName, rd);
1047 return returnLocalDpnId;
1049 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency
1051 Optional<Routes> extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker,
1052 vpnName, rd, vrfEntry.getDestPrefix());
1053 if (extraRouteOptional.isPresent()) {
1054 Routes extraRoute = extraRouteOptional.get();
1055 localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId,
1056 extraRoute.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX);
1057 if (localNextHopInfo != null) {
1058 BigInteger dpnId = localNextHopInfo.getDpnId();
1059 if (!dpnId.equals(BigInteger.ZERO)) {
1060 nextHopManager.setupLoadBalancingNextHop(vpnId, dpnId,
1061 vrfEntry.getDestPrefix(), /*listBucketInfo*/ null, /*remove*/ false);
1062 returnLocalDpnId.add(dpnId);
1067 if (localNextHopInfo == null) {
1068 /* Imported VRF entry */
1069 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1070 if (optionalLabel.isPresent()) {
1071 Long label = optionalLabel.get();
1072 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
1073 LabelRouteInfo lri = getLabelRouteInfo(label);
1074 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
1075 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
1076 prefixBuilder.setDpnId(lri.getDpnId());
1077 BigInteger dpnId = checkDeleteLocalFibEntry(prefixBuilder.build(), localNextHopIP,
1078 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
1079 if (!dpnId.equals(BigInteger.ZERO)) {
1080 returnLocalDpnId.add(dpnId);
1087 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
1088 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
1089 if (!dpnId.equals(BigInteger.ZERO)) {
1090 returnLocalDpnId.add(dpnId);
1094 return returnLocalDpnId;
1097 private BigInteger checkDeleteLocalFibEntry(Prefixes localNextHopInfo, final String localNextHopIP,
1098 final Long vpnId, final String rd,
1099 final VrfEntry vrfEntry, final boolean isExtraRoute) {
1100 if (localNextHopInfo != null) {
1101 final BigInteger dpnId = localNextHopInfo.getDpnId();
1102 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1103 dataStoreCoordinator.enqueueJob("FIB-" + vpnId.toString() + "-"
1104 + dpnId.toString() + "-" + vrfEntry.getDestPrefix(),
1106 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1107 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null /* instructions */,
1108 NwConstants.DEL_FLOW, tx);
1109 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1110 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
1111 makeLFibTableEntry(dpnId, label, null /* instructions */,
1112 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1113 removeTunnelTableEntry(dpnId, label, tx);
1116 List<ListenableFuture<Void>> futures = new ArrayList<>();
1117 futures.add(tx.submit());
1120 //TODO: verify below adjacency call need to be optimized (?)
1121 deleteLocalAdjacency(dpnId, vpnId, localNextHopIP, vrfEntry.getDestPrefix());
1124 return BigInteger.ZERO;
1127 static InstanceIdentifier<Routes> getVpnToExtrarouteIdentifier(String vpnName, String vrfId,
1129 return InstanceIdentifier.builder(VpnToExtraroutes.class)
1130 .child(Vpn.class, new VpnKey(vpnName)).child(ExtraRoutes.class,
1131 new ExtraRoutesKey(vrfId)).child(Routes.class, new RoutesKey(ipPrefix)).build();
1134 public Routes getVpnToExtraroute(String vpnRd, String destPrefix) {
1135 Optional<String> optVpnName = FibUtil.getVpnNameFromRd(dataBroker, vpnRd);
1136 if (optVpnName.isPresent()) {
1137 InstanceIdentifier<Routes> vpnExtraRoutesId = getVpnToExtrarouteIdentifier(
1138 optVpnName.get(), vpnRd, destPrefix);
1139 return FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, vpnExtraRoutesId).orNull();
1144 private void createRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, final VrfTablesKey vrfTableKey,
1145 final VrfEntry vrfEntry, WriteTransaction tx) {
1146 Boolean wrTxPresent = true;
1148 wrTxPresent = false;
1149 tx = dataBroker.newWriteOnlyTransaction();
1151 String rd = vrfTableKey.getRouteDistinguisher();
1152 String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnId);
1153 LOG.debug("createremotefibentry: adding route {} for rd {} on remoteDpnId {}",
1154 vrfEntry.getDestPrefix(), rd, remoteDpnId);
1156 List<AdjacencyResult> adjacencyResults = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
1157 if (adjacencyResults == null || adjacencyResults.isEmpty()) {
1158 LOG.error("Could not get interface for route-paths: {} in vpn {}",
1159 vrfEntry.getRoutePaths(), rd);
1160 LOG.warn("Failed to add Route: {} in vpn: {}",
1161 vrfEntry.getDestPrefix(), rd);
1164 if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
1165 programRemoteFibForBgpRoutes(remoteDpnId, vpnId, vrfEntry, tx, rd, adjacencyResults);
1167 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
1168 List<Routes> vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker,
1169 vpnName, usedRds, vrfEntry.getDestPrefix());
1170 if (!vpnExtraRoutes.isEmpty()) {
1171 List<InstructionInfo> instructions = new ArrayList<>();
1172 long groupId = nextHopManager.createNextHopGroups(vpnId, rd, remoteDpnId, vrfEntry,
1173 null, vpnExtraRoutes);
1174 if (groupId == FibConstants.INVALID_GROUP_ID) {
1175 LOG.error("Unable to create Group for local prefix {} on rd {} on Node {}",
1176 vrfEntry.getDestPrefix(), rd, remoteDpnId.toString());
1179 List<ActionInfo> actionInfos =
1180 Collections.singletonList(new ActionGroup(groupId));
1181 instructions.add(new InstructionApplyActions(actionInfos));
1182 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
1184 programRemoteFib(remoteDpnId, vpnId, vrfEntry, tx, rd, adjacencyResults);
1190 LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
1193 private void programRemoteFib(final BigInteger remoteDpnId, final long vpnId,
1194 final VrfEntry vrfEntry, WriteTransaction tx, String rd, List<AdjacencyResult> adjacencyResults) {
1195 List<InstructionInfo> instructions = new ArrayList<>();
1196 for (AdjacencyResult adjacencyResult : adjacencyResults) {
1197 List<ActionInfo> actionInfos = new ArrayList<>();
1198 String egressInterface = adjacencyResult.getInterfaceName();
1199 if (FibUtil.isTunnelInterface(adjacencyResult)) {
1200 addTunnelInterfaceActions(adjacencyResult, vpnId, vrfEntry, actionInfos);
1202 addRewriteDstMacAction(vpnId, vrfEntry, actionInfos);
1204 List<ActionInfo> egressActions = nextHopManager.getEgressActionsForInterface(egressInterface,
1205 actionInfos.size());
1206 if (egressActions.isEmpty()) {
1208 "Failed to retrieve egress action for prefix {} route-paths {} interface {}. "
1209 + "Aborting remote FIB entry creation.",
1210 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(), egressInterface);
1213 actionInfos.addAll(egressActions);
1214 instructions.add(new InstructionApplyActions(actionInfos));
1216 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
1219 private void addRewriteDstMacAction(long vpnId, VrfEntry vrfEntry, List<ActionInfo> actionInfos) {
1220 if (vrfEntry.getMac() != null) {
1221 actionInfos.add(new ActionSetFieldEthernetDestination(actionInfos.size(),
1222 new MacAddress(vrfEntry.getMac())));
1226 String ipPrefix = vrfEntry.getDestPrefix();
1227 Prefixes prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, ipPrefix);
1228 if (prefixInfo == null) {
1229 LOG.debug("No prefix info found for prefix {}", ipPrefix);
1233 String ifName = prefixInfo.getVpnInterfaceName();
1234 if (ifName == null) {
1235 LOG.warn("Failed to get VPN interface for prefix {}", ipPrefix);
1239 String macAddress = FibUtil.getMacAddressFromPrefix(dataBroker, ifName, ipPrefix);
1240 if (macAddress == null) {
1241 LOG.warn("No MAC address found for VPN interface {} prefix {}", ifName, ipPrefix);
1245 actionInfos.add(new ActionSetFieldEthernetDestination(actionInfos.size(), new MacAddress(macAddress)));
1248 private void addTunnelInterfaceActions(AdjacencyResult adjacencyResult, long vpnId, VrfEntry vrfEntry,
1249 List<ActionInfo> actionInfos) {
1250 Class<? extends TunnelTypeBase> tunnelType = VpnExtraRouteHelper.getTunnelType(interfaceManager,
1251 adjacencyResult.getInterfaceName());
1252 // TODO - For now have added routePath into adjacencyResult so that we know for which
1253 // routePath this result is built for. If this is not possible construct a map which does
1255 String nextHopIp = adjacencyResult.getNextHopIp();
1256 java.util.Optional<Long> optionalLabel = FibUtil.getLabelForNextHop(vrfEntry, nextHopIp);
1257 if (!optionalLabel.isPresent()) {
1258 LOG.warn("NextHopIp {} not found in vrfEntry {}", nextHopIp, vrfEntry);
1261 long label = optionalLabel.get();
1262 if (tunnelType.equals(TunnelTypeMplsOverGre.class)) {
1263 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
1264 actionInfos.add(new ActionPushMpls());
1265 actionInfos.add(new ActionSetFieldMplsLabel(label));
1266 actionInfos.add(new ActionNxLoadInPort(BigInteger.ZERO));
1268 BigInteger tunnelId;
1269 // FIXME vxlan vni bit set is not working properly with OVS.need to
1271 if (tunnelType.equals(TunnelTypeVxlan.class)) {
1272 tunnelId = BigInteger.valueOf(label);
1274 tunnelId = BigInteger.valueOf(label);
1277 LOG.debug("adding set tunnel id action for label {}", label);
1278 actionInfos.add(new ActionSetFieldTunnelId(tunnelId));
1279 addRewriteDstMacAction(vpnId, vrfEntry, actionInfos);
1283 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
1284 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
1285 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1286 if (dpnInVpn.isPresent()) {
1287 List<VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
1288 VpnInterfaces currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
1290 if (vpnInterfaces.remove(currVpnInterface)) {
1291 if (vpnInterfaces.isEmpty()) {
1292 LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
1293 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1294 cleanUpDpnForVpn(dpnId, vpnId, rd, null);
1296 LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
1297 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id.child(
1298 VpnInterfaces.class,
1299 new VpnInterfacesKey(intfName)));
1305 void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
1306 /* Get interface info from prefix to interface mapping;
1307 Use the interface info to get the corresponding vpn interface op DS entry,
1308 remove the adjacency corresponding to this fib entry.
1309 If adjacency removed is the last adjacency, clean up the following:
1310 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
1311 - prefix to interface entry
1312 - vpn interface op DS
1314 LOG.debug("Cleanup of prefix {} in VPN {}", vrfEntry.getDestPrefix(), vpnId);
1315 Prefixes prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
1316 Routes extraRoute = null;
1317 if (prefixInfo == null) {
1318 extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1319 if (extraRoute != null) {
1320 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1321 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
1322 if (nextHopIp != null) {
1323 prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, nextHopIp
1324 + NwConstants.IPV4PREFIX);
1325 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1329 if (prefixInfo == null) {
1330 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1331 if (optionalLabel.isPresent()) {
1332 Long label = optionalLabel.get();
1333 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
1334 LabelRouteInfo lri = getLabelRouteInfo(label);
1335 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
1336 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
1337 prefixBuilder.setDpnId(lri.getDpnId());
1338 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
1339 prefixBuilder.setIpAddress(lri.getPrefix());
1340 prefixInfo = prefixBuilder.build();
1341 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
1342 label, prefixInfo.getVpnInterfaceName(), lri.getDpnId());
1343 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1348 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1352 private void checkCleanUpOpDataForFib(final Prefixes prefixInfo, final Long vpnId, final String rd,
1353 final VrfEntry vrfEntry, final Routes extraRoute) {
1355 if (prefixInfo == null) {
1356 LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for prefix {}", vrfEntry.getDestPrefix());
1357 return; //Don't have any info for this prefix (shouldn't happen); need to return
1360 if (Boolean.TRUE.equals(prefixInfo.isNatPrefix())) {
1361 LOG.debug("NAT Prefix {} with vpnId {} rd {}. Skip FIB processing",
1362 vrfEntry.getDestPrefix(), vpnId, rd);
1366 String ifName = prefixInfo.getVpnInterfaceName();
1367 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1368 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + ifName,
1369 new CleanupVpnInterfaceWorker(prefixInfo, vpnId, rd, vrfEntry, extraRoute));
1372 private class CleanupVpnInterfaceWorker implements Callable<List<ListenableFuture<Void>>> {
1373 Prefixes prefixInfo;
1379 CleanupVpnInterfaceWorker(final Prefixes prefixInfo, final Long vpnId, final String rd,
1380 final VrfEntry vrfEntry, final Routes extraRoute) {
1381 this.prefixInfo = prefixInfo;
1384 this.vrfEntry = vrfEntry;
1385 this.extraRoute = extraRoute;
1389 public List<ListenableFuture<Void>> call() throws Exception {
1390 // If another renderer(for eg : CSS) needs to be supported, check can be performed here
1391 // to call the respective helpers.
1392 WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
1394 //First Cleanup LabelRouteInfo
1395 //TODO(KIRAN) : Move the below block when addressing iRT/eRT for L3VPN Over VxLan
1396 if (vrfEntry.getEncapType().equals(VrfEntry.EncapType.Mplsgre)) {
1397 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
1398 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
1399 synchronized (label.toString().intern()) {
1400 LabelRouteInfo lri = getLabelRouteInfo(label);
1401 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
1402 && nextHopAddressList.contains(lri.getNextHopIpList().get(0))) {
1403 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
1404 FibUtil.getVpnInstanceOpData(dataBroker, rd);
1405 String vpnInstanceName = "";
1406 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1407 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1409 boolean lriRemoved = deleteLabelRouteInfo(lri, vpnInstanceName, writeOperTxn);
1411 String parentRd = lri.getParentVpnRd();
1412 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1413 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1416 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1417 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1422 String ifName = prefixInfo.getVpnInterfaceName();
1423 Optional<VpnInterface> optvpnInterface = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1424 FibUtil.getVpnInterfaceIdentifier(ifName));
1425 if (optvpnInterface.isPresent()) {
1426 long associatedVpnId = FibUtil.getVpnId(dataBroker, optvpnInterface.get().getVpnInstanceName());
1427 if (vpnId != associatedVpnId) {
1428 LOG.warn("Prefixes {} are associated with different vpn instance with id : {} rather than {}",
1429 vrfEntry.getDestPrefix(), associatedVpnId, vpnId);
1430 LOG.warn("Not proceeding with Cleanup op data for prefix {}", vrfEntry.getDestPrefix());
1433 LOG.debug("Processing cleanup of prefix {} associated with vpn {}",
1434 vrfEntry.getDestPrefix(), associatedVpnId);
1437 if (extraRoute != null) {
1438 Optional<String> optVpnName = FibUtil.getVpnNameFromRd(dataBroker, rd);
1439 if (optVpnName.isPresent()) {
1440 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
1441 getVpnToExtrarouteIdentifier(optVpnName.get(), rd, vrfEntry.getDestPrefix()));
1444 Optional<Adjacencies> optAdjacencies = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1445 FibUtil.getAdjListPath(ifName));
1447 if (optAdjacencies.isPresent()) {
1448 numAdj = optAdjacencies.get().getAdjacency().size();
1450 //remove adjacency corr to prefix
1452 LOG.info("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId,
1453 vrfEntry.getDestPrefix());
1454 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
1455 FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
1457 //this is last adjacency (or) no more adjacency left for this vpn interface, so
1458 //clean up the vpn interface from DpnToVpn list
1459 LOG.info("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
1460 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnInterfaceIdentifier(ifName));
1462 List<ListenableFuture<Void>> futures = new ArrayList<>();
1463 futures.add(writeOperTxn.submit());
1468 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1469 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1470 final String rd = vrfTableKey.getRouteDistinguisher();
1471 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1472 if (vpnInstance == null) {
1473 LOG.error("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1476 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1478 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1479 final java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1480 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
1481 String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnInstance.getVpnId());
1482 if (subnetRoute != null) {
1483 elanTag = subnetRoute.getElantag();
1484 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
1485 rd, vrfEntry.getDestPrefix(), elanTag);
1486 if (vpnToDpnList != null) {
1487 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1488 dataStoreCoordinator.enqueueJob("FIB-" + rd + "-" + vrfEntry.getDestPrefix(),
1490 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1492 for (final VpnToDpnList curDpn : vpnToDpnList) {
1494 makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry,
1495 vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW, tx);
1496 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1497 optionalLabel.ifPresent(label -> {
1498 makeLFibTableEntry(curDpn.getDpnId(), label, null,
1499 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1503 List<ListenableFuture<Void>> futures = new ArrayList<>();
1504 futures.add(tx.submit());
1508 optionalLabel.ifPresent(label -> {
1509 synchronized (label.toString().intern()) {
1510 LabelRouteInfo lri = getLabelRouteInfo(label);
1511 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
1512 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
1513 FibUtil.getVpnInstanceOpData(dataBroker, rd);
1514 String vpnInstanceName = "";
1515 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1516 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1518 boolean lriRemoved = this.deleteLabelRouteInfo(lri, vpnInstanceName, null);
1520 String parentRd = lri.getParentVpnRd();
1521 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1522 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1523 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {} as "
1524 + "labelRouteInfo cleared", label, rd,
1525 vrfEntry.getDestPrefix());
1528 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1529 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1530 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {}",
1531 label, rd, vrfEntry.getDestPrefix());
1537 if (installRouterFibEntries(vrfEntry, vpnToDpnList, vpnInstance.getVpnId(), NwConstants.DEL_FLOW)) {
1541 final List<BigInteger> localDpnIdList = deleteLocalFibEntry(vpnInstance.getVpnId(),
1542 vrfTableKey.getRouteDistinguisher(), vrfEntry);
1543 if (vpnToDpnList != null) {
1544 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker,
1545 vpnInstance.getVpnId(), vrfEntry.getDestPrefix());
1546 String usedRd = null;
1547 Optional<Routes> extraRouteOptional;
1548 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
1549 if (usedRds != null && !usedRds.isEmpty()) {
1550 if (usedRds.size() > 1) {
1551 LOG.error("The extra route prefix is still present in some DPNs");
1554 // The first rd is retrieved from usedrds as Only 1 rd would be present as extra route prefix
1555 //is not present in any other DPN
1556 extraRouteOptional = VpnExtraRouteHelper
1557 .getVpnExtraroutes(dataBroker, vpnName, usedRds.get(0), vrfEntry.getDestPrefix());
1560 extraRouteOptional = Optional.absent();
1562 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1563 dataStoreCoordinator.enqueueJob("FIB-" + usedRd + "-" + vrfEntry.getDestPrefix(),
1565 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1567 if (localDpnIdList.size() <= 0) {
1568 for (VpnToDpnList curDpn : vpnToDpnList) {
1569 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1570 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1571 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(),
1572 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, tx);
1575 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(),
1576 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, tx);
1580 for (BigInteger localDpnId : localDpnIdList) {
1581 for (VpnToDpnList curDpn : vpnToDpnList) {
1582 if (!curDpn.getDpnId().equals(localDpnId)) {
1583 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1584 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1585 deleteRemoteRoute(localDpnId, curDpn.getDpnId(),
1586 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, tx);
1589 deleteRemoteRoute(localDpnId, curDpn.getDpnId(),
1590 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, tx);
1596 List<ListenableFuture<Void>> futures = new ArrayList<>();
1597 futures.add(tx.submit());
1602 //The flow/group entry has been deleted from config DS; need to clean up associated operational
1603 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
1604 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
1606 // Remove all fib entries configured due to interVpnLink, when nexthop is the opposite endPoint
1607 // of the interVpnLink.
1608 Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(this.dataBroker, rd);
1609 if (optVpnUuid.isPresent()) {
1610 String vpnUuid = optVpnUuid.get();
1611 FibUtil.getFirstNextHopAddress(vrfEntry).ifPresent(routeNexthop -> {
1612 Optional<InterVpnLinkDataComposite> optInterVpnLink =
1613 InterVpnLinkCache.getInterVpnLinkByVpnId(vpnUuid);
1614 if (optInterVpnLink.isPresent()) {
1615 InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
1616 if (interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid)) {
1617 // This is route that points to the other endpoint of an InterVpnLink
1618 // In that case, we should look for the FIB table pointing to
1619 // LPortDispatcher table and remove it.
1620 removeInterVPNLinkRouteFlows(interVpnLink.getInterVpnLinkName(),
1621 interVpnLink.isFirstEndpointVpnName(rd),
1631 Please note that the following deleteFibEntries will be invoked only for BGP Imported Routes.
1632 The invocation of the following method is via delete() callback from the MDSAL Batching Infrastructure
1633 provided by ResourceBatchingManager
1635 private void deleteFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> identifier,
1636 final VrfEntry vrfEntry) {
1637 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1638 String rd = vrfTableKey.getRouteDistinguisher();
1639 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1640 if (vpnInstance == null) {
1641 LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1644 String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnInstance.getVpnId());
1645 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1646 if (vpnToDpnList != null) {
1647 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker,
1648 vpnInstance.getVpnId(), vrfEntry.getDestPrefix());
1649 Optional<Routes> extraRouteOptional;
1650 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
1651 if (usedRds != null && !usedRds.isEmpty()) {
1652 if (usedRds.size() > 1) {
1653 LOG.error("The extra route prefix is still present in some DPNs");
1656 extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, vpnName,
1657 usedRds.get(0), vrfEntry.getDestPrefix());
1660 extraRouteOptional = Optional.absent();
1662 for (VpnToDpnList curDpn : vpnToDpnList) {
1663 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1664 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey,
1665 vrfEntry, extraRouteOptional, writeTx);
1671 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
1672 final long vpnId, final VrfTablesKey vrfTableKey,
1673 final VrfEntry vrfEntry, Optional<Routes> extraRouteOptional, WriteTransaction tx) {
1675 Boolean wrTxPresent = true;
1677 wrTxPresent = false;
1678 tx = dataBroker.newWriteOnlyTransaction();
1681 LOG.debug("deleting remote route: prefix={}, vpnId={} localDpnId {} remoteDpnId {}",
1682 vrfEntry.getDestPrefix(), vpnId, localDpnId, remoteDpnId);
1683 String rd = vrfTableKey.getRouteDistinguisher();
1685 if (localDpnId != null && localDpnId != BigInteger.ZERO) {
1686 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
1687 if (extraRouteOptional.isPresent()) {
1688 nextHopManager.setupLoadBalancingNextHop(vpnId, remoteDpnId, vrfEntry.getDestPrefix(), null , false);
1690 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1694 // below two reads are kept as is, until best way is found to identify dpnID
1695 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
1696 if (extraRouteOptional.isPresent()) {
1697 nextHopManager.setupLoadBalancingNextHop(vpnId, remoteDpnId, vrfEntry.getDestPrefix(), null , false);
1699 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1706 private boolean checkDpnDeleteFibEntry(VpnNexthop localNextHopInfo, BigInteger remoteDpnId, long vpnId,
1707 VrfEntry vrfEntry, String rd, WriteTransaction tx) {
1708 boolean isRemoteRoute = true;
1709 if (localNextHopInfo != null) {
1710 isRemoteRoute = !remoteDpnId.equals(localNextHopInfo.getDpnId());
1712 if (isRemoteRoute) {
1713 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1716 LOG.debug("Did not delete FIB entry: rd={}, vrfEntry={}, as it is local to dpnId={}",
1717 rd, vrfEntry.getDestPrefix(), remoteDpnId);
1722 private void deleteFibEntry(BigInteger remoteDpnId, long vpnId, VrfEntry vrfEntry,
1723 String rd, WriteTransaction tx) {
1724 // When the tunnel is removed the fib entries should be reprogrammed/deleted depending on
1725 // the adjacencyResults.
1726 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1727 List<AdjacencyResult> adjacencyResults = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
1728 if (!adjacencyResults.isEmpty()) {
1729 programRemoteFibForBgpRoutes(remoteDpnId, vpnId, vrfEntry, tx, rd, adjacencyResults);
1733 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1734 LOG.debug("Successfully delete FIB entry: vrfEntry={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
1737 private long get(byte[] rawIpAddress) {
1738 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
1739 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
1742 void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
1743 List<InstructionInfo> instructions, int addOrRemove, WriteTransaction tx) {
1744 Boolean wrTxPresent = true;
1746 wrTxPresent = false;
1747 tx = dataBroker.newWriteOnlyTransaction();
1750 LOG.trace("makeConnectedRoute: vrfEntry {}", vrfEntry);
1751 String[] values = vrfEntry.getDestPrefix().split("/");
1752 String ipAddress = values[0];
1753 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
1754 if (addOrRemove == NwConstants.ADD_FLOW) {
1755 LOG.debug("Adding route to DPN {} for rd {} prefix {} ", dpId, rd, vrfEntry.getDestPrefix());
1757 LOG.debug("Removing route from DPN {} for rd {} prefix {}", dpId, rd, vrfEntry.getDestPrefix());
1759 InetAddress destPrefix;
1761 destPrefix = InetAddress.getByName(ipAddress);
1762 } catch (UnknownHostException e) {
1763 LOG.error("Failed to get destPrefix for prefix {} ", vrfEntry.getDestPrefix(), e);
1767 List<MatchInfo> matches = new ArrayList<>();
1769 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
1771 if (destPrefix instanceof Inet4Address) {
1772 matches.add(MatchEthernetType.IPV4);
1773 if (prefixLength != 0) {
1774 matches.add(new MatchIpv4Destination(destPrefix.getHostAddress(), Integer.toString(prefixLength)));
1777 matches.add(MatchEthernetType.IPV6);
1778 if (prefixLength != 0) {
1779 matches.add(new MatchIpv6Destination(destPrefix.getHostAddress() + "/" + prefixLength));
1783 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
1784 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, priority, destPrefix);
1785 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef, priority,
1787 COOKIE_VM_FIB_TABLE, matches, instructions);
1788 Flow flow = flowEntity.getFlowBuilder().build();
1789 String flowId = flowEntity.getFlowId();
1790 FlowKey flowKey = new FlowKey(new FlowId(flowId));
1791 Node nodeDpn = buildDpnNode(dpId);
1793 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1794 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1795 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1797 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1798 SubTransaction subTransaction = new SubTransactionImpl();
1799 if (addOrRemove == NwConstants.ADD_FLOW) {
1800 subTransaction.setInstanceIdentifier(flowInstanceId);
1801 subTransaction.setInstance(flow);
1802 subTransaction.setAction(SubTransaction.CREATE);
1804 subTransaction.setInstanceIdentifier(flowInstanceId);
1805 subTransaction.setAction(SubTransaction.DELETE);
1807 transactionObjects.add(subTransaction);
1810 if (addOrRemove == NwConstants.ADD_FLOW) {
1811 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
1813 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1821 //TODO: How to handle the below code, its a copy paste from MDSALManager.java
1822 Node buildDpnNode(BigInteger dpnId) {
1823 NodeId nodeId = new NodeId("openflow:" + dpnId);
1824 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
1829 private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions, int priority,
1830 int addOrRemove, WriteTransaction tx) {
1831 Boolean wrTxPresent = true;
1833 wrTxPresent = false;
1834 tx = dataBroker.newWriteOnlyTransaction();
1837 List<MatchInfo> matches = new ArrayList<>();
1838 matches.add(MatchEthernetType.MPLS_UNICAST);
1839 matches.add(new MatchMplsLabel(label));
1841 // Install the flow entry in L3_LFIB_TABLE
1842 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, priority);
1844 FlowEntity flowEntity;
1845 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef, priority, flowRef, 0, 0,
1846 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
1847 Flow flow = flowEntity.getFlowBuilder().build();
1848 String flowId = flowEntity.getFlowId();
1849 FlowKey flowKey = new FlowKey(new FlowId(flowId));
1850 Node nodeDpn = buildDpnNode(dpId);
1851 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1852 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1853 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1855 if (addOrRemove == NwConstants.ADD_FLOW) {
1856 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
1858 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1864 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} : key {} {} successfully",
1865 dpId, label, instructions, flowKey, (NwConstants.ADD_FLOW == addOrRemove) ? "ADDED" : "REMOVED");
1868 void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress,
1869 final String ipPrefixAddress) {
1870 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}", dpId, vpnId, ipAddress);
1872 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress, ipPrefixAddress);
1873 } catch (NullPointerException e) {
1878 public void populateFibOnNewDpn(final BigInteger dpnId, final long vpnId, final String rd,
1879 final FutureCallback<List<Void>> callback) {
1880 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
1881 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1882 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1883 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1884 if (!vrfTable.isPresent()) {
1885 LOG.warn("VRF Table not yet available for RD {}", rd);
1886 if (callback != null) {
1887 List<ListenableFuture<Void>> futures = new ArrayList<>();
1888 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1889 Futures.addCallback(listenableFuture, callback);
1893 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1894 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1896 List<ListenableFuture<Void>> futures = new ArrayList<>();
1897 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1898 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1899 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1900 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1901 if (subnetRoute != null) {
1902 long elanTag = subnetRoute.getElantag();
1903 installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
1906 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
1907 if (routerInt != null) {
1908 LOG.trace("Router augmented vrfentry found rd:{}, uuid:{}, ip:{}, mac:{}",
1909 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
1910 installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(),
1911 routerInt.getIpAddress(),
1912 new MacAddress(routerInt.getMacAddress()), NwConstants.ADD_FLOW);
1915 //Handle local flow creation for imports
1916 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
1917 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1918 if (optionalLabel.isPresent()) {
1919 List<String> nextHopList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
1920 LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get());
1921 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList, lri)) {
1922 if (lri.getDpnId().equals(dpnId)) {
1923 createLocalFibEntry(vpnId, rd, vrfEntry);
1930 boolean shouldCreateRemoteFibEntry = shouldCreateFibEntryForVrfAndVpnIdOnDpn(vpnId,
1932 if (shouldCreateRemoteFibEntry) {
1933 LOG.trace("Will create remote FIB entry for vrfEntry {} on DPN {}",
1935 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1938 //TODO: if we have 100K entries in FIB, can it fit in one Tranasaction (?)
1939 futures.add(tx.submit());
1941 if (callback != null) {
1942 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1943 Futures.addCallback(listenableFuture, callback);
1949 public void populateExternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1950 final String localNextHopIp, final String remoteNextHopIp) {
1951 LOG.trace("populateExternalRoutesOnDpn : dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} ",
1952 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1953 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1954 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1955 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1956 if (vrfTable.isPresent()) {
1957 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1958 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1960 List<ListenableFuture<Void>> futures = new ArrayList<>();
1961 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1962 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
1963 vrfTable.get().getVrfEntry().stream()
1964 .filter(vrfEntry -> RouteOrigin.BGP == RouteOrigin.value(vrfEntry.getOrigin()))
1966 getConsumerForCreatingRemoteFib(dpnId, vpnId,
1967 rd, remoteNextHopIp, vrfTable,
1969 futures.add(writeCfgTxn.submit());
1976 public void populateInternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1977 final String localNextHopIp, final String remoteNextHopIp) {
1978 LOG.trace("populateInternalRoutesOnDpn : dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} ",
1979 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1980 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1981 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1982 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1983 if (vrfTable.isPresent()) {
1984 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1985 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1987 List<ListenableFuture<Void>> futures = new ArrayList<>();
1988 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1989 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
1990 // Handle Vpn Interface driven Routes only (i.e., STATIC and LOCAL)
1991 vrfTable.get().getVrfEntry().stream()
1992 .filter(vrfEntry -> {
1993 /* Ignore SubnetRoute entry */
1994 return (FibHelper.isControllerManagedVpnInterfaceRoute(RouteOrigin.value(
1995 vrfEntry.getOrigin())));
1997 .forEach(getConsumerForCreatingRemoteFib(dpnId, vpnId,
1998 rd, remoteNextHopIp, vrfTable,
2000 futures.add(writeCfgTxn.submit());
2007 public void manageRemoteRouteOnDPN(final boolean action,
2008 final BigInteger localDpnId,
2011 final String destPrefix,
2012 final String destTepIp,
2014 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
2016 if (vpnInstance == null) {
2017 LOG.error("VpnInstance for rd {} not present for prefix {}", rd, destPrefix);
2020 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
2021 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + localDpnId.toString(),
2023 List<ListenableFuture<Void>> futures = new ArrayList<>();
2024 synchronized (vpnInstance.getVpnInstanceName().intern()) {
2025 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
2026 VrfTablesKey vrfTablesKey = new VrfTablesKey(rd);
2027 VrfEntry vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
2028 if (vrfEntry == null) {
2031 LOG.trace("manageRemoteRouteOnDPN :: action {}, DpnId {}, vpnId {}, rd {}, destPfx {}",
2032 action, localDpnId, vpnId, rd, destPrefix);
2033 List<RoutePaths> routePathList = vrfEntry.getRoutePaths();
2034 VrfEntry modVrfEntry;
2035 if (routePathList == null || (routePathList.isEmpty())) {
2036 modVrfEntry = FibHelper.getVrfEntryBuilder(vrfEntry, label,
2037 Collections.singletonList(destTepIp),
2038 RouteOrigin.value(vrfEntry.getOrigin()))
2041 modVrfEntry = vrfEntry;
2044 if (action == true) {
2045 LOG.trace("manageRemoteRouteOnDPN updated(add) vrfEntry :: {}", modVrfEntry);
2046 createRemoteFibEntry(localDpnId, vpnId, vrfTablesKey, modVrfEntry, writeTransaction);
2048 LOG.trace("manageRemoteRouteOnDPN updated(remove) vrfEntry :: {}", modVrfEntry);
2049 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnInstance.getVpnId(),
2050 vrfEntry.getDestPrefix());
2051 if (usedRds.size() > 1) {
2052 LOG.debug("The extra route prefix is still present in some DPNs");
2055 //Is this fib route an extra route? If yes, get the nexthop which would be
2056 //an adjacency in the vpn
2057 Optional<Routes> extraRouteOptional = Optional.absent();
2058 if (usedRds.size() != 0) {
2059 extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker,
2060 FibUtil.getVpnNameFromId(dataBroker, vpnInstance.getVpnId()),
2061 usedRds.get(0), vrfEntry.getDestPrefix());
2063 deleteRemoteRoute(null, localDpnId, vpnId, vrfTablesKey, modVrfEntry,
2064 extraRouteOptional, writeTransaction);
2066 futures.add(writeTransaction.submit());
2072 public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd,
2073 final FutureCallback<List<Void>> callback) {
2074 LOG.trace("cleanUpDpnForVpn: Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
2075 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
2076 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
2077 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2078 if (vrfTable.isPresent()) {
2079 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
2080 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
2082 List<ListenableFuture<Void>> futures = new ArrayList<>();
2083 synchronized (vpnInstance.getVpnInstanceName().intern()) {
2084 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
2085 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
2086 /* Handle subnet routes here */
2087 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
2088 if (subnetRoute != null) {
2089 LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn",
2090 vrfEntry.getDestPrefix(),
2092 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
2093 java.util.Optional.ofNullable(vrfEntry.getRoutePaths()).ifPresent(routePaths -> {
2094 routePaths.stream().forEach(routePath -> {
2095 makeLFibTableEntry(dpnId, routePath.getLabel(), null,
2096 DEFAULT_FIB_FLOW_PRIORITY,
2097 NwConstants.DEL_FLOW, tx);
2098 LOG.trace("cleanUpDpnForVpn: Released subnetroute label {} "
2099 + "for rd {} prefix {}",
2100 routePath.getLabel(), rd,
2101 vrfEntry.getDestPrefix());
2106 // ping responder for router interfaces
2107 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
2108 if (routerInt != null) {
2109 LOG.trace("Router augmented vrfentry found for rd:{}, uuid:{}, ip:{}, mac:{}",
2110 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
2111 installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(),
2112 routerInt.getIpAddress(),
2113 new MacAddress(routerInt.getMacAddress()), NwConstants.DEL_FLOW);
2116 // Passing null as we don't know the dpn
2117 // to which prefix is attached at this point
2118 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnInstance.getVpnId(),
2119 vrfEntry.getDestPrefix());
2120 String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnInstance.getVpnId());
2121 Optional<Routes> extraRouteOptional;
2122 //Is this fib route an extra route? If yes, get the nexthop which would be
2123 //an adjacency in the vpn
2124 if (usedRds != null && !usedRds.isEmpty()) {
2125 if (usedRds.size() > 1) {
2126 LOG.error("The extra route prefix is still present in some DPNs");
2129 extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, vpnName,
2130 usedRds.get(0), vrfEntry.getDestPrefix());
2134 extraRouteOptional = Optional.absent();
2136 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry,
2137 extraRouteOptional, tx);
2139 futures.add(tx.submit());
2140 if (callback != null) {
2141 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
2142 Futures.addCallback(listenableFuture, callback);
2150 public void cleanUpExternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
2151 final String localNextHopIp, final String remoteNextHopIp) {
2152 LOG.trace("cleanUpExternalRoutesOnDpn : cleanup remote routes on dpn {} for vpn {}, rd {}, "
2153 + " localNexthopIp {} , remoteNexhtHopIp {}",
2154 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
2155 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
2156 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
2157 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2158 if (vrfTable.isPresent()) {
2159 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
2160 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
2162 List<ListenableFuture<Void>> futures = new ArrayList<>();
2163 synchronized (vpnInstance.getVpnInstanceName().intern()) {
2164 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
2165 vrfTable.get().getVrfEntry().stream()
2166 .filter(vrfEntry -> RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP)
2167 .forEach(getConsumerForDeletingRemoteFib(dpnId, vpnId, rd,
2168 remoteNextHopIp, vrfTable, writeCfgTxn));
2169 futures.add(writeCfgTxn.submit());
2176 public void cleanUpInternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
2177 final String localNextHopIp, final String remoteNextHopIp) {
2178 LOG.trace("cleanUpInternalRoutesOnDpn : cleanup remote routes on dpn {} for vpn {}, rd {}, "
2179 + " localNexthopIp {} , remoteNexhtHopIp {}",
2180 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
2181 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
2182 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
2183 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2184 if (vrfTable.isPresent()) {
2185 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
2186 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
2188 List<ListenableFuture<Void>> futures = new ArrayList<>();
2189 synchronized (vpnInstance.getVpnInstanceName().intern()) {
2190 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
2191 vrfTable.get().getVrfEntry().stream()
2192 .filter(vrfEntry -> {
2193 /* Ignore SubnetRoute entry */
2194 return (FibHelper.isControllerManagedVpnInterfaceRoute(
2195 RouteOrigin.value(vrfEntry.getOrigin())));
2197 .forEach(getConsumerForDeletingRemoteFib(dpnId, vpnId,
2198 rd, remoteNextHopIp, vrfTable, writeCfgTxn));
2199 futures.add(writeCfgTxn.submit());
2206 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
2207 InstanceIdentifierBuilder<VrfTables> idBuilder =
2208 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
2209 InstanceIdentifier<VrfTables> id = idBuilder.build();
2213 private String getFlowRef(BigInteger dpnId, short tableId, long label, int priority) {
2214 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + label
2215 + NwConstants.FLOWID_SEPARATOR + priority;
2218 private String getFlowRef(BigInteger dpnId, short tableId, String rd, int priority, InetAddress destPrefix) {
2219 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + rd
2220 + NwConstants.FLOWID_SEPARATOR + priority + NwConstants.FLOWID_SEPARATOR + destPrefix.getHostAddress();
2223 private String getInterVpnFibFlowRef(String interVpnLinkName, String prefix, String nextHop) {
2224 return FLOWID_PREFIX + interVpnLinkName + NwConstants.FLOWID_SEPARATOR + prefix + NwConstants
2225 .FLOWID_SEPARATOR + nextHop;
2228 protected List<AdjacencyResult> resolveAdjacency(final BigInteger remoteDpnId, final long vpnId,
2229 final VrfEntry vrfEntry, String rd) {
2230 List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
2231 FibHelper.sortIpAddress(routePaths);
2232 List<AdjacencyResult> adjacencyList = new ArrayList<>();
2233 List<String> prefixIpList = new ArrayList<>();
2234 LOG.trace("resolveAdjacency called with remotedDpnId {}, vpnId{}, VrfEntry {}",
2235 remoteDpnId, vpnId, vrfEntry);
2237 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
2238 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
2239 List<Routes> vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker,
2240 FibUtil.getVpnNameFromId(dataBroker, vpnId), usedRds, vrfEntry.getDestPrefix());
2241 if (vpnExtraRoutes.isEmpty()) {
2242 prefixIpList = Collections.singletonList(vrfEntry.getDestPrefix());
2244 List<String> prefixIpListLocal = new ArrayList<>();
2245 vpnExtraRoutes.stream().forEach(route -> {
2246 route.getNexthopIpList().stream().forEach(extraRouteIp -> {
2247 prefixIpListLocal.add(extraRouteIp + NwConstants.IPV4PREFIX);
2250 prefixIpList = prefixIpListLocal;
2253 prefixIpList = Collections.singletonList(vrfEntry.getDestPrefix());
2256 for (String prefixIp : prefixIpList) {
2257 if (routePaths == null || routePaths.isEmpty()) {
2258 LOG.trace("Processing Destination IP {} without NextHop IP", prefixIp);
2259 AdjacencyResult adjacencyResult = nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId,
2261 addAdjacencyResultToList(adjacencyList, adjacencyResult);
2264 adjacencyList.addAll(routePaths.stream()
2266 LOG.debug("NextHop IP for destination {} is {}", prefixIp,
2267 routePath.getNexthopAddress());
2268 return nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId,
2269 prefixIp, routePath.getNexthopAddress());
2271 .filter(adjacencyResult -> adjacencyResult != null && !adjacencyList.contains(adjacencyResult))
2273 .collect(toList()));
2275 } catch (NullPointerException e) {
2278 return adjacencyList;
2281 private void addAdjacencyResultToList(List<AdjacencyResult> adjacencyList, AdjacencyResult adjacencyResult) {
2282 if (adjacencyResult != null && !adjacencyList.contains(adjacencyResult)) {
2283 adjacencyList.add(adjacencyResult);
2287 protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
2288 InstanceIdentifier<VpnInstanceOpDataEntry> id =
2289 InstanceIdentifier.create(VpnInstanceOpData.class)
2290 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
2291 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData =
2292 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
2293 return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null;
2296 private String getTableMissFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
2297 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR
2298 + tableMiss + FLOWID_PREFIX;
2302 * Install flow entry in protocol table to forward mpls
2303 * coming through gre tunnel to LFIB table.
2305 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
2306 final BigInteger cookieProtocolTable = new BigInteger("1070000", 16);
2307 // Instruction to goto L3 InterfaceTable
2308 List<InstructionInfo> instructions = new ArrayList<>();
2309 instructions.add(new InstructionGotoTable(NwConstants.L3_LFIB_TABLE));
2310 List<MatchInfo> matches = new ArrayList<>();
2311 matches.add(MatchEthernetType.MPLS_UNICAST);
2312 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2313 getTableMissFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2314 NwConstants.L3_LFIB_TABLE),
2315 DEFAULT_FIB_FLOW_PRIORITY,
2316 "Protocol Table For LFIB",
2318 cookieProtocolTable,
2319 matches, instructions);
2321 if (addOrRemove == NwConstants.ADD_FLOW) {
2322 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
2323 mdsalManager.installFlow(flowEntityToLfib);
2325 mdsalManager.removeFlow(flowEntityToLfib);
2329 public List<String> printFibEntries() {
2330 List<String> result = new ArrayList<>();
2331 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s", "RD", "Prefix", "NextHop", "Label", "Origin"));
2332 result.add("-------------------------------------------------------------------");
2333 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
2334 Optional<FibEntries> fibEntries = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2335 if (fibEntries.isPresent()) {
2336 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
2337 for (VrfTables vrfTable : vrfTables) {
2338 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
2339 List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
2340 for (RoutePaths routePath : routePaths) {
2341 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s",
2342 vrfTable.getRouteDistinguisher(),
2343 vrfEntry.getDestPrefix(), routePath.getNexthopAddress(),
2344 routePath.getLabel(), vrfEntry.getOrigin()));
2346 if (routePaths.isEmpty()) {
2347 result.add(String.format(" %-7s %-20s %-20s %-7s",
2348 vrfTable.getRouteDistinguisher(),
2349 vrfEntry.getDestPrefix(), "local", vrfEntry.getOrigin()));
2358 private VrfEntry getVrfEntry(DataBroker broker, String rd, String ipPrefix) {
2359 InstanceIdentifier<VrfEntry> vrfEntryId = InstanceIdentifier.builder(FibEntries.class)
2360 .child(VrfTables.class, new VrfTablesKey(rd))
2361 .child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2362 Optional<VrfEntry> vrfEntry = read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
2363 if (vrfEntry.isPresent()) {
2364 return vrfEntry.get();
2369 private InstanceIdentifier<VrfEntry> getVrfEntryId(String rd, String ipPrefix) {
2370 InstanceIdentifier<VrfEntry> vrfEntryId = InstanceIdentifier.builder(FibEntries.class)
2371 .child(VrfTables.class, new VrfTablesKey(rd))
2372 .child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2376 protected Boolean isIpv4Address(String ipAddress) {
2378 InetAddress address = InetAddress.getByName(ipAddress);
2379 if (address instanceof Inet4Address) {
2382 } catch (UnknownHostException e) {
2383 LOG.warn("Invalid ip address {}", ipAddress, e);
2389 protected Boolean installRouterFibEntries(final VrfEntry vrfEntry, final Collection<VpnToDpnList> vpnToDpnList,
2390 long vpnId, int addOrRemove) {
2391 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
2392 if (routerInt == null) {
2395 if (vpnToDpnList != null) {
2396 String routerId = routerInt.getUuid();
2397 String macAddress = routerInt.getMacAddress();
2398 String ipValue = routerInt.getIpAddress();
2399 LOG.trace("createFibEntries - Router augmented vrfentry found for for router uuid:{}, ip:{}, mac:{}",
2400 routerId, ipValue, macAddress);
2401 for (VpnToDpnList vpnDpn : vpnToDpnList) {
2402 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
2403 installRouterFibEntry(vrfEntry, vpnDpn.getDpnId(), vpnId, routerId, ipValue,
2404 new MacAddress(macAddress), addOrRemove);
2411 public void installRouterFibEntry(final VrfEntry vrfEntry, BigInteger dpnId, long vpnId, String routerUuid,
2412 String routerInternalIp, MacAddress routerMac, int addOrRemove) {
2413 String[] subSplit = routerInternalIp.split("/");
2414 if (!isIpv4Address(subSplit[0])) {
2415 // Ping responder using OpenFlow rules is only supported for IPv4, hence skipping.
2419 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
2420 if (!optionalLabel.isPresent()) {
2421 LOG.warn("Routes paths not present. Exiting installRouterFibEntry");
2424 String addRemoveStr = (addOrRemove == NwConstants.ADD_FLOW) ? "ADD_FLOW" : "DELETE_FLOW";
2425 LOG.trace("{}: bulding Echo Flow entity for dpid:{}, router_ip:{}, vpnId:{}, subSplit:{} ", addRemoveStr,
2426 dpnId, routerInternalIp, vpnId, subSplit[0]);
2428 List<MatchInfo> matches = new ArrayList<>();
2430 matches.add(MatchIpProtocol.ICMP);
2431 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
2432 matches.add(new MatchIcmpv4((short) 8, (short) 0));
2433 matches.add(MatchEthernetType.IPV4);
2434 matches.add(new MatchIpv4Destination(subSplit[0], "32"));
2436 List<ActionInfo> actionsInfos = new ArrayList<>();
2438 // Set Eth Src and Eth Dst
2439 actionsInfos.add(new ActionMoveSourceDestinationEth());
2440 actionsInfos.add(new ActionSetFieldEthernetSource(routerMac));
2442 // Move Ip Src to Ip Dst
2443 actionsInfos.add(new ActionMoveSourceDestinationIp());
2444 actionsInfos.add(new ActionSetSourceIp(subSplit[0], "32"));
2446 // Set the ICMP type to 0 (echo reply)
2447 actionsInfos.add(new ActionSetIcmpType((short) 0));
2449 actionsInfos.add(new ActionNxLoadInPort(BigInteger.ZERO));
2451 actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
2453 List<InstructionInfo> instructions = new ArrayList<>();
2455 instructions.add(new InstructionApplyActions(actionsInfos));
2457 int priority = FibConstants.DEFAULT_FIB_FLOW_PRIORITY + FibConstants.DEFAULT_PREFIX_LENGTH;
2458 String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, optionalLabel.get(),
2461 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef,
2462 0, 0, NwConstants.COOKIE_VM_FIB_TABLE, matches, instructions);
2464 if (addOrRemove == NwConstants.ADD_FLOW) {
2465 mdsalManager.installFlow(flowEntity);
2467 mdsalManager.removeFlow(flowEntity);
2471 public void removeInterVPNLinkRouteFlows(final String interVpnLinkName,
2472 final boolean isVpnFirstEndPoint,
2473 final VrfEntry vrfEntry) {
2474 Preconditions.checkArgument(vrfEntry.getRoutePaths() != null
2475 && vrfEntry.getRoutePaths().size() == 1);
2476 Optional<InterVpnLinkState> interVpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLinkName);
2478 if (!interVpnLinkState.isPresent()) {
2479 LOG.warn("Could not find State for InterVpnLink {}", interVpnLinkName);
2483 List<BigInteger> targetDpns =
2484 isVpnFirstEndPoint ? interVpnLinkState.get().getFirstEndpointState().getDpId()
2485 : interVpnLinkState.get().getSecondEndpointState().getDpId();
2487 java.util.Optional<String> optionalNextHop = FibUtil.getFirstNextHopAddress(vrfEntry);
2488 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
2492 optionalNextHop.ifPresent(nextHop -> {
2493 String flowRef = getInterVpnFibFlowRef(interVpnLinkName, vrfEntry.getDestPrefix(), nextHop);
2494 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
2495 Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef))
2496 .setTableId(NwConstants.L3_FIB_TABLE).setFlowName(flowRef).build();
2498 LOG.trace("Removing flow in FIB table for interVpnLink {} key {}",
2499 interVpnLinkName, flowRef);
2501 for (BigInteger dpId : targetDpns) {
2502 LOG.debug("Removing flow: VrfEntry=[prefix={} nexthop={}] dpn {} for InterVpnLink {} in FIB",
2503 vrfEntry.getDestPrefix(), nextHop,
2504 dpId, interVpnLinkName);
2506 mdsalManager.removeFlow(dpId, flow);
2512 optionalLabel.ifPresent(label -> {
2513 LOG.trace("Removing flow in FIB table for interVpnLink {}", interVpnLinkName);
2515 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
2516 for (BigInteger dpId : targetDpns) {
2517 LOG.debug("Removing flow: VrfEntry=[prefix={} label={}] dpn {} for InterVpnLink {} in LFIB",
2518 vrfEntry.getDestPrefix(), label,
2519 dpId, interVpnLinkName);
2520 makeLFibTableEntry(dpId, label, null /* no instructions */,
2521 LFIB_INTERVPN_PRIORITY, NwConstants.DEL_FLOW, tx);
2527 private Consumer<? super VrfEntry> getConsumerForCreatingRemoteFib(
2528 final BigInteger dpnId, final long vpnId, final String rd,
2529 final String remoteNextHopIp, final Optional<VrfTables> vrfTable,
2530 WriteTransaction writeCfgTxn) {
2531 return vrfEntry -> vrfEntry.getRoutePaths().stream()
2532 .filter(routes -> !routes.getNexthopAddress().isEmpty()
2533 && remoteNextHopIp.trim().equals(routes.getNexthopAddress().trim()))
2535 .ifPresent(routes -> {
2536 LOG.trace("creating remote FIB entry for prefix {} rd {} on Dpn {}",
2537 vrfEntry.getDestPrefix(), rd, dpnId);
2538 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeCfgTxn);
2542 private Consumer<? super VrfEntry> getConsumerForDeletingRemoteFib(
2543 final BigInteger dpnId, final long vpnId, final String rd,
2544 final String remoteNextHopIp, final Optional<VrfTables> vrfTable,
2545 WriteTransaction writeCfgTxn) {
2546 return vrfEntry -> vrfEntry.getRoutePaths().stream()
2547 .filter(routes -> !routes.getNexthopAddress().isEmpty()
2548 && remoteNextHopIp.trim().equals(routes.getNexthopAddress().trim()))
2550 .ifPresent(routes -> {
2551 LOG.trace(" deleting remote FIB entry {}", vrfEntry);
2552 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry,
2553 Optional.absent(), writeCfgTxn);
2557 private boolean isPrefixAndNextHopPresentInLri(String prefix,
2558 List<String> nextHopAddressList, LabelRouteInfo lri) {
2559 return lri != null && lri.getPrefix().equals(prefix)
2560 && nextHopAddressList.contains(lri.getNextHopIpList().get(0));
2563 private boolean shouldCreateFibEntryForVrfAndVpnIdOnDpn(Long vpnId, VrfEntry vrfEntry, BigInteger dpnId) {
2564 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
2568 Prefixes prefix = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
2569 if (prefix != null) {
2570 BigInteger prefixDpnId = prefix.getDpnId();
2571 if (prefixDpnId == dpnId) {
2572 LOG.trace("Should not create remote FIB entry for vrfEntry {} on DPN {}",
2581 private void programRemoteFibForBgpRoutes(final BigInteger remoteDpnId, final long vpnId,
2582 final VrfEntry vrfEntry, WriteTransaction tx, String rd, List<AdjacencyResult> adjacencyResults) {
2583 Preconditions.checkArgument(vrfEntry.getRoutePaths().size() <= 2);
2585 if (adjacencyResults.size() == 1) {
2586 programRemoteFib(remoteDpnId, vpnId, vrfEntry, tx, rd, adjacencyResults);
2589 // ECMP Use case, point to LB group. Move the mpls label accordingly.
2590 List<String> tunnelList =
2591 adjacencyResults.stream()
2592 .map(adjacencyResult -> adjacencyResult.getNextHopIp())
2593 .sorted().collect(toList());
2594 String lbGroupKey = FibUtil.getGreLbGroupKey(tunnelList);
2595 long groupId = nextHopManager.createNextHopPointer(lbGroupKey);
2597 List<ActionInfo> actionInfos = new ArrayList<>();
2598 for (AdjacencyResult adjResult : adjacencyResults) {
2599 String nextHopIp = adjResult.getNextHopIp();
2600 java.util.Optional<Long> optionalLabel = FibUtil.getLabelForNextHop(vrfEntry, nextHopIp);
2601 if (!optionalLabel.isPresent()) {
2602 LOG.warn("NextHopIp {} not found in vrfEntry {}", nextHopIp, vrfEntry);
2605 long label = optionalLabel.get();
2607 actionInfos.add(new ActionRegLoad(index, FibConstants.NXM_REG_MAPPING.get(index++), 0,
2610 List<InstructionInfo> instructions = new ArrayList<>();
2611 actionInfos.add(new ActionGroup(index, groupId));
2612 instructions.add(new InstructionApplyActions(actionInfos));
2613 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);