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.EncapType.Vxlan.equals(vrfEntry.getEncapType())) {
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 if (vrfEntry.getRoutePaths() != null) {
568 for (RoutePaths routePath : vrfEntry.getRoutePaths()) {
569 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
570 List<ActionInfo> actionsInfos = new ArrayList<>();
571 // reinitialize instructions list for LFIB Table
572 final List<InstructionInfo> LFIBinstructions = new ArrayList<>();
574 actionsInfos.add(new ActionPopMpls());
575 LFIBinstructions.add(new InstructionApplyActions(actionsInfos));
576 LFIBinstructions.add(new InstructionWriteMetadata(subnetRouteMeta,
577 MetaDataUtil.METADATA_MASK_SUBNET_ROUTE));
578 LFIBinstructions.add(new InstructionGotoTable(NwConstants.L3_SUBNET_ROUTE_TABLE));
580 makeLFibTableEntry(dpnId, routePath.getLabel(), LFIBinstructions, DEFAULT_FIB_FLOW_PRIORITY,
581 NwConstants.ADD_FLOW, tx);
591 * For a given route, it installs a flow in LFIB that sets the lportTag of the other endpoint and sends to
592 * LportDispatcher table (via table 80)
594 private void installInterVpnRouteInLFib(final String rd, final VrfEntry vrfEntry) {
595 // INTERVPN routes are routes in a Vpn1 that have been leaked to Vpn2. In DC-GW, this Vpn2 route is pointing
596 // to a list of DPNs where Vpn2's VpnLink was instantiated. In these DPNs LFIB must be programmed so that the
597 // packet is commuted from Vpn2 to Vpn1.
598 Optional<String> vpnNameOpc = FibUtil.getVpnNameFromRd(dataBroker, rd);
599 if (!vpnNameOpc.isPresent()) {
600 LOG.warn("Could not find VpnInstanceName for Route-Distinguisher {}", rd);
604 String vpnName = vpnNameOpc.get();
605 List<InterVpnLink> interVpnLinks = FibUtil.getAllInterVpnLinks(dataBroker);
606 boolean interVpnLinkFound = false;
607 for (InterVpnLink interVpnLink : interVpnLinks) {
608 boolean vpnIs1stEndpoint = interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName);
609 boolean vpnIs2ndEndpoint = !vpnIs1stEndpoint
610 && interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnName);
611 if (vpnIs1stEndpoint || vpnIs2ndEndpoint) {
612 interVpnLinkFound = true;
614 Optional<InterVpnLinkState> vpnLinkState =
615 FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName());
616 if (!vpnLinkState.isPresent()
617 || !vpnLinkState.get().getState().equals(InterVpnLinkState.State.Active)) {
618 LOG.warn("InterVpnLink {}, linking VPN {} and {}, is not in Active state",
619 interVpnLink.getName(), interVpnLink.getFirstEndpoint().getVpnUuid().getValue(),
620 interVpnLink.getSecondEndpoint().getVpnUuid().getValue());
624 List<BigInteger> targetDpns = vpnIs1stEndpoint ? vpnLinkState.get().getFirstEndpointState().getDpId()
625 : vpnLinkState.get().getSecondEndpointState().getDpId();
626 Long lportTag = vpnIs1stEndpoint ? vpnLinkState.get().getSecondEndpointState().getLportTag()
627 : vpnLinkState.get().getFirstEndpointState().getLportTag();
629 LOG.trace("Installing flow in LFIB table for interVpnLink {}", interVpnLink.getName());
631 for (BigInteger dpId : targetDpns) {
632 List<ActionInfo> actionsInfos = Collections.singletonList(new ActionPopMpls());
634 List<InstructionInfo> instructions =
635 Arrays.asList(new InstructionApplyActions(actionsInfos),
636 new InstructionWriteMetadata(
637 MetaDataUtil.getMetaDataForLPortDispatcher(lportTag.intValue(),
638 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
639 NwConstants.L3VPN_SERVICE_INDEX)),
640 MetaDataUtil.getMetaDataMaskForLPortDispatcher()),
641 new InstructionGotoTable(NwConstants.L3_INTERFACE_TABLE));
643 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(interVpnRoutePathLabel -> {
644 List<String> interVpnNextHopList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
645 LOG.debug("Installing flow: VrfEntry=[prefix={} label={} nexthop={}] dpn {} for "
646 + "InterVpnLink {} in LFIB",
647 vrfEntry.getDestPrefix(), interVpnRoutePathLabel, interVpnNextHopList,
648 dpId, interVpnLink.getName());
650 makeLFibTableEntry(dpId, interVpnRoutePathLabel, instructions, LFIB_INTERVPN_PRIORITY,
651 NwConstants.ADD_FLOW, null);
659 if (!interVpnLinkFound) {
660 LOG.warn("VrfEntry=[prefix={} route-paths={}] for VPN {} has origin INTERVPN but "
661 + "no InterVpnLink could be found",
662 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(), rd);
668 * Installs the flows in FIB table that, for a given route, do the switching from one VPN to the other.
670 private void installIVpnLinkSwitchingFlows(final InterVpnLinkDataComposite interVpnLink, final String vpnUuid,
671 final VrfEntry vrfEntry, long vpnTag) {
672 Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
673 Preconditions.checkArgument(vrfEntry.getRoutePaths() != null
674 && vrfEntry.getRoutePaths().size() == 1);
675 String destination = vrfEntry.getDestPrefix();
676 String nextHop = vrfEntry.getRoutePaths().get(0).getNexthopAddress();
677 String interVpnLinkName = interVpnLink.getInterVpnLinkName();
679 // After having received a static route, we should check if the vpn is part of an inter-vpn-link.
680 // In that case, we should populate the FIB table of the VPN pointing to LPortDisptacher table
681 // using as metadata the LPortTag associated to that vpn in the inter-vpn-link.
682 if (interVpnLink.getState().or(State.Error) != State.Active) {
683 LOG.warn("Route to {} with nexthop={} cannot be installed because the interVpnLink {} is not active",
684 destination, nextHop, interVpnLinkName);
688 Optional<Long> optOtherEndpointLportTag = interVpnLink.getOtherEndpointLportTagByVpnName(vpnUuid);
689 if (!optOtherEndpointLportTag.isPresent()) {
690 LOG.warn("Could not find suitable LportTag for the endpoint opposite to vpn {} in interVpnLink {}",
691 vpnUuid, interVpnLinkName);
695 List<BigInteger> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnUuid);
696 if (targetDpns.isEmpty()) {
697 LOG.warn("Could not find DPNs for endpoint opposite to vpn {} in interVpnLink {}",
698 vpnUuid, interVpnLinkName);
702 String[] values = destination.split("/");
703 String destPrefixIpAddress = values[0];
704 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
706 List<MatchInfo> matches = new ArrayList<>();
707 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnTag), MetaDataUtil.METADATA_MASK_VRFID));
708 matches.add(MatchEthernetType.IPV4);
710 if (prefixLength != 0) {
711 matches.add(new MatchIpv4Destination(destPrefixIpAddress, Integer.toString(prefixLength)));
714 List<Instruction> instructions =
715 Arrays.asList(new InstructionWriteMetadata(
716 MetaDataUtil.getMetaDataForLPortDispatcher(optOtherEndpointLportTag.get().intValue(),
717 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants
718 .L3VPN_SERVICE_INDEX)),
719 MetaDataUtil.getMetaDataMaskForLPortDispatcher()).buildInstruction(0),
720 new InstructionGotoTable(NwConstants.L3_INTERFACE_TABLE).buildInstruction(1));
722 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
723 String flowRef = getInterVpnFibFlowRef(interVpnLinkName, destination, nextHop);
724 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
725 COOKIE_VM_FIB_TABLE, matches, instructions);
727 LOG.trace("Installing flow in FIB table for vpn {} interVpnLink {} nextHop {} key {}",
728 vpnUuid, interVpnLink.getInterVpnLinkName(), nextHop, flowRef);
730 for (BigInteger dpId : targetDpns) {
732 LOG.debug("Installing flow: VrfEntry=[prefix={} route-paths={}] dpn {} for InterVpnLink {} in FIB",
733 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(),
734 dpId, interVpnLink.getInterVpnLinkName());
736 mdsalManager.installFlow(dpId, flowEntity);
741 // TODO Clean up the exception handling
742 @SuppressWarnings("checkstyle:IllegalCatch")
743 private <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
744 InstanceIdentifier<T> path) {
746 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
748 Optional<T> result = Optional.absent();
750 result = tx.read(datastoreType, path).get();
751 } catch (Exception e) {
752 throw new RuntimeException(e);
758 private List<BigInteger> getDpnIdForPrefix(DataBroker broker, Long vpnId, String rd, VrfEntry vrfEntry) {
759 List<BigInteger> returnLocalDpnId = new ArrayList<>();
760 Prefixes localNextHopInfo = FibUtil.getPrefixToInterface(broker, vpnId, vrfEntry.getDestPrefix());
762 if (localNextHopInfo == null) {
763 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
764 Optional<Routes> extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker,
765 FibUtil.getVpnNameFromId(dataBroker, vpnId), rd, vrfEntry.getDestPrefix());
766 if (extraRouteOptional.isPresent()) {
767 Routes extraRoute = extraRouteOptional.get();
768 for (String nextHopIp : extraRoute.getNexthopIpList()) {
769 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
770 if (nextHopIp != null) {
771 localNextHopInfo = FibUtil.getPrefixToInterface(broker, vpnId, nextHopIp
772 + NwConstants.IPV4PREFIX);
773 if (localNextHopInfo != null) {
774 returnLocalDpnId.add(localNextHopInfo.getDpnId());
780 returnLocalDpnId.add(localNextHopInfo.getDpnId());
783 return returnLocalDpnId;
786 private List<BigInteger> createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
787 List<BigInteger> returnLocalDpnId = new ArrayList<>();
788 Prefixes localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
789 String localNextHopIP = vrfEntry.getDestPrefix();
790 String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnId);
791 if (localNextHopInfo == null) {
792 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
793 List<Routes> vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker,
794 vpnName, usedRds, localNextHopIP);
795 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
796 vpnExtraRoutes.stream().forEach(extraRoute -> {
797 Prefixes localNextHopInfoLocal = FibUtil.getPrefixToInterface(dataBroker,
798 vpnId, extraRoute.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX);
799 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfoLocal, vrfEntry.getDestPrefix(),
800 vpnId, rd, vrfEntry, vpnId, extraRoute, vpnExtraRoutes);
801 returnLocalDpnId.add(dpnId);
803 if (localNextHopInfo == null) {
804 /* imported routes case */
805 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
806 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
807 if (optionalLabel.isPresent()) {
808 Long label = optionalLabel.get();
809 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
810 synchronized (label.toString().intern()) {
811 LabelRouteInfo lri = getLabelRouteInfo(label);
812 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
813 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
814 FibUtil.getVpnInstanceOpData(dataBroker, rd);
815 if (vpnInstanceOpDataEntryOptional.isPresent()) {
816 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
817 if (lri.getVpnInstanceList().contains(vpnInstanceName)) {
818 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, true);
819 localNextHopIP = lri.getPrefix();
821 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, false);
822 localNextHopIP = lri.getPrefix();
825 if (localNextHopInfo != null) {
826 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
827 label, localNextHopInfo.getVpnInterfaceName(), lri.getDpnId());
828 if (vpnExtraRoutes == null || vpnExtraRoutes.isEmpty()) {
829 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP,
830 vpnId, rd, vrfEntry, lri.getParentVpnid(), null, vpnExtraRoutes);
831 returnLocalDpnId.add(dpnId);
833 for (Routes extraRoutes : vpnExtraRoutes) {
834 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo,
836 vpnId, rd, vrfEntry, lri.getParentVpnid(),
837 extraRoutes, vpnExtraRoutes);
838 returnLocalDpnId.add(dpnId);
847 if (returnLocalDpnId.isEmpty()) {
848 LOG.error("Local DPNID is empty for rd {}, vpnId {}, vrfEntry {}", rd, vpnId, vrfEntry);
851 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId,
852 rd, vrfEntry, vpnId, /*routes*/ null, /*vpnExtraRoutes*/ null);
853 returnLocalDpnId.add(dpnId);
855 return returnLocalDpnId;
858 private BigInteger checkCreateLocalFibEntry(Prefixes localNextHopInfo, String localNextHopIP,
859 final Long vpnId, final String rd,
860 final VrfEntry vrfEntry, Long parentVpnId,
861 Routes routes, List<Routes> vpnExtraRoutes) {
862 String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnId);
863 if (localNextHopInfo != null) {
866 final BigInteger dpnId = localNextHopInfo.getDpnId();
867 if (Boolean.TRUE.equals(localNextHopInfo.isNatPrefix())) {
868 LOG.debug("NAT Prefix {} with vpnId {} rd {}. Skip local dpn {} FIB processing",
869 vrfEntry.getDestPrefix(), vpnId, rd, dpnId);
872 String jobKey = FibUtil.getCreateLocalNextHopJobKey(vpnId, dpnId, vrfEntry.getDestPrefix());
873 if (routes != null) {
874 groupId = nextHopManager.createNextHopGroups(parentVpnId, rd, dpnId, vrfEntry, routes,
876 localGroupId = nextHopManager.getLocalNextHopGroup(parentVpnId,
877 routes.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX);
879 groupId = nextHopManager.createLocalNextHop(parentVpnId, dpnId,
880 localNextHopInfo.getVpnInterfaceName(), localNextHopIP, vrfEntry.getDestPrefix(),
881 vrfEntry.getGatewayMacAddress(), jobKey);
882 localGroupId = groupId;
884 if (groupId == FibConstants.INVALID_GROUP_ID) {
885 LOG.error("Unable to create Group for local prefix {} on rd {} for vpninterface {} on Node {}",
886 vrfEntry.getDestPrefix(), rd, localNextHopInfo.getVpnInterfaceName(), dpnId.toString());
887 return BigInteger.ZERO;
889 final List<InstructionInfo> instructions = Collections.singletonList(
890 new InstructionApplyActions(
891 Collections.singletonList(new ActionGroup(groupId))));
892 final List<InstructionInfo> lfibinstructions = Collections.singletonList(
893 new InstructionApplyActions(
894 Arrays.asList(new ActionPopMpls(), new ActionGroup(groupId))));
895 java.util.Optional<Long> optLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
896 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
897 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
898 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
899 dpnId, localNextHopInfo.getVpnInterfaceName(), optLabel);
901 LOG.debug("Route with rd {} prefix {} label {} nexthop {} for vpn {} is an imported route. "
902 + "LFib and Terminating table entries will not be created.",
903 rd, vrfEntry.getDestPrefix(), optLabel, nextHopAddressList, vpnId);
905 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
907 dataStoreCoordinator.enqueueJob(jobKey,
909 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
910 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
911 optLabel.ifPresent(label -> {
912 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
913 makeLFibTableEntry(dpnId, label, lfibinstructions,
914 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
915 makeTunnelTableEntry(dpnId, label, localGroupId, tx);
919 List<ListenableFuture<Void>> futures = new ArrayList<>();
920 futures.add(tx.submit());
925 LOG.error("localNextHopInfo received is null for prefix {} on rd {} on vpn {}",
926 vrfEntry.getDestPrefix(), rd, vpnName);
927 return BigInteger.ZERO;
930 private boolean isVpnPresentInDpn(String rd, BigInteger dpnId) {
931 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
932 return FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id).isPresent();
935 private LabelRouteInfo getLabelRouteInfo(Long label) {
936 InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
937 .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build();
938 Optional<LabelRouteInfo> opResult = read(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid);
939 if (opResult.isPresent()) {
940 return opResult.get();
945 private boolean deleteLabelRouteInfo(LabelRouteInfo lri, String vpnInstanceName, WriteTransaction tx) {
946 LOG.debug("deleting LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
947 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
948 .child(LabelRouteInfo.class, new LabelRouteInfoKey(lri.getLabel())).build();
952 List<String> vpnInstancesList = lri.getVpnInstanceList() != null
953 ? lri.getVpnInstanceList() : new ArrayList<>();
954 if (vpnInstancesList.contains(vpnInstanceName)) {
955 LOG.debug("vpninstance {} name is present", vpnInstanceName);
956 vpnInstancesList.remove(vpnInstanceName);
958 if (vpnInstancesList.size() == 0) {
959 LOG.debug("deleting LRI instance object for label {}", lri.getLabel());
961 tx.delete(LogicalDatastoreType.OPERATIONAL, lriId);
963 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId);
967 LOG.debug("updating LRI instance object for label {}", lri.getLabel());
968 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri).setVpnInstanceList(vpnInstancesList);
969 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(),
970 FibUtil.DEFAULT_CALLBACK);
975 void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/,
976 WriteTransaction tx) {
977 List<ActionInfo> actionsInfos = Collections.singletonList(new ActionGroup(groupId));
979 createTerminatingServiceActions(dpId, (int) label, actionsInfos, tx);
981 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully",
982 dpId, label, groupId);
985 public void createTerminatingServiceActions(BigInteger destDpId, int label, List<ActionInfo> actionsInfos,
986 WriteTransaction tx) {
987 List<MatchInfo> mkMatches = new ArrayList<>();
989 LOG.debug("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}",
990 destDpId, label, actionsInfos);
993 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
994 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(label)));
996 List<InstructionInfo> mkInstructions = new ArrayList<>();
997 mkInstructions.add(new InstructionApplyActions(actionsInfos));
999 FlowEntity terminatingServiceTableFlowEntity =
1000 MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
1001 getTableMissFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE, label), 5,
1002 String.format("%s:%d", "TST Flow Entry ", label),
1003 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, mkInstructions);
1005 FlowKey flowKey = new FlowKey(new FlowId(terminatingServiceTableFlowEntity.getFlowId()));
1007 FlowBuilder flowbld = terminatingServiceTableFlowEntity.getFlowBuilder();
1009 Node nodeDpn = buildDpnNode(terminatingServiceTableFlowEntity.getDpnId());
1010 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1011 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1012 .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId()))
1013 .child(Flow.class, flowKey).build();
1014 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flowbld.build(), true);
1017 private void removeTunnelTableEntry(BigInteger dpId, long label, WriteTransaction tx) {
1018 FlowEntity flowEntity;
1019 LOG.debug("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId, label);
1020 List<MatchInfo> mkMatches = new ArrayList<>();
1021 // Matching metadata
1022 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(label)));
1023 flowEntity = MDSALUtil.buildFlowEntity(dpId,
1024 NwConstants.INTERNAL_TUNNEL_TABLE,
1025 getTableMissFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int) label),
1026 5, String.format("%s:%d", "TST Flow Entry ", label), 0, 0,
1027 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
1028 Node nodeDpn = buildDpnNode(flowEntity.getDpnId());
1029 FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getFlowId()));
1030 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1031 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1032 .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build();
1034 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1035 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully", dpId, label);
1038 public List<BigInteger> deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
1039 List<BigInteger> returnLocalDpnId = new ArrayList<>();
1040 Prefixes localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
1041 String localNextHopIP = vrfEntry.getDestPrefix();
1042 String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnId);
1044 if (localNextHopInfo == null) {
1045 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
1046 if (usedRds.size() > 1) {
1047 LOG.error("The extra route prefix {} is still present in some DPNs in vpn {} on rd {}",
1048 vrfEntry.getDestPrefix(), vpnName, rd);
1049 return returnLocalDpnId;
1051 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency
1053 Optional<Routes> extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker,
1054 vpnName, rd, vrfEntry.getDestPrefix());
1055 if (extraRouteOptional.isPresent()) {
1056 Routes extraRoute = extraRouteOptional.get();
1057 localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId,
1058 extraRoute.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX);
1059 if (localNextHopInfo != null) {
1060 BigInteger dpnId = localNextHopInfo.getDpnId();
1061 if (!dpnId.equals(BigInteger.ZERO)) {
1062 nextHopManager.setupLoadBalancingNextHop(vpnId, dpnId,
1063 vrfEntry.getDestPrefix(), /*listBucketInfo*/ null, /*remove*/ false);
1064 returnLocalDpnId.add(dpnId);
1069 if (localNextHopInfo == null) {
1070 /* Imported VRF entry */
1071 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1072 if (optionalLabel.isPresent()) {
1073 Long label = optionalLabel.get();
1074 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
1075 LabelRouteInfo lri = getLabelRouteInfo(label);
1076 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
1077 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
1078 prefixBuilder.setDpnId(lri.getDpnId());
1079 BigInteger dpnId = checkDeleteLocalFibEntry(prefixBuilder.build(), localNextHopIP,
1080 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
1081 if (!dpnId.equals(BigInteger.ZERO)) {
1082 returnLocalDpnId.add(dpnId);
1089 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
1090 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
1091 if (!dpnId.equals(BigInteger.ZERO)) {
1092 returnLocalDpnId.add(dpnId);
1096 return returnLocalDpnId;
1099 private BigInteger checkDeleteLocalFibEntry(Prefixes localNextHopInfo, final String localNextHopIP,
1100 final Long vpnId, final String rd,
1101 final VrfEntry vrfEntry, final boolean isExtraRoute) {
1102 if (localNextHopInfo != null) {
1103 final BigInteger dpnId = localNextHopInfo.getDpnId();
1104 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1105 dataStoreCoordinator.enqueueJob("FIB-" + vpnId.toString() + "-"
1106 + dpnId.toString() + "-" + vrfEntry.getDestPrefix(),
1108 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1109 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null /* instructions */,
1110 NwConstants.DEL_FLOW, tx);
1111 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1112 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
1113 makeLFibTableEntry(dpnId, label, null /* instructions */,
1114 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1115 removeTunnelTableEntry(dpnId, label, tx);
1118 List<ListenableFuture<Void>> futures = new ArrayList<>();
1119 futures.add(tx.submit());
1122 //TODO: verify below adjacency call need to be optimized (?)
1123 deleteLocalAdjacency(dpnId, vpnId, localNextHopIP, vrfEntry.getDestPrefix());
1126 return BigInteger.ZERO;
1129 static InstanceIdentifier<Routes> getVpnToExtrarouteIdentifier(String vpnName, String vrfId,
1131 return InstanceIdentifier.builder(VpnToExtraroutes.class)
1132 .child(Vpn.class, new VpnKey(vpnName)).child(ExtraRoutes.class,
1133 new ExtraRoutesKey(vrfId)).child(Routes.class, new RoutesKey(ipPrefix)).build();
1136 public Routes getVpnToExtraroute(String vpnRd, String destPrefix) {
1137 Optional<String> optVpnName = FibUtil.getVpnNameFromRd(dataBroker, vpnRd);
1138 if (optVpnName.isPresent()) {
1139 InstanceIdentifier<Routes> vpnExtraRoutesId = getVpnToExtrarouteIdentifier(
1140 optVpnName.get(), vpnRd, destPrefix);
1141 return FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, vpnExtraRoutesId).orNull();
1146 private void createRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, final VrfTablesKey vrfTableKey,
1147 final VrfEntry vrfEntry, WriteTransaction tx) {
1148 Boolean wrTxPresent = true;
1150 wrTxPresent = false;
1151 tx = dataBroker.newWriteOnlyTransaction();
1153 String rd = vrfTableKey.getRouteDistinguisher();
1154 String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnId);
1155 LOG.debug("createremotefibentry: adding route {} for rd {} on remoteDpnId {}",
1156 vrfEntry.getDestPrefix(), rd, remoteDpnId);
1158 List<AdjacencyResult> adjacencyResults = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
1159 if (adjacencyResults == null || adjacencyResults.isEmpty()) {
1160 LOG.error("Could not get interface for route-paths: {} in vpn {}",
1161 vrfEntry.getRoutePaths(), rd);
1162 LOG.warn("Failed to add Route: {} in vpn: {}",
1163 vrfEntry.getDestPrefix(), rd);
1166 if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) {
1167 programRemoteFibForBgpRoutes(remoteDpnId, vpnId, vrfEntry, tx, rd, adjacencyResults);
1169 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
1170 List<Routes> vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker,
1171 vpnName, usedRds, vrfEntry.getDestPrefix());
1172 if (!vpnExtraRoutes.isEmpty()) {
1173 List<InstructionInfo> instructions = new ArrayList<>();
1174 long groupId = nextHopManager.createNextHopGroups(vpnId, rd, remoteDpnId, vrfEntry,
1175 null, vpnExtraRoutes);
1176 if (groupId == FibConstants.INVALID_GROUP_ID) {
1177 LOG.error("Unable to create Group for local prefix {} on rd {} on Node {}",
1178 vrfEntry.getDestPrefix(), rd, remoteDpnId.toString());
1181 List<ActionInfo> actionInfos =
1182 Collections.singletonList(new ActionGroup(groupId));
1183 instructions.add(new InstructionApplyActions(actionInfos));
1184 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
1186 programRemoteFib(remoteDpnId, vpnId, vrfEntry, tx, rd, adjacencyResults);
1192 LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
1195 private void programRemoteFib(final BigInteger remoteDpnId, final long vpnId,
1196 final VrfEntry vrfEntry, WriteTransaction tx, String rd, List<AdjacencyResult> adjacencyResults) {
1197 List<InstructionInfo> instructions = new ArrayList<>();
1198 for (AdjacencyResult adjacencyResult : adjacencyResults) {
1199 List<ActionInfo> actionInfos = new ArrayList<>();
1200 String egressInterface = adjacencyResult.getInterfaceName();
1201 if (FibUtil.isTunnelInterface(adjacencyResult)) {
1202 addTunnelInterfaceActions(adjacencyResult, vpnId, vrfEntry, actionInfos);
1204 addRewriteDstMacAction(vpnId, vrfEntry, actionInfos);
1206 List<ActionInfo> egressActions = nextHopManager.getEgressActionsForInterface(egressInterface,
1207 actionInfos.size());
1208 if (egressActions.isEmpty()) {
1210 "Failed to retrieve egress action for prefix {} route-paths {} interface {}. "
1211 + "Aborting remote FIB entry creation.",
1212 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(), egressInterface);
1215 actionInfos.addAll(egressActions);
1216 instructions.add(new InstructionApplyActions(actionInfos));
1218 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
1221 private void addRewriteDstMacAction(long vpnId, VrfEntry vrfEntry, List<ActionInfo> actionInfos) {
1222 if (vrfEntry.getMac() != null) {
1223 actionInfos.add(new ActionSetFieldEthernetDestination(actionInfos.size(),
1224 new MacAddress(vrfEntry.getMac())));
1228 String ipPrefix = vrfEntry.getDestPrefix();
1229 Prefixes prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, ipPrefix);
1230 if (prefixInfo == null) {
1231 LOG.debug("No prefix info found for prefix {}", ipPrefix);
1235 String ifName = prefixInfo.getVpnInterfaceName();
1236 if (ifName == null) {
1237 LOG.warn("Failed to get VPN interface for prefix {}", ipPrefix);
1241 String macAddress = FibUtil.getMacAddressFromPrefix(dataBroker, ifName, ipPrefix);
1242 if (macAddress == null) {
1243 LOG.warn("No MAC address found for VPN interface {} prefix {}", ifName, ipPrefix);
1247 actionInfos.add(new ActionSetFieldEthernetDestination(actionInfos.size(), new MacAddress(macAddress)));
1250 private void addTunnelInterfaceActions(AdjacencyResult adjacencyResult, long vpnId, VrfEntry vrfEntry,
1251 List<ActionInfo> actionInfos) {
1252 Class<? extends TunnelTypeBase> tunnelType = VpnExtraRouteHelper.getTunnelType(interfaceManager,
1253 adjacencyResult.getInterfaceName());
1254 // TODO - For now have added routePath into adjacencyResult so that we know for which
1255 // routePath this result is built for. If this is not possible construct a map which does
1257 String nextHopIp = adjacencyResult.getNextHopIp();
1258 java.util.Optional<Long> optionalLabel = FibUtil.getLabelForNextHop(vrfEntry, nextHopIp);
1259 if (!optionalLabel.isPresent()) {
1260 LOG.warn("NextHopIp {} not found in vrfEntry {}", nextHopIp, vrfEntry);
1263 long label = optionalLabel.get();
1264 if (tunnelType.equals(TunnelTypeMplsOverGre.class)) {
1265 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
1266 actionInfos.add(new ActionPushMpls());
1267 actionInfos.add(new ActionSetFieldMplsLabel(label));
1268 actionInfos.add(new ActionNxLoadInPort(BigInteger.ZERO));
1270 BigInteger tunnelId;
1271 // FIXME vxlan vni bit set is not working properly with OVS.need to
1273 if (tunnelType.equals(TunnelTypeVxlan.class)) {
1274 tunnelId = BigInteger.valueOf(label);
1276 tunnelId = BigInteger.valueOf(label);
1279 LOG.debug("adding set tunnel id action for label {}", label);
1280 actionInfos.add(new ActionSetFieldTunnelId(tunnelId));
1281 addRewriteDstMacAction(vpnId, vrfEntry, actionInfos);
1285 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
1286 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
1287 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1288 if (dpnInVpn.isPresent()) {
1289 List<VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
1290 VpnInterfaces currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
1292 if (vpnInterfaces.remove(currVpnInterface)) {
1293 if (vpnInterfaces.isEmpty()) {
1294 LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
1295 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1296 cleanUpDpnForVpn(dpnId, vpnId, rd, null);
1298 LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
1299 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id.child(
1300 VpnInterfaces.class,
1301 new VpnInterfacesKey(intfName)));
1307 void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
1308 /* Get interface info from prefix to interface mapping;
1309 Use the interface info to get the corresponding vpn interface op DS entry,
1310 remove the adjacency corresponding to this fib entry.
1311 If adjacency removed is the last adjacency, clean up the following:
1312 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
1313 - prefix to interface entry
1314 - vpn interface op DS
1316 LOG.debug("Cleanup of prefix {} in VPN {}", vrfEntry.getDestPrefix(), vpnId);
1317 Prefixes prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
1318 Routes extraRoute = null;
1319 if (prefixInfo == null) {
1320 extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1321 if (extraRoute != null) {
1322 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1323 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
1324 if (nextHopIp != null) {
1325 prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, nextHopIp
1326 + NwConstants.IPV4PREFIX);
1327 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1331 if (prefixInfo == null) {
1332 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1333 if (optionalLabel.isPresent()) {
1334 Long label = optionalLabel.get();
1335 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
1336 LabelRouteInfo lri = getLabelRouteInfo(label);
1337 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
1338 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
1339 prefixBuilder.setDpnId(lri.getDpnId());
1340 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
1341 prefixBuilder.setIpAddress(lri.getPrefix());
1342 prefixInfo = prefixBuilder.build();
1343 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
1344 label, prefixInfo.getVpnInterfaceName(), lri.getDpnId());
1345 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1350 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1354 private void checkCleanUpOpDataForFib(final Prefixes prefixInfo, final Long vpnId, final String rd,
1355 final VrfEntry vrfEntry, final Routes extraRoute) {
1357 if (prefixInfo == null) {
1358 LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for prefix {}", vrfEntry.getDestPrefix());
1359 return; //Don't have any info for this prefix (shouldn't happen); need to return
1362 if (Boolean.TRUE.equals(prefixInfo.isNatPrefix())) {
1363 LOG.debug("NAT Prefix {} with vpnId {} rd {}. Skip FIB processing",
1364 vrfEntry.getDestPrefix(), vpnId, rd);
1368 String ifName = prefixInfo.getVpnInterfaceName();
1369 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1370 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + ifName,
1371 new CleanupVpnInterfaceWorker(prefixInfo, vpnId, rd, vrfEntry, extraRoute));
1374 private class CleanupVpnInterfaceWorker implements Callable<List<ListenableFuture<Void>>> {
1375 Prefixes prefixInfo;
1381 CleanupVpnInterfaceWorker(final Prefixes prefixInfo, final Long vpnId, final String rd,
1382 final VrfEntry vrfEntry, final Routes extraRoute) {
1383 this.prefixInfo = prefixInfo;
1386 this.vrfEntry = vrfEntry;
1387 this.extraRoute = extraRoute;
1391 public List<ListenableFuture<Void>> call() throws Exception {
1392 // If another renderer(for eg : CSS) needs to be supported, check can be performed here
1393 // to call the respective helpers.
1394 WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
1396 //First Cleanup LabelRouteInfo
1397 //TODO(KIRAN) : Move the below block when addressing iRT/eRT for L3VPN Over VxLan
1398 if (vrfEntry.getEncapType().equals(VrfEntry.EncapType.Mplsgre)) {
1399 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
1400 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
1401 synchronized (label.toString().intern()) {
1402 LabelRouteInfo lri = getLabelRouteInfo(label);
1403 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
1404 && nextHopAddressList.contains(lri.getNextHopIpList().get(0))) {
1405 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
1406 FibUtil.getVpnInstanceOpData(dataBroker, rd);
1407 String vpnInstanceName = "";
1408 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1409 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1411 boolean lriRemoved = deleteLabelRouteInfo(lri, vpnInstanceName, writeOperTxn);
1413 String parentRd = lri.getParentVpnRd();
1414 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1415 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1418 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1419 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1424 String ifName = prefixInfo.getVpnInterfaceName();
1425 Optional<VpnInterface> optvpnInterface = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1426 FibUtil.getVpnInterfaceIdentifier(ifName));
1427 if (optvpnInterface.isPresent()) {
1428 long associatedVpnId = FibUtil.getVpnId(dataBroker, optvpnInterface.get().getVpnInstanceName());
1429 if (vpnId != associatedVpnId) {
1430 LOG.warn("Prefixes {} are associated with different vpn instance with id : {} rather than {}",
1431 vrfEntry.getDestPrefix(), associatedVpnId, vpnId);
1432 LOG.warn("Not proceeding with Cleanup op data for prefix {}", vrfEntry.getDestPrefix());
1435 LOG.debug("Processing cleanup of prefix {} associated with vpn {}",
1436 vrfEntry.getDestPrefix(), associatedVpnId);
1439 if (extraRoute != null) {
1440 Optional<String> optVpnName = FibUtil.getVpnNameFromRd(dataBroker, rd);
1441 if (optVpnName.isPresent()) {
1442 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
1443 getVpnToExtrarouteIdentifier(optVpnName.get(), rd, vrfEntry.getDestPrefix()));
1446 Optional<Adjacencies> optAdjacencies = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1447 FibUtil.getAdjListPath(ifName));
1449 if (optAdjacencies.isPresent()) {
1450 numAdj = optAdjacencies.get().getAdjacency().size();
1452 //remove adjacency corr to prefix
1454 LOG.info("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId,
1455 vrfEntry.getDestPrefix());
1456 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
1457 FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
1459 //this is last adjacency (or) no more adjacency left for this vpn interface, so
1460 //clean up the vpn interface from DpnToVpn list
1461 LOG.info("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
1462 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnInterfaceIdentifier(ifName));
1464 List<ListenableFuture<Void>> futures = new ArrayList<>();
1465 futures.add(writeOperTxn.submit());
1470 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1471 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1472 final String rd = vrfTableKey.getRouteDistinguisher();
1473 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1474 if (vpnInstance == null) {
1475 LOG.error("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1478 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1480 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1481 final java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1482 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
1483 String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnInstance.getVpnId());
1484 if (subnetRoute != null) {
1485 elanTag = subnetRoute.getElantag();
1486 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
1487 rd, vrfEntry.getDestPrefix(), elanTag);
1488 if (vpnToDpnList != null) {
1489 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1490 dataStoreCoordinator.enqueueJob("FIB-" + rd + "-" + vrfEntry.getDestPrefix(),
1492 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1494 for (final VpnToDpnList curDpn : vpnToDpnList) {
1496 makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry,
1497 vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW, tx);
1498 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1499 optionalLabel.ifPresent(label -> {
1500 makeLFibTableEntry(curDpn.getDpnId(), label, null,
1501 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1505 List<ListenableFuture<Void>> futures = new ArrayList<>();
1506 futures.add(tx.submit());
1510 optionalLabel.ifPresent(label -> {
1511 synchronized (label.toString().intern()) {
1512 LabelRouteInfo lri = getLabelRouteInfo(label);
1513 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
1514 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
1515 FibUtil.getVpnInstanceOpData(dataBroker, rd);
1516 String vpnInstanceName = "";
1517 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1518 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1520 boolean lriRemoved = this.deleteLabelRouteInfo(lri, vpnInstanceName, null);
1522 String parentRd = lri.getParentVpnRd();
1523 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1524 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1525 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {} as "
1526 + "labelRouteInfo cleared", label, rd,
1527 vrfEntry.getDestPrefix());
1530 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1531 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1532 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {}",
1533 label, rd, vrfEntry.getDestPrefix());
1539 if (installRouterFibEntries(vrfEntry, vpnToDpnList, vpnInstance.getVpnId(), NwConstants.DEL_FLOW)) {
1543 final List<BigInteger> localDpnIdList = deleteLocalFibEntry(vpnInstance.getVpnId(),
1544 vrfTableKey.getRouteDistinguisher(), vrfEntry);
1545 if (vpnToDpnList != null) {
1546 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker,
1547 vpnInstance.getVpnId(), vrfEntry.getDestPrefix());
1548 String usedRd = null;
1549 Optional<Routes> extraRouteOptional;
1550 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
1551 if (usedRds != null && !usedRds.isEmpty()) {
1552 if (usedRds.size() > 1) {
1553 LOG.error("The extra route prefix is still present in some DPNs");
1556 // The first rd is retrieved from usedrds as Only 1 rd would be present as extra route prefix
1557 //is not present in any other DPN
1558 extraRouteOptional = VpnExtraRouteHelper
1559 .getVpnExtraroutes(dataBroker, vpnName, usedRds.get(0), vrfEntry.getDestPrefix());
1562 extraRouteOptional = Optional.absent();
1564 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1565 dataStoreCoordinator.enqueueJob("FIB-" + usedRd + "-" + vrfEntry.getDestPrefix(),
1567 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1569 if (localDpnIdList.size() <= 0) {
1570 for (VpnToDpnList curDpn : vpnToDpnList) {
1571 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1572 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1573 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(),
1574 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, tx);
1577 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(),
1578 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, tx);
1582 for (BigInteger localDpnId : localDpnIdList) {
1583 for (VpnToDpnList curDpn : vpnToDpnList) {
1584 if (!curDpn.getDpnId().equals(localDpnId)) {
1585 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1586 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1587 deleteRemoteRoute(localDpnId, curDpn.getDpnId(),
1588 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, tx);
1591 deleteRemoteRoute(localDpnId, curDpn.getDpnId(),
1592 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, tx);
1598 List<ListenableFuture<Void>> futures = new ArrayList<>();
1599 futures.add(tx.submit());
1604 //The flow/group entry has been deleted from config DS; need to clean up associated operational
1605 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
1606 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
1608 // Remove all fib entries configured due to interVpnLink, when nexthop is the opposite endPoint
1609 // of the interVpnLink.
1610 Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(this.dataBroker, rd);
1611 if (optVpnUuid.isPresent()) {
1612 String vpnUuid = optVpnUuid.get();
1613 FibUtil.getFirstNextHopAddress(vrfEntry).ifPresent(routeNexthop -> {
1614 Optional<InterVpnLinkDataComposite> optInterVpnLink =
1615 InterVpnLinkCache.getInterVpnLinkByVpnId(vpnUuid);
1616 if (optInterVpnLink.isPresent()) {
1617 InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
1618 if (interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid)) {
1619 // This is route that points to the other endpoint of an InterVpnLink
1620 // In that case, we should look for the FIB table pointing to
1621 // LPortDispatcher table and remove it.
1622 removeInterVPNLinkRouteFlows(interVpnLink.getInterVpnLinkName(),
1623 interVpnLink.isFirstEndpointVpnName(rd),
1633 Please note that the following deleteFibEntries will be invoked only for BGP Imported Routes.
1634 The invocation of the following method is via delete() callback from the MDSAL Batching Infrastructure
1635 provided by ResourceBatchingManager
1637 private void deleteFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> identifier,
1638 final VrfEntry vrfEntry) {
1639 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1640 String rd = vrfTableKey.getRouteDistinguisher();
1641 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1642 if (vpnInstance == null) {
1643 LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1646 String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnInstance.getVpnId());
1647 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1648 if (vpnToDpnList != null) {
1649 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker,
1650 vpnInstance.getVpnId(), vrfEntry.getDestPrefix());
1651 Optional<Routes> extraRouteOptional;
1652 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
1653 if (usedRds != null && !usedRds.isEmpty()) {
1654 if (usedRds.size() > 1) {
1655 LOG.error("The extra route prefix is still present in some DPNs");
1658 extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, vpnName,
1659 usedRds.get(0), vrfEntry.getDestPrefix());
1662 extraRouteOptional = Optional.absent();
1664 for (VpnToDpnList curDpn : vpnToDpnList) {
1665 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1666 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey,
1667 vrfEntry, extraRouteOptional, writeTx);
1673 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
1674 final long vpnId, final VrfTablesKey vrfTableKey,
1675 final VrfEntry vrfEntry, Optional<Routes> extraRouteOptional, WriteTransaction tx) {
1677 Boolean wrTxPresent = true;
1679 wrTxPresent = false;
1680 tx = dataBroker.newWriteOnlyTransaction();
1683 LOG.debug("deleting remote route: prefix={}, vpnId={} localDpnId {} remoteDpnId {}",
1684 vrfEntry.getDestPrefix(), vpnId, localDpnId, remoteDpnId);
1685 String rd = vrfTableKey.getRouteDistinguisher();
1687 if (localDpnId != null && localDpnId != BigInteger.ZERO) {
1688 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
1689 if (extraRouteOptional.isPresent()) {
1690 nextHopManager.setupLoadBalancingNextHop(vpnId, remoteDpnId, vrfEntry.getDestPrefix(), null , false);
1692 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1696 // below two reads are kept as is, until best way is found to identify dpnID
1697 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
1698 if (extraRouteOptional.isPresent()) {
1699 nextHopManager.setupLoadBalancingNextHop(vpnId, remoteDpnId, vrfEntry.getDestPrefix(), null , false);
1701 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1708 private boolean checkDpnDeleteFibEntry(VpnNexthop localNextHopInfo, BigInteger remoteDpnId, long vpnId,
1709 VrfEntry vrfEntry, String rd, WriteTransaction tx) {
1710 boolean isRemoteRoute = true;
1711 if (localNextHopInfo != null) {
1712 isRemoteRoute = !remoteDpnId.equals(localNextHopInfo.getDpnId());
1714 if (isRemoteRoute) {
1715 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1718 LOG.debug("Did not delete FIB entry: rd={}, vrfEntry={}, as it is local to dpnId={}",
1719 rd, vrfEntry.getDestPrefix(), remoteDpnId);
1724 private void deleteFibEntry(BigInteger remoteDpnId, long vpnId, VrfEntry vrfEntry,
1725 String rd, WriteTransaction tx) {
1726 // When the tunnel is removed the fib entries should be reprogrammed/deleted depending on
1727 // the adjacencyResults.
1728 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1729 List<AdjacencyResult> adjacencyResults = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
1730 if (!adjacencyResults.isEmpty()) {
1731 programRemoteFibForBgpRoutes(remoteDpnId, vpnId, vrfEntry, tx, rd, adjacencyResults);
1735 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1736 LOG.debug("Successfully delete FIB entry: vrfEntry={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
1739 private long get(byte[] rawIpAddress) {
1740 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
1741 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
1744 void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
1745 List<InstructionInfo> instructions, int addOrRemove, WriteTransaction tx) {
1746 Boolean wrTxPresent = true;
1748 wrTxPresent = false;
1749 tx = dataBroker.newWriteOnlyTransaction();
1752 LOG.trace("makeConnectedRoute: vrfEntry {}", vrfEntry);
1753 String[] values = vrfEntry.getDestPrefix().split("/");
1754 String ipAddress = values[0];
1755 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
1756 if (addOrRemove == NwConstants.ADD_FLOW) {
1757 LOG.debug("Adding route to DPN {} for rd {} prefix {} ", dpId, rd, vrfEntry.getDestPrefix());
1759 LOG.debug("Removing route from DPN {} for rd {} prefix {}", dpId, rd, vrfEntry.getDestPrefix());
1761 InetAddress destPrefix;
1763 destPrefix = InetAddress.getByName(ipAddress);
1764 } catch (UnknownHostException e) {
1765 LOG.error("Failed to get destPrefix for prefix {} ", vrfEntry.getDestPrefix(), e);
1769 List<MatchInfo> matches = new ArrayList<>();
1771 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
1773 if (destPrefix instanceof Inet4Address) {
1774 matches.add(MatchEthernetType.IPV4);
1775 if (prefixLength != 0) {
1776 matches.add(new MatchIpv4Destination(destPrefix.getHostAddress(), Integer.toString(prefixLength)));
1779 matches.add(MatchEthernetType.IPV6);
1780 if (prefixLength != 0) {
1781 matches.add(new MatchIpv6Destination(destPrefix.getHostAddress() + "/" + prefixLength));
1785 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
1786 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, priority, destPrefix);
1787 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef, priority,
1789 COOKIE_VM_FIB_TABLE, matches, instructions);
1790 Flow flow = flowEntity.getFlowBuilder().build();
1791 String flowId = flowEntity.getFlowId();
1792 FlowKey flowKey = new FlowKey(new FlowId(flowId));
1793 Node nodeDpn = buildDpnNode(dpId);
1795 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1796 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1797 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1799 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1800 SubTransaction subTransaction = new SubTransactionImpl();
1801 if (addOrRemove == NwConstants.ADD_FLOW) {
1802 subTransaction.setInstanceIdentifier(flowInstanceId);
1803 subTransaction.setInstance(flow);
1804 subTransaction.setAction(SubTransaction.CREATE);
1806 subTransaction.setInstanceIdentifier(flowInstanceId);
1807 subTransaction.setAction(SubTransaction.DELETE);
1809 transactionObjects.add(subTransaction);
1812 if (addOrRemove == NwConstants.ADD_FLOW) {
1813 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
1815 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1823 //TODO: How to handle the below code, its a copy paste from MDSALManager.java
1824 Node buildDpnNode(BigInteger dpnId) {
1825 NodeId nodeId = new NodeId("openflow:" + dpnId);
1826 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
1831 private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions, int priority,
1832 int addOrRemove, WriteTransaction tx) {
1833 Boolean wrTxPresent = true;
1835 wrTxPresent = false;
1836 tx = dataBroker.newWriteOnlyTransaction();
1839 List<MatchInfo> matches = new ArrayList<>();
1840 matches.add(MatchEthernetType.MPLS_UNICAST);
1841 matches.add(new MatchMplsLabel(label));
1843 // Install the flow entry in L3_LFIB_TABLE
1844 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, priority);
1846 FlowEntity flowEntity;
1847 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef, priority, flowRef, 0, 0,
1848 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
1849 Flow flow = flowEntity.getFlowBuilder().build();
1850 String flowId = flowEntity.getFlowId();
1851 FlowKey flowKey = new FlowKey(new FlowId(flowId));
1852 Node nodeDpn = buildDpnNode(dpId);
1853 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1854 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1855 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1857 if (addOrRemove == NwConstants.ADD_FLOW) {
1858 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
1860 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1866 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} : key {} {} successfully",
1867 dpId, label, instructions, flowKey, (NwConstants.ADD_FLOW == addOrRemove) ? "ADDED" : "REMOVED");
1870 void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress,
1871 final String ipPrefixAddress) {
1872 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}", dpId, vpnId, ipAddress);
1874 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress, ipPrefixAddress);
1875 } catch (NullPointerException e) {
1880 public void populateFibOnNewDpn(final BigInteger dpnId, final long vpnId, final String rd,
1881 final FutureCallback<List<Void>> callback) {
1882 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
1883 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1884 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1885 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1886 if (!vrfTable.isPresent()) {
1887 LOG.warn("VRF Table not yet available for RD {}", rd);
1888 if (callback != null) {
1889 List<ListenableFuture<Void>> futures = new ArrayList<>();
1890 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1891 Futures.addCallback(listenableFuture, callback);
1895 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1896 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1898 List<ListenableFuture<Void>> futures = new ArrayList<>();
1899 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1900 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1901 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1902 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1903 if (subnetRoute != null) {
1904 long elanTag = subnetRoute.getElantag();
1905 installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
1908 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
1909 if (routerInt != null) {
1910 LOG.trace("Router augmented vrfentry found rd:{}, uuid:{}, ip:{}, mac:{}",
1911 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
1912 installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(),
1913 routerInt.getIpAddress(),
1914 new MacAddress(routerInt.getMacAddress()), NwConstants.ADD_FLOW);
1917 //Handle local flow creation for imports
1918 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
1919 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1920 if (optionalLabel.isPresent()) {
1921 List<String> nextHopList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
1922 LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get());
1923 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList, lri)) {
1924 if (lri.getDpnId().equals(dpnId)) {
1925 createLocalFibEntry(vpnId, rd, vrfEntry);
1932 boolean shouldCreateRemoteFibEntry = shouldCreateFibEntryForVrfAndVpnIdOnDpn(vpnId,
1934 if (shouldCreateRemoteFibEntry) {
1935 LOG.trace("Will create remote FIB entry for vrfEntry {} on DPN {}",
1937 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1940 //TODO: if we have 100K entries in FIB, can it fit in one Tranasaction (?)
1941 futures.add(tx.submit());
1943 if (callback != null) {
1944 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1945 Futures.addCallback(listenableFuture, callback);
1951 public void populateExternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1952 final String localNextHopIp, final String remoteNextHopIp) {
1953 LOG.trace("populateExternalRoutesOnDpn : dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} ",
1954 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1955 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1956 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1957 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1958 if (vrfTable.isPresent()) {
1959 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1960 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1962 List<ListenableFuture<Void>> futures = new ArrayList<>();
1963 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1964 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
1965 vrfTable.get().getVrfEntry().stream()
1966 .filter(vrfEntry -> RouteOrigin.BGP == RouteOrigin.value(vrfEntry.getOrigin()))
1968 getConsumerForCreatingRemoteFib(dpnId, vpnId,
1969 rd, remoteNextHopIp, vrfTable,
1971 futures.add(writeCfgTxn.submit());
1978 public void populateInternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1979 final String localNextHopIp, final String remoteNextHopIp) {
1980 LOG.trace("populateInternalRoutesOnDpn : dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} ",
1981 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1982 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1983 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1984 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1985 if (vrfTable.isPresent()) {
1986 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1987 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1989 List<ListenableFuture<Void>> futures = new ArrayList<>();
1990 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1991 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
1992 // Handle Vpn Interface driven Routes only (i.e., STATIC and LOCAL)
1993 vrfTable.get().getVrfEntry().stream()
1994 .filter(vrfEntry -> {
1995 /* Ignore SubnetRoute entry */
1996 return (FibHelper.isControllerManagedVpnInterfaceRoute(RouteOrigin.value(
1997 vrfEntry.getOrigin())));
1999 .forEach(getConsumerForCreatingRemoteFib(dpnId, vpnId,
2000 rd, remoteNextHopIp, vrfTable,
2002 futures.add(writeCfgTxn.submit());
2009 public void manageRemoteRouteOnDPN(final boolean action,
2010 final BigInteger localDpnId,
2013 final String destPrefix,
2014 final String destTepIp,
2016 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
2018 if (vpnInstance == null) {
2019 LOG.error("VpnInstance for rd {} not present for prefix {}", rd, destPrefix);
2022 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
2023 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + localDpnId.toString(),
2025 List<ListenableFuture<Void>> futures = new ArrayList<>();
2026 synchronized (vpnInstance.getVpnInstanceName().intern()) {
2027 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
2028 VrfTablesKey vrfTablesKey = new VrfTablesKey(rd);
2029 VrfEntry vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
2030 if (vrfEntry == null) {
2033 LOG.trace("manageRemoteRouteOnDPN :: action {}, DpnId {}, vpnId {}, rd {}, destPfx {}",
2034 action, localDpnId, vpnId, rd, destPrefix);
2035 List<RoutePaths> routePathList = vrfEntry.getRoutePaths();
2036 VrfEntry modVrfEntry;
2037 if (routePathList == null || (routePathList.isEmpty())) {
2038 modVrfEntry = FibHelper.getVrfEntryBuilder(vrfEntry, label,
2039 Collections.singletonList(destTepIp),
2040 RouteOrigin.value(vrfEntry.getOrigin()), null /* parentVpnRd */).build();
2042 modVrfEntry = vrfEntry;
2045 if (action == true) {
2046 LOG.trace("manageRemoteRouteOnDPN updated(add) vrfEntry :: {}", modVrfEntry);
2047 createRemoteFibEntry(localDpnId, vpnId, vrfTablesKey, modVrfEntry, writeTransaction);
2049 LOG.trace("manageRemoteRouteOnDPN updated(remove) vrfEntry :: {}", modVrfEntry);
2050 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnInstance.getVpnId(),
2051 vrfEntry.getDestPrefix());
2052 if (usedRds.size() > 1) {
2053 LOG.debug("The extra route prefix is still present in some DPNs");
2056 //Is this fib route an extra route? If yes, get the nexthop which would be
2057 //an adjacency in the vpn
2058 Optional<Routes> extraRouteOptional = Optional.absent();
2059 if (usedRds.size() != 0) {
2060 extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker,
2061 FibUtil.getVpnNameFromId(dataBroker, vpnInstance.getVpnId()),
2062 usedRds.get(0), vrfEntry.getDestPrefix());
2064 deleteRemoteRoute(null, localDpnId, vpnId, vrfTablesKey, modVrfEntry,
2065 extraRouteOptional, writeTransaction);
2067 futures.add(writeTransaction.submit());
2073 public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd,
2074 final FutureCallback<List<Void>> callback) {
2075 LOG.trace("cleanUpDpnForVpn: Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
2076 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
2077 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
2078 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2079 if (vrfTable.isPresent()) {
2080 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
2081 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
2083 List<ListenableFuture<Void>> futures = new ArrayList<>();
2084 synchronized (vpnInstance.getVpnInstanceName().intern()) {
2085 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
2086 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
2087 /* Handle subnet routes here */
2088 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
2089 if (subnetRoute != null) {
2090 LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn",
2091 vrfEntry.getDestPrefix(),
2093 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
2094 java.util.Optional.ofNullable(vrfEntry.getRoutePaths()).ifPresent(routePaths -> {
2095 routePaths.stream().forEach(routePath -> {
2096 makeLFibTableEntry(dpnId, routePath.getLabel(), null,
2097 DEFAULT_FIB_FLOW_PRIORITY,
2098 NwConstants.DEL_FLOW, tx);
2099 LOG.trace("cleanUpDpnForVpn: Released subnetroute label {} "
2100 + "for rd {} prefix {}",
2101 routePath.getLabel(), rd,
2102 vrfEntry.getDestPrefix());
2107 // ping responder for router interfaces
2108 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
2109 if (routerInt != null) {
2110 LOG.trace("Router augmented vrfentry found for rd:{}, uuid:{}, ip:{}, mac:{}",
2111 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
2112 installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(),
2113 routerInt.getIpAddress(),
2114 new MacAddress(routerInt.getMacAddress()), NwConstants.DEL_FLOW);
2117 // Passing null as we don't know the dpn
2118 // to which prefix is attached at this point
2119 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnInstance.getVpnId(),
2120 vrfEntry.getDestPrefix());
2121 String vpnName = FibUtil.getVpnNameFromId(dataBroker, vpnInstance.getVpnId());
2122 Optional<Routes> extraRouteOptional;
2123 //Is this fib route an extra route? If yes, get the nexthop which would be
2124 //an adjacency in the vpn
2125 if (usedRds != null && !usedRds.isEmpty()) {
2126 if (usedRds.size() > 1) {
2127 LOG.error("The extra route prefix is still present in some DPNs");
2130 extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, vpnName,
2131 usedRds.get(0), vrfEntry.getDestPrefix());
2135 extraRouteOptional = Optional.absent();
2137 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry,
2138 extraRouteOptional, tx);
2140 futures.add(tx.submit());
2141 if (callback != null) {
2142 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
2143 Futures.addCallback(listenableFuture, callback);
2151 public void cleanUpExternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
2152 final String localNextHopIp, final String remoteNextHopIp) {
2153 LOG.trace("cleanUpExternalRoutesOnDpn : cleanup remote routes on dpn {} for vpn {}, rd {}, "
2154 + " localNexthopIp {} , remoteNexhtHopIp {}",
2155 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
2156 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
2157 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
2158 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2159 if (vrfTable.isPresent()) {
2160 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
2161 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
2163 List<ListenableFuture<Void>> futures = new ArrayList<>();
2164 synchronized (vpnInstance.getVpnInstanceName().intern()) {
2165 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
2166 vrfTable.get().getVrfEntry().stream()
2167 .filter(vrfEntry -> RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP)
2168 .forEach(getConsumerForDeletingRemoteFib(dpnId, vpnId, rd,
2169 remoteNextHopIp, vrfTable, writeCfgTxn));
2170 futures.add(writeCfgTxn.submit());
2177 public void cleanUpInternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
2178 final String localNextHopIp, final String remoteNextHopIp) {
2179 LOG.trace("cleanUpInternalRoutesOnDpn : cleanup remote routes on dpn {} for vpn {}, rd {}, "
2180 + " localNexthopIp {} , remoteNexhtHopIp {}",
2181 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
2182 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
2183 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
2184 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2185 if (vrfTable.isPresent()) {
2186 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
2187 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
2189 List<ListenableFuture<Void>> futures = new ArrayList<>();
2190 synchronized (vpnInstance.getVpnInstanceName().intern()) {
2191 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
2192 vrfTable.get().getVrfEntry().stream()
2193 .filter(vrfEntry -> {
2194 /* Ignore SubnetRoute entry */
2195 return (FibHelper.isControllerManagedVpnInterfaceRoute(
2196 RouteOrigin.value(vrfEntry.getOrigin())));
2198 .forEach(getConsumerForDeletingRemoteFib(dpnId, vpnId,
2199 rd, remoteNextHopIp, vrfTable, writeCfgTxn));
2200 futures.add(writeCfgTxn.submit());
2207 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
2208 InstanceIdentifierBuilder<VrfTables> idBuilder =
2209 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
2210 InstanceIdentifier<VrfTables> id = idBuilder.build();
2214 private String getFlowRef(BigInteger dpnId, short tableId, long label, int priority) {
2215 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + label
2216 + NwConstants.FLOWID_SEPARATOR + priority;
2219 private String getFlowRef(BigInteger dpnId, short tableId, String rd, int priority, InetAddress destPrefix) {
2220 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + rd
2221 + NwConstants.FLOWID_SEPARATOR + priority + NwConstants.FLOWID_SEPARATOR + destPrefix.getHostAddress();
2224 private String getInterVpnFibFlowRef(String interVpnLinkName, String prefix, String nextHop) {
2225 return FLOWID_PREFIX + interVpnLinkName + NwConstants.FLOWID_SEPARATOR + prefix + NwConstants
2226 .FLOWID_SEPARATOR + nextHop;
2229 protected List<AdjacencyResult> resolveAdjacency(final BigInteger remoteDpnId, final long vpnId,
2230 final VrfEntry vrfEntry, String rd) {
2231 List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
2232 FibHelper.sortIpAddress(routePaths);
2233 List<AdjacencyResult> adjacencyList = new ArrayList<>();
2234 List<String> prefixIpList = new ArrayList<>();
2235 LOG.trace("resolveAdjacency called with remotedDpnId {}, vpnId{}, VrfEntry {}",
2236 remoteDpnId, vpnId, vrfEntry);
2238 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
2239 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
2240 List<Routes> vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker,
2241 FibUtil.getVpnNameFromId(dataBroker, vpnId), usedRds, vrfEntry.getDestPrefix());
2242 if (vpnExtraRoutes.isEmpty()) {
2243 prefixIpList = Collections.singletonList(vrfEntry.getDestPrefix());
2245 List<String> prefixIpListLocal = new ArrayList<>();
2246 vpnExtraRoutes.stream().forEach(route -> {
2247 route.getNexthopIpList().stream().forEach(extraRouteIp -> {
2248 prefixIpListLocal.add(extraRouteIp + NwConstants.IPV4PREFIX);
2251 prefixIpList = prefixIpListLocal;
2254 prefixIpList = Collections.singletonList(vrfEntry.getDestPrefix());
2257 for (String prefixIp : prefixIpList) {
2258 if (routePaths == null || routePaths.isEmpty()) {
2259 LOG.trace("Processing Destination IP {} without NextHop IP", prefixIp);
2260 AdjacencyResult adjacencyResult = nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId,
2262 addAdjacencyResultToList(adjacencyList, adjacencyResult);
2265 adjacencyList.addAll(routePaths.stream()
2267 LOG.debug("NextHop IP for destination {} is {}", prefixIp,
2268 routePath.getNexthopAddress());
2269 return nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId,
2270 prefixIp, routePath.getNexthopAddress());
2272 .filter(adjacencyResult -> adjacencyResult != null && !adjacencyList.contains(adjacencyResult))
2274 .collect(toList()));
2276 } catch (NullPointerException e) {
2279 return adjacencyList;
2282 private void addAdjacencyResultToList(List<AdjacencyResult> adjacencyList, AdjacencyResult adjacencyResult) {
2283 if (adjacencyResult != null && !adjacencyList.contains(adjacencyResult)) {
2284 adjacencyList.add(adjacencyResult);
2288 protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
2289 InstanceIdentifier<VpnInstanceOpDataEntry> id =
2290 InstanceIdentifier.create(VpnInstanceOpData.class)
2291 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
2292 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData =
2293 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
2294 return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null;
2297 private String getTableMissFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
2298 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR
2299 + tableMiss + FLOWID_PREFIX;
2303 * Install flow entry in protocol table to forward mpls
2304 * coming through gre tunnel to LFIB table.
2306 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
2307 final BigInteger cookieProtocolTable = new BigInteger("1070000", 16);
2308 // Instruction to goto L3 InterfaceTable
2309 List<InstructionInfo> instructions = new ArrayList<>();
2310 instructions.add(new InstructionGotoTable(NwConstants.L3_LFIB_TABLE));
2311 List<MatchInfo> matches = new ArrayList<>();
2312 matches.add(MatchEthernetType.MPLS_UNICAST);
2313 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2314 getTableMissFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2315 NwConstants.L3_LFIB_TABLE),
2316 DEFAULT_FIB_FLOW_PRIORITY,
2317 "Protocol Table For LFIB",
2319 cookieProtocolTable,
2320 matches, instructions);
2322 if (addOrRemove == NwConstants.ADD_FLOW) {
2323 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
2324 mdsalManager.installFlow(flowEntityToLfib);
2326 mdsalManager.removeFlow(flowEntityToLfib);
2330 public List<String> printFibEntries() {
2331 List<String> result = new ArrayList<>();
2332 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s", "RD", "Prefix", "NextHop", "Label", "Origin"));
2333 result.add("-------------------------------------------------------------------");
2334 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
2335 Optional<FibEntries> fibEntries = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2336 if (fibEntries.isPresent()) {
2337 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
2338 for (VrfTables vrfTable : vrfTables) {
2339 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
2340 List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
2341 for (RoutePaths routePath : routePaths) {
2342 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s",
2343 vrfTable.getRouteDistinguisher(),
2344 vrfEntry.getDestPrefix(), routePath.getNexthopAddress(),
2345 routePath.getLabel(), vrfEntry.getOrigin()));
2347 if (routePaths.isEmpty()) {
2348 result.add(String.format(" %-7s %-20s %-20s %-7s",
2349 vrfTable.getRouteDistinguisher(),
2350 vrfEntry.getDestPrefix(), "local", vrfEntry.getOrigin()));
2359 private VrfEntry getVrfEntry(DataBroker broker, String rd, String ipPrefix) {
2360 InstanceIdentifier<VrfEntry> vrfEntryId = InstanceIdentifier.builder(FibEntries.class)
2361 .child(VrfTables.class, new VrfTablesKey(rd))
2362 .child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2363 Optional<VrfEntry> vrfEntry = read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
2364 if (vrfEntry.isPresent()) {
2365 return vrfEntry.get();
2370 private InstanceIdentifier<VrfEntry> getVrfEntryId(String rd, String ipPrefix) {
2371 InstanceIdentifier<VrfEntry> vrfEntryId = InstanceIdentifier.builder(FibEntries.class)
2372 .child(VrfTables.class, new VrfTablesKey(rd))
2373 .child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2377 protected Boolean isIpv4Address(String ipAddress) {
2379 InetAddress address = InetAddress.getByName(ipAddress);
2380 if (address instanceof Inet4Address) {
2383 } catch (UnknownHostException e) {
2384 LOG.warn("Invalid ip address {}", ipAddress, e);
2390 protected Boolean installRouterFibEntries(final VrfEntry vrfEntry, final Collection<VpnToDpnList> vpnToDpnList,
2391 long vpnId, int addOrRemove) {
2392 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
2393 if (routerInt == null) {
2396 if (vpnToDpnList != null) {
2397 String routerId = routerInt.getUuid();
2398 String macAddress = routerInt.getMacAddress();
2399 String ipValue = routerInt.getIpAddress();
2400 LOG.trace("createFibEntries - Router augmented vrfentry found for for router uuid:{}, ip:{}, mac:{}",
2401 routerId, ipValue, macAddress);
2402 for (VpnToDpnList vpnDpn : vpnToDpnList) {
2403 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
2404 installRouterFibEntry(vrfEntry, vpnDpn.getDpnId(), vpnId, routerId, ipValue,
2405 new MacAddress(macAddress), addOrRemove);
2412 public void installRouterFibEntry(final VrfEntry vrfEntry, BigInteger dpnId, long vpnId, String routerUuid,
2413 String routerInternalIp, MacAddress routerMac, int addOrRemove) {
2414 String[] subSplit = routerInternalIp.split("/");
2415 if (!isIpv4Address(subSplit[0])) {
2416 // Ping responder using OpenFlow rules is only supported for IPv4, hence skipping.
2420 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
2421 if (!optionalLabel.isPresent()) {
2422 LOG.warn("Routes paths not present. Exiting installRouterFibEntry");
2425 String addRemoveStr = (addOrRemove == NwConstants.ADD_FLOW) ? "ADD_FLOW" : "DELETE_FLOW";
2426 LOG.trace("{}: bulding Echo Flow entity for dpid:{}, router_ip:{}, vpnId:{}, subSplit:{} ", addRemoveStr,
2427 dpnId, routerInternalIp, vpnId, subSplit[0]);
2429 List<MatchInfo> matches = new ArrayList<>();
2431 matches.add(MatchIpProtocol.ICMP);
2432 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
2433 matches.add(new MatchIcmpv4((short) 8, (short) 0));
2434 matches.add(MatchEthernetType.IPV4);
2435 matches.add(new MatchIpv4Destination(subSplit[0], "32"));
2437 List<ActionInfo> actionsInfos = new ArrayList<>();
2439 // Set Eth Src and Eth Dst
2440 actionsInfos.add(new ActionMoveSourceDestinationEth());
2441 actionsInfos.add(new ActionSetFieldEthernetSource(routerMac));
2443 // Move Ip Src to Ip Dst
2444 actionsInfos.add(new ActionMoveSourceDestinationIp());
2445 actionsInfos.add(new ActionSetSourceIp(subSplit[0], "32"));
2447 // Set the ICMP type to 0 (echo reply)
2448 actionsInfos.add(new ActionSetIcmpType((short) 0));
2450 actionsInfos.add(new ActionNxLoadInPort(BigInteger.ZERO));
2452 actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
2454 List<InstructionInfo> instructions = new ArrayList<>();
2456 instructions.add(new InstructionApplyActions(actionsInfos));
2458 int priority = FibConstants.DEFAULT_FIB_FLOW_PRIORITY + FibConstants.DEFAULT_PREFIX_LENGTH;
2459 String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, optionalLabel.get(),
2462 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef,
2463 0, 0, NwConstants.COOKIE_VM_FIB_TABLE, matches, instructions);
2465 if (addOrRemove == NwConstants.ADD_FLOW) {
2466 mdsalManager.installFlow(flowEntity);
2468 mdsalManager.removeFlow(flowEntity);
2472 public void removeInterVPNLinkRouteFlows(final String interVpnLinkName,
2473 final boolean isVpnFirstEndPoint,
2474 final VrfEntry vrfEntry) {
2475 Preconditions.checkArgument(vrfEntry.getRoutePaths() != null
2476 && vrfEntry.getRoutePaths().size() == 1);
2477 Optional<InterVpnLinkState> interVpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLinkName);
2479 if (!interVpnLinkState.isPresent()) {
2480 LOG.warn("Could not find State for InterVpnLink {}", interVpnLinkName);
2484 List<BigInteger> targetDpns =
2485 isVpnFirstEndPoint ? interVpnLinkState.get().getFirstEndpointState().getDpId()
2486 : interVpnLinkState.get().getSecondEndpointState().getDpId();
2488 java.util.Optional<String> optionalNextHop = FibUtil.getFirstNextHopAddress(vrfEntry);
2489 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
2493 optionalNextHop.ifPresent(nextHop -> {
2494 String flowRef = getInterVpnFibFlowRef(interVpnLinkName, vrfEntry.getDestPrefix(), nextHop);
2495 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
2496 Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef))
2497 .setTableId(NwConstants.L3_FIB_TABLE).setFlowName(flowRef).build();
2499 LOG.trace("Removing flow in FIB table for interVpnLink {} key {}",
2500 interVpnLinkName, flowRef);
2502 for (BigInteger dpId : targetDpns) {
2503 LOG.debug("Removing flow: VrfEntry=[prefix={} nexthop={}] dpn {} for InterVpnLink {} in FIB",
2504 vrfEntry.getDestPrefix(), nextHop,
2505 dpId, interVpnLinkName);
2507 mdsalManager.removeFlow(dpId, flow);
2513 optionalLabel.ifPresent(label -> {
2514 LOG.trace("Removing flow in FIB table for interVpnLink {}", interVpnLinkName);
2516 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
2517 for (BigInteger dpId : targetDpns) {
2518 LOG.debug("Removing flow: VrfEntry=[prefix={} label={}] dpn {} for InterVpnLink {} in LFIB",
2519 vrfEntry.getDestPrefix(), label,
2520 dpId, interVpnLinkName);
2521 makeLFibTableEntry(dpId, label, null /* no instructions */,
2522 LFIB_INTERVPN_PRIORITY, NwConstants.DEL_FLOW, tx);
2528 private Consumer<? super VrfEntry> getConsumerForCreatingRemoteFib(
2529 final BigInteger dpnId, final long vpnId, final String rd,
2530 final String remoteNextHopIp, final Optional<VrfTables> vrfTable,
2531 WriteTransaction writeCfgTxn) {
2532 return vrfEntry -> vrfEntry.getRoutePaths().stream()
2533 .filter(routes -> !routes.getNexthopAddress().isEmpty()
2534 && remoteNextHopIp.trim().equals(routes.getNexthopAddress().trim()))
2536 .ifPresent(routes -> {
2537 LOG.trace("creating remote FIB entry for prefix {} rd {} on Dpn {}",
2538 vrfEntry.getDestPrefix(), rd, dpnId);
2539 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeCfgTxn);
2543 private Consumer<? super VrfEntry> getConsumerForDeletingRemoteFib(
2544 final BigInteger dpnId, final long vpnId, final String rd,
2545 final String remoteNextHopIp, final Optional<VrfTables> vrfTable,
2546 WriteTransaction writeCfgTxn) {
2547 return vrfEntry -> vrfEntry.getRoutePaths().stream()
2548 .filter(routes -> !routes.getNexthopAddress().isEmpty()
2549 && remoteNextHopIp.trim().equals(routes.getNexthopAddress().trim()))
2551 .ifPresent(routes -> {
2552 LOG.trace(" deleting remote FIB entry {}", vrfEntry);
2553 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry,
2554 Optional.absent(), writeCfgTxn);
2558 private boolean isPrefixAndNextHopPresentInLri(String prefix,
2559 List<String> nextHopAddressList, LabelRouteInfo lri) {
2560 return lri != null && lri.getPrefix().equals(prefix)
2561 && nextHopAddressList.contains(lri.getNextHopIpList().get(0));
2564 private boolean shouldCreateFibEntryForVrfAndVpnIdOnDpn(Long vpnId, VrfEntry vrfEntry, BigInteger dpnId) {
2565 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
2569 Prefixes prefix = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
2570 if (prefix != null) {
2571 BigInteger prefixDpnId = prefix.getDpnId();
2572 if (prefixDpnId == dpnId) {
2573 LOG.trace("Should not create remote FIB entry for vrfEntry {} on DPN {}",
2582 private void programRemoteFibForBgpRoutes(final BigInteger remoteDpnId, final long vpnId,
2583 final VrfEntry vrfEntry, WriteTransaction tx, String rd, List<AdjacencyResult> adjacencyResults) {
2584 Preconditions.checkArgument(vrfEntry.getRoutePaths().size() <= 2);
2586 if (adjacencyResults.size() == 1) {
2587 programRemoteFib(remoteDpnId, vpnId, vrfEntry, tx, rd, adjacencyResults);
2590 // ECMP Use case, point to LB group. Move the mpls label accordingly.
2591 List<String> tunnelList =
2592 adjacencyResults.stream()
2593 .map(adjacencyResult -> adjacencyResult.getNextHopIp())
2594 .sorted().collect(toList());
2595 String lbGroupKey = FibUtil.getGreLbGroupKey(tunnelList);
2596 long groupId = nextHopManager.createNextHopPointer(lbGroupKey);
2598 List<ActionInfo> actionInfos = new ArrayList<>();
2599 for (AdjacencyResult adjResult : adjacencyResults) {
2600 String nextHopIp = adjResult.getNextHopIp();
2601 java.util.Optional<Long> optionalLabel = FibUtil.getLabelForNextHop(vrfEntry, nextHopIp);
2602 if (!optionalLabel.isPresent()) {
2603 LOG.warn("NextHopIp {} not found in vrfEntry {}", nextHopIp, vrfEntry);
2606 long label = optionalLabel.get();
2608 actionInfos.add(new ActionRegLoad(index, FibConstants.NXM_REG_MAPPING.get(index++), 0,
2611 List<InstructionInfo> instructions = new ArrayList<>();
2612 actionInfos.add(new ActionGroup(index, groupId));
2613 instructions.add(new InstructionApplyActions(actionInfos));
2614 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);