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 com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
16 import java.math.BigInteger;
17 import java.net.Inet4Address;
18 import java.net.InetAddress;
19 import java.net.UnknownHostException;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.concurrent.BlockingQueue;
26 import java.util.concurrent.Callable;
27 import java.util.concurrent.ExecutionException;
28 import java.util.concurrent.Future;
29 import java.util.concurrent.LinkedBlockingQueue;
30 import java.util.function.Consumer;
31 import java.util.stream.Collectors;
33 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
34 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
35 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
36 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
37 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
38 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
39 import org.opendaylight.genius.mdsalutil.ActionInfo;
40 import org.opendaylight.genius.mdsalutil.FlowEntity;
41 import org.opendaylight.genius.mdsalutil.InstructionInfo;
42 import org.opendaylight.genius.mdsalutil.MDSALUtil;
43 import org.opendaylight.genius.mdsalutil.MatchInfo;
44 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
45 import org.opendaylight.genius.mdsalutil.NwConstants;
46 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
47 import org.opendaylight.genius.mdsalutil.actions.ActionMoveSourceDestinationEth;
48 import org.opendaylight.genius.mdsalutil.actions.ActionMoveSourceDestinationIp;
49 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
50 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
51 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
52 import org.opendaylight.genius.mdsalutil.actions.ActionPushMpls;
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.intervpnlink.IVpnLinkService;
82 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
83 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
84 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
85 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
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.GetTunnelTypeInputBuilder;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetTunnelTypeOutput;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.vrfentry.RoutePaths;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthopBuilder;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroutes;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
124 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesBuilder;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
129 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;
130 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;
131 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;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.Vpn;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.VpnKey;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.ExtraRoutes;
135 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.ExtraRoutesKey;
136 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes;
137 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.RoutesKey;
138 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
139 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState.State;
140 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
141 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
142 import org.opendaylight.yangtools.yang.binding.DataObject;
143 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
144 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
145 import org.opendaylight.yangtools.yang.common.RpcResult;
146 import org.slf4j.Logger;
147 import org.slf4j.LoggerFactory;
149 public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry, VrfEntryListener>
150 implements AutoCloseable, ResourceHandler {
152 private static final Logger LOG = LoggerFactory.getLogger(VrfEntryListener.class);
153 private static final String FLOWID_PREFIX = "L3.";
154 private static final int BATCH_SIZE = 1000;
155 private static final int PERIODICITY = 500;
156 private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16);
157 private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
158 private static final int LFIB_INTERVPN_PRIORITY = 15;
159 public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
161 private final DataBroker dataBroker;
162 private final IMdsalApiManager mdsalManager;
163 private final NexthopManager nextHopManager;
164 private final OdlInterfaceRpcService interfaceManager;
165 private final IdManagerService idManager;
166 private final IVpnLinkService ivpnLinkService;
168 List<SubTransaction> transactionObjects;
170 private static Integer batchSize;
171 private static Integer batchInterval;
173 private static BlockingQueue<ActionableResource> vrfEntryBufferQ = new LinkedBlockingQueue<>();
174 private final ResourceBatchingManager resourceBatchingManager;
176 public VrfEntryListener(final DataBroker dataBroker, final IMdsalApiManager mdsalApiManager,
177 final NexthopManager nexthopManager, final OdlInterfaceRpcService interfaceManager,
178 final IdManagerService idManager, final IVpnLinkService ivpnLinkService) {
179 super(VrfEntry.class, VrfEntryListener.class);
180 this.dataBroker = dataBroker;
181 this.mdsalManager = mdsalApiManager;
182 this.nextHopManager = nexthopManager;
183 this.interfaceManager = interfaceManager;
184 this.idManager = idManager;
185 this.ivpnLinkService = ivpnLinkService;
187 batchSize = Integer.getInteger("batch.size", BATCH_SIZE);
188 batchInterval = Integer.getInteger("batch.wait.time", PERIODICITY);
189 resourceBatchingManager = ResourceBatchingManager.getInstance();
190 resourceBatchingManager.registerBatchableResource("FIB-VRFENTRY", vrfEntryBufferQ, this);
191 transactionObjects = new ArrayList<>();
194 public void start() {
195 LOG.info("{} start", getClass().getSimpleName());
196 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
200 protected VrfEntryListener getDataTreeChangeListener() {
201 return VrfEntryListener.this;
205 protected InstanceIdentifier<VrfEntry> getWildCardPath() {
206 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
210 public DataBroker getResourceBroker() {
215 protected void add(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
216 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
217 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
218 LOG.debug("ADD: Adding Fib Entry rd {} prefix {} route-paths {}",
219 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
220 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
221 createFibEntries(identifier, vrfEntry);
223 ActionableResource actResource = new ActionableResourceImpl(rd + vrfEntry.getDestPrefix());
224 actResource.setAction(ActionableResource.CREATE);
225 actResource.setInstanceIdentifier(identifier);
226 actResource.setInstance(vrfEntry);
227 vrfEntryBufferQ.add(actResource);
229 leakRouteIfNeeded(identifier, vrfEntry, NwConstants.ADD_FLOW);
230 LOG.info("ADD: Added Fib Entry rd {} prefix {} route-paths {}",
231 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
235 protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
236 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
237 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
238 LOG.debug("REMOVE: Removing Fib Entry rd {} prefix {} route-paths {}",
239 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
240 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
241 deleteFibEntries(identifier, vrfEntry);
243 ActionableResource actResource = new ActionableResourceImpl(rd + vrfEntry.getDestPrefix());
244 actResource.setAction(ActionableResource.DELETE);
245 actResource.setInstanceIdentifier(identifier);
246 actResource.setInstance(vrfEntry);
247 vrfEntryBufferQ.add(actResource);
249 leakRouteIfNeeded(identifier, vrfEntry, NwConstants.DEL_FLOW);
250 LOG.info("REMOVE: Removed Fib Entry rd {} prefix {} route-paths {}",
251 rd, vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths());
255 protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
256 Preconditions.checkNotNull(update, "VrfEntry should not be null or empty.");
258 final String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
259 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
260 LOG.debug("UPDATE: Updating Fib Entries to rd {} prefix {} route-paths {}",
261 rd, update.getDestPrefix(), update.getRoutePaths());
262 // Handle BGP Routes first
263 if (RouteOrigin.value(update.getOrigin()) == RouteOrigin.BGP) {
264 ActionableResource actResource = new ActionableResourceImpl(rd + update.getDestPrefix());
265 actResource.setAction(ActionableResource.UPDATE);
266 actResource.setInstanceIdentifier(identifier);
267 actResource.setInstance(update);
268 actResource.setOldInstance(original);
269 vrfEntryBufferQ.add(actResource);
270 LOG.info("UPDATE: Updated Fib Entries to rd {} prefix {} route-paths {}",
271 rd, update.getDestPrefix(), update.getRoutePaths());
275 // Handle Vpn Interface driven Routes next (ie., STATIC and LOCAL)
276 if (FibHelper.isControllerManagedVpnInterfaceRoute(RouteOrigin.value(update.getOrigin()))) {
277 List<RoutePaths> originalRoutePath = original.getRoutePaths();
278 List<RoutePaths> updateRoutePath = update.getRoutePaths();
279 LOG.info("UPDATE: Original route-path {} update route-path {} ", originalRoutePath, updateRoutePath);
281 // If original VRF Entry had nexthop null , but update VRF Entry
282 // has nexthop , route needs to be created on remote Dpns
283 if (((originalRoutePath == null) || (originalRoutePath.isEmpty())
284 && (updateRoutePath != null) && (!updateRoutePath.isEmpty()))) {
285 // TODO(vivek): Though ugly, Not handling this code now, as each
286 // tep add event will invoke flow addition
287 LOG.trace("Original VRF entry NH is null for destprefix {}. This event is IGNORED here.",
288 update.getDestPrefix());
292 // If original VRF Entry had valid nexthop , but update VRF Entry
293 // has nexthop empty'ed out, route needs to be removed from remote Dpns
294 if (((updateRoutePath == null) || (updateRoutePath.isEmpty())
295 && (originalRoutePath != null) && (!originalRoutePath.isEmpty()))) {
296 LOG.trace("Original VRF entry had valid NH for destprefix {}. This event is IGNORED here.",
297 update.getDestPrefix());
300 createFibEntries(identifier, update);
301 LOG.info("UPDATE: Updated Fib Entries to rd {} prefix {} route-paths {}",
302 rd, update.getDestPrefix(), update.getRoutePaths());
306 /* Handl all other route origins */
307 createFibEntries(identifier, update);
309 LOG.info("UPDATE: Updated Fib Entries to rd {} prefix {} route-paths {}",
310 rd, update.getDestPrefix(), update.getRoutePaths());
314 public void update(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier,
315 Object original, Object update, List<SubTransaction> transactionObjects) {
316 this.transactionObjects = transactionObjects;
317 if ((original instanceof VrfEntry) && (update instanceof VrfEntry)) {
318 createFibEntries(tx, identifier, (VrfEntry) update);
323 public void create(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier,
324 Object vrfEntry, List<SubTransaction> transactionObjects) {
325 this.transactionObjects = transactionObjects;
326 if (vrfEntry instanceof VrfEntry) {
327 createFibEntries(tx, identifier, (VrfEntry) vrfEntry);
332 public void delete(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier,
333 Object vrfEntry, List<SubTransaction> transactionObjects) {
334 this.transactionObjects = transactionObjects;
335 if (vrfEntry instanceof VrfEntry) {
336 deleteFibEntries(tx, identifier, (VrfEntry) vrfEntry);
341 public int getBatchSize() {
346 public int getBatchInterval() {
347 return batchInterval;
351 public LogicalDatastoreType getDatastoreType() {
352 return LogicalDatastoreType.CONFIGURATION;
355 private void createFibEntries(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
356 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
358 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
359 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
360 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId()
361 + " has null vpnId!");
363 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
364 final Long vpnId = vpnInstance.getVpnId();
365 final String rd = vrfTableKey.getRouteDistinguisher();
366 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
367 if (subnetRoute != null) {
368 final long elanTag = subnetRoute.getElantag();
369 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
370 rd, vrfEntry.getDestPrefix(), elanTag);
371 if (vpnToDpnList != null) {
372 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
373 dataStoreCoordinator.enqueueJob("FIB-" + rd + "-" + vrfEntry.getDestPrefix(),
375 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
376 for (final VpnToDpnList curDpn : vpnToDpnList) {
377 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
378 installSubnetRouteInFib(curDpn.getDpnId(), elanTag, rd, vpnId, vrfEntry, tx);
381 List<ListenableFuture<Void>> futures = new ArrayList<>();
382 futures.add(tx.submit());
388 // ping responder for router interfaces
389 if (installRouterFibEntries(vrfEntry, vpnToDpnList, vpnId, NwConstants.ADD_FLOW)) {
393 final List<BigInteger> localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry);
395 if (vpnToDpnList != null) {
396 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
397 dataStoreCoordinator.enqueueJob("FIB-" + rd + "-" + vrfEntry.getDestPrefix(),
399 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
400 for (VpnToDpnList vpnDpn : vpnToDpnList) {
401 if (!localDpnIdList.contains(vpnDpn.getDpnId())) {
402 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
403 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(),
404 vrfTableKey, vrfEntry, tx);
408 List<ListenableFuture<Void>> futures = new ArrayList<>();
409 futures.add(tx.submit());
414 Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(dataBroker, rd);
415 if (optVpnUuid.isPresent()) {
416 Optional<InterVpnLinkDataComposite> optInterVpnLink =
417 InterVpnLinkCache.getInterVpnLinkByVpnId(optVpnUuid.get());
418 LOG.debug("InterVpnLink {} found in Cache: {}", optVpnUuid.get(), optInterVpnLink.isPresent());
419 if (optInterVpnLink.isPresent()) {
420 InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
421 String vpnUuid = optVpnUuid.get();
422 FibUtil.getFirstNextHopAddress(vrfEntry).ifPresent(routeNexthop -> {
423 if (interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid)) {
424 // This is an static route that points to the other endpoint of an InterVpnLink
425 // In that case, we should add another entry in FIB table pointing to LPortDispatcher table.
426 installIVpnLinkSwitchingFlows(interVpnLink, vpnUuid, vrfEntry, vpnId);
427 installInterVpnRouteInLFib(rd, vrfEntry);
436 Please note that the following createFibEntries will be invoked only for BGP Imported Routes.
437 The invocation of the following method is via create() callback from the MDSAL Batching Infrastructure
438 provided by ResourceBatchingManager
440 private void createFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> vrfEntryIid,
441 final VrfEntry vrfEntry) {
442 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
444 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
445 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
446 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId()
447 + " has null vpnId!");
449 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
450 if (vpnToDpnList != null) {
451 for (VpnToDpnList vpnDpn : vpnToDpnList) {
452 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
453 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, writeTx);
459 // FIXME: Refactoring needed here.
460 // This kind of logic must be taken to an 'upper' layer like BgpManager or VpnManager
461 private void leakRouteIfNeeded(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry,
463 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
464 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
466 String prefix = vrfEntry.getDestPrefix();
467 List<String> nextHopsList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
468 // Label is used only for logging in subsequent method calls.
469 //TODO : This label is not needed here. Can be removed. Hence using a default value.
470 Long label = FibUtil.getLabelFromRoutePaths(vrfEntry).orElse(0L);
471 String rd = vrfTableKey.getRouteDistinguisher();
472 LOG.trace("leakRouteIfNeeded: srcVpnRd={} prefix={} nhList={} label={}", rd, prefix, nextHopsList, label);
474 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
475 if (vpnInstance == null) {
476 LOG.error("VPN Instance not available for route with prefix {} label {} nextHop {} RD {}. Returning...",
477 prefix, label, nextHopsList, rd);
480 String vpnUuid = vpnInstance.getVpnInstanceName();
481 if (vpnUuid == null || vpnUuid.isEmpty()) {
482 LOG.warn("Could not find suitable VPN UUID for rd={}. vrfEntry=[prefix={} nhList={} label={}]",
483 rd, prefix, nextHopsList, label);
487 ivpnLinkService.leakRouteIfNeeded(vpnUuid, prefix, nextHopsList, label.intValue(),
488 RouteOrigin.value(vrfEntry.getOrigin()), addOrRemove);
491 private Prefixes updateVpnReferencesInLri(LabelRouteInfo lri, String vpnInstanceName, boolean isPresentInList) {
492 LOG.debug("updating LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
493 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
494 prefixBuilder.setDpnId(lri.getDpnId());
495 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
496 prefixBuilder.setIpAddress(lri.getPrefix());
497 // Increment the refCount here
498 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
499 .child(LabelRouteInfo.class, new LabelRouteInfoKey(lri.getLabel())).build();
500 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri);
501 if (!isPresentInList) {
502 LOG.debug("vpnName {} is not present in LRI with label {}..", vpnInstanceName, lri.getLabel());
503 List<String> vpnInstanceNames = lri.getVpnInstanceList();
504 vpnInstanceNames.add(vpnInstanceName);
505 builder.setVpnInstanceList(vpnInstanceNames);
506 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(),
507 FibUtil.DEFAULT_CALLBACK);
509 LOG.debug("vpnName {} is present in LRI with label {}..", vpnInstanceName, lri.getLabel());
511 return prefixBuilder.build();
514 private void installSubnetRouteInFib(final BigInteger dpnId, final long elanTag, final String rd,
515 final long vpnId, final VrfEntry vrfEntry, WriteTransaction tx) {
516 Boolean wrTxPresent = true;
519 tx = dataBroker.newWriteOnlyTransaction();
521 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
522 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
523 synchronized (label.toString().intern()) {
524 LabelRouteInfo lri = getLabelRouteInfo(label);
525 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
527 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
528 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
529 FibUtil.getVpnInstanceOpData(dataBroker, rd);
530 if (vpnInstanceOpDataEntryOptional.isPresent()) {
531 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
532 if (!lri.getVpnInstanceList().contains(vpnInstanceName)) {
533 updateVpnReferencesInLri(lri, vpnInstanceName, false);
537 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
538 label, lri.getVpnInterfaceName(), lri.getDpnId());
542 final List<InstructionInfo> instructions = new ArrayList<>();
543 BigInteger subnetRouteMeta = ((BigInteger.valueOf(elanTag)).shiftLeft(32))
544 .or((BigInteger.valueOf(vpnId).shiftLeft(1)));
545 instructions.add(new InstructionWriteMetadata(subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE));
546 instructions.add(new InstructionGotoTable(NwConstants.L3_SUBNET_ROUTE_TABLE));
547 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
549 for (RoutePaths routePath : vrfEntry.getRoutePaths()) {
550 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
551 List<ActionInfo> actionsInfos = new ArrayList<>();
552 // reinitialize instructions list for LFIB Table
553 final List<InstructionInfo> LFIBinstructions = new ArrayList<>();
555 actionsInfos.add(new ActionPopMpls());
556 LFIBinstructions.add(new InstructionApplyActions(actionsInfos));
557 LFIBinstructions.add(new InstructionWriteMetadata(subnetRouteMeta,
558 MetaDataUtil.METADATA_MASK_SUBNET_ROUTE));
559 LFIBinstructions.add(new InstructionGotoTable(NwConstants.L3_SUBNET_ROUTE_TABLE));
561 makeLFibTableEntry(dpnId, routePath.getLabel(), LFIBinstructions, DEFAULT_FIB_FLOW_PRIORITY,
562 NwConstants.ADD_FLOW, tx);
571 * For a given route, it installs a flow in LFIB that sets the lportTag of the other endpoint and sends to
572 * LportDispatcher table (via table 80)
574 private void installInterVpnRouteInLFib(final String rd, final VrfEntry vrfEntry) {
575 // INTERVPN routes are routes in a Vpn1 that have been leaked to Vpn2. In DC-GW, this Vpn2 route is pointing
576 // to a list of DPNs where Vpn2's VpnLink was instantiated. In these DPNs LFIB must be programmed so that the
577 // packet is commuted from Vpn2 to Vpn1.
578 Optional<String> vpnNameOpc = FibUtil.getVpnNameFromRd(dataBroker, rd);
579 if (!vpnNameOpc.isPresent()) {
580 LOG.warn("Could not find VpnInstanceName for Route-Distinguisher {}", rd);
584 String vpnName = vpnNameOpc.get();
585 List<InterVpnLink> interVpnLinks = FibUtil.getAllInterVpnLinks(dataBroker);
586 boolean interVpnLinkFound = false;
587 for (InterVpnLink interVpnLink : interVpnLinks) {
588 boolean vpnIs1stEndpoint = interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName);
589 boolean vpnIs2ndEndpoint = !vpnIs1stEndpoint
590 && interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnName);
591 if (vpnIs1stEndpoint || vpnIs2ndEndpoint) {
592 interVpnLinkFound = true;
594 Optional<InterVpnLinkState> vpnLinkState =
595 FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName());
596 if (!vpnLinkState.isPresent()
597 || !vpnLinkState.get().getState().equals(InterVpnLinkState.State.Active)) {
598 LOG.warn("InterVpnLink {}, linking VPN {} and {}, is not in Active state",
599 interVpnLink.getName(), interVpnLink.getFirstEndpoint().getVpnUuid().getValue(),
600 interVpnLink.getSecondEndpoint().getVpnUuid().getValue());
604 List<BigInteger> targetDpns = vpnIs1stEndpoint ? vpnLinkState.get().getFirstEndpointState().getDpId()
605 : vpnLinkState.get().getSecondEndpointState().getDpId();
606 Long lportTag = vpnIs1stEndpoint ? vpnLinkState.get().getSecondEndpointState().getLportTag()
607 : vpnLinkState.get().getFirstEndpointState().getLportTag();
609 LOG.trace("Installing flow in LFIB table for interVpnLink {}", interVpnLink.getName());
611 for (BigInteger dpId : targetDpns) {
612 List<ActionInfo> actionsInfos = Collections.singletonList(new ActionPopMpls());
614 List<InstructionInfo> instructions =
615 Arrays.asList(new InstructionApplyActions(actionsInfos),
616 new InstructionWriteMetadata(
617 MetaDataUtil.getMetaDataForLPortDispatcher(lportTag.intValue(),
618 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
619 NwConstants.L3VPN_SERVICE_INDEX)),
620 MetaDataUtil.getMetaDataMaskForLPortDispatcher()),
621 new InstructionGotoTable(NwConstants.L3_INTERFACE_TABLE));
623 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(interVpnRoutePathLabel -> {
624 List<String> interVpnNextHopList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
625 LOG.debug("Installing flow: VrfEntry=[prefix={} label={} nexthop={}] dpn {} for "
626 + "InterVpnLink {} in LFIB",
627 vrfEntry.getDestPrefix(), interVpnRoutePathLabel, interVpnNextHopList,
628 dpId, interVpnLink.getName());
630 makeLFibTableEntry(dpId, interVpnRoutePathLabel, instructions, LFIB_INTERVPN_PRIORITY,
631 NwConstants.ADD_FLOW, null);
639 if (!interVpnLinkFound) {
640 LOG.warn("VrfEntry=[prefix={} route-paths={}] for VPN {} has origin INTERVPN but "
641 + "no InterVpnLink could be found",
642 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(), rd);
648 * Installs the flows in FIB table that, for a given route, do the switching from one VPN to the other.
650 private void installIVpnLinkSwitchingFlows(final InterVpnLinkDataComposite interVpnLink, final String vpnUuid,
651 final VrfEntry vrfEntry, long vpnTag) {
652 Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
653 Preconditions.checkArgument(vrfEntry.getRoutePaths() != null
654 && vrfEntry.getRoutePaths().size() == 1);
655 String destination = vrfEntry.getDestPrefix();
656 String nextHop = vrfEntry.getRoutePaths().get(0).getNexthopAddress();
657 String interVpnLinkName = interVpnLink.getInterVpnLinkName();
659 // After having received a static route, we should check if the vpn is part of an inter-vpn-link.
660 // In that case, we should populate the FIB table of the VPN pointing to LPortDisptacher table
661 // using as metadata the LPortTag associated to that vpn in the inter-vpn-link.
662 if (interVpnLink.getState().or(State.Error) != State.Active) {
663 LOG.warn("Route to {} with nexthop={} cannot be installed because the interVpnLink {} is not active",
664 destination, nextHop, interVpnLinkName);
668 Optional<Long> optOtherEndpointLportTag = interVpnLink.getOtherEndpointLportTagByVpnName(vpnUuid);
669 if (!optOtherEndpointLportTag.isPresent()) {
670 LOG.warn("Could not find suitable LportTag for the endpoint opposite to vpn {} in interVpnLink {}",
671 vpnUuid, interVpnLinkName);
675 List<BigInteger> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnUuid);
676 if (targetDpns.isEmpty()) {
677 LOG.warn("Could not find DPNs for endpoint opposite to vpn {} in interVpnLink {}",
678 vpnUuid, interVpnLinkName);
682 String[] values = destination.split("/");
683 String destPrefixIpAddress = values[0];
684 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
686 List<MatchInfo> matches = new ArrayList<>();
687 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnTag), MetaDataUtil.METADATA_MASK_VRFID));
688 matches.add(MatchEthernetType.IPV4);
690 if (prefixLength != 0) {
691 matches.add(new MatchIpv4Destination(destPrefixIpAddress, Integer.toString(prefixLength)));
694 List<Instruction> instructions =
695 Arrays.asList(new InstructionWriteMetadata(
696 MetaDataUtil.getMetaDataForLPortDispatcher(optOtherEndpointLportTag.get().intValue(),
697 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants
698 .L3VPN_SERVICE_INDEX)),
699 MetaDataUtil.getMetaDataMaskForLPortDispatcher()).buildInstruction(0),
700 new InstructionGotoTable(NwConstants.L3_INTERFACE_TABLE).buildInstruction(1));
702 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
703 String flowRef = getInterVpnFibFlowRef(interVpnLinkName, destination, nextHop);
704 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
705 COOKIE_VM_FIB_TABLE, matches, instructions);
707 LOG.trace("Installing flow in FIB table for vpn {} interVpnLink {} nextHop {} key {}",
708 vpnUuid, interVpnLink.getInterVpnLinkName(), nextHop, flowRef);
710 for (BigInteger dpId : targetDpns) {
712 LOG.debug("Installing flow: VrfEntry=[prefix={} route-paths={}] dpn {} for InterVpnLink {} in FIB",
713 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(),
714 dpId, interVpnLink.getInterVpnLinkName());
716 mdsalManager.installFlow(dpId, flowEntity);
721 // TODO Clean up the exception handling
722 @SuppressWarnings("checkstyle:IllegalCatch")
723 private <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
724 InstanceIdentifier<T> path) {
726 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
728 Optional<T> result = Optional.absent();
730 result = tx.read(datastoreType, path).get();
731 } catch (Exception e) {
732 throw new RuntimeException(e);
738 private List<BigInteger> getDpnIdForPrefix(DataBroker broker, Long vpnId, String rd, VrfEntry vrfEntry) {
739 List<BigInteger> returnLocalDpnId = new ArrayList<>();
740 Prefixes localNextHopInfo = FibUtil.getPrefixToInterface(broker, vpnId, vrfEntry.getDestPrefix());
742 if (localNextHopInfo == null) {
743 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
744 Routes extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
745 if (extraRoute != null) {
746 for (String nextHopIp : extraRoute.getNexthopIpList()) {
747 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
748 if (nextHopIp != null) {
749 localNextHopInfo = FibUtil.getPrefixToInterface(broker, vpnId, nextHopIp + "/32");
750 if (localNextHopInfo != null) {
751 returnLocalDpnId.add(localNextHopInfo.getDpnId());
757 returnLocalDpnId.add(localNextHopInfo.getDpnId());
760 return returnLocalDpnId;
763 private List<BigInteger> createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
764 List<BigInteger> returnLocalDpnId = new ArrayList<>();
765 Prefixes localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
766 String localNextHopIP = vrfEntry.getDestPrefix();
768 if (localNextHopInfo == null) {
769 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
770 Routes extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
771 if (extraRoute != null) {
772 for (String nextHopIp : extraRoute.getNexthopIpList()) {
773 LOG.info("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
774 if (nextHopIp != null) {
775 localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, nextHopIp + "/32");
776 localNextHopIP = nextHopIp + "/32";
777 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId,
778 rd, vrfEntry, vpnId);
779 returnLocalDpnId.add(dpnId);
783 if (localNextHopInfo == null) {
784 /* imported routes case */
785 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
786 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
787 if (optionalLabel.isPresent()) {
788 Long label = optionalLabel.get();
789 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
790 synchronized (label.toString().intern()) {
791 LabelRouteInfo lri = getLabelRouteInfo(label);
792 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
793 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
794 FibUtil.getVpnInstanceOpData(dataBroker, rd);
795 if (vpnInstanceOpDataEntryOptional.isPresent()) {
796 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
797 if (lri.getVpnInstanceList().contains(vpnInstanceName)) {
798 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, true);
799 localNextHopIP = lri.getPrefix();
801 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, false);
802 localNextHopIP = lri.getPrefix();
805 if (localNextHopInfo != null) {
806 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
807 label, localNextHopInfo.getVpnInterfaceName(), lri.getDpnId());
808 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP,
809 vpnId, rd, vrfEntry, lri.getParentVpnid());
810 returnLocalDpnId.add(dpnId);
818 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, vpnId);
819 returnLocalDpnId.add(dpnId);
822 return returnLocalDpnId;
825 private BigInteger checkCreateLocalFibEntry(Prefixes localNextHopInfo, String localNextHopIP,
826 final Long vpnId, final String rd,
827 final VrfEntry vrfEntry, Long parentVpnId) {
828 if (localNextHopInfo != null) {
829 final BigInteger dpnId = localNextHopInfo.getDpnId();
830 if (!isVpnPresentInDpn(rd, dpnId)) {
831 LOG.error("The vpnName with vpnId {} rd {} is not available on dpn {}", vpnId, rd, dpnId.toString());
832 return BigInteger.ZERO;
835 if (Boolean.TRUE.equals(localNextHopInfo.isNatPrefix())) {
836 LOG.debug("NAT Prefix {} with vpnId {} rd {}. Skip local dpn {} FIB processing",
837 vrfEntry.getDestPrefix(), vpnId, rd, dpnId);
841 String jobKey = "FIB-" + vpnId.toString() + "-" + dpnId.toString() + "-" + vrfEntry.getDestPrefix();
842 final long groupId = nextHopManager.createLocalNextHop(parentVpnId, dpnId,
843 localNextHopInfo.getVpnInterfaceName(), localNextHopIP, vrfEntry.getDestPrefix(),
844 vrfEntry.getGatewayMacAddress(), jobKey);
846 LOG.error("Unable to create Group for local prefix {} on rd {} for vpninterface {} on Node {}",
847 vrfEntry.getDestPrefix(), rd, localNextHopInfo.getVpnInterfaceName(), dpnId.toString());
848 return BigInteger.ZERO;
850 final List<InstructionInfo> instructions = Collections.singletonList(
851 new InstructionApplyActions(
852 Collections.singletonList(new ActionGroup(groupId))));
853 final List<InstructionInfo> lfibinstructions = Collections.singletonList(
854 new InstructionApplyActions(
855 Arrays.asList(new ActionPopMpls(), new ActionGroup(groupId))));
856 java.util.Optional<Long> optLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
857 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
858 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
859 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
860 dpnId, localNextHopInfo.getVpnInterfaceName(), optLabel);
862 LOG.debug("Route with rd {} prefix {} label {} nexthop {} for vpn {} is an imported route. "
863 + "LFib and Terminating table entries will not be created.",
864 rd, vrfEntry.getDestPrefix(), optLabel, nextHopAddressList, vpnId);
866 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
868 dataStoreCoordinator.enqueueJob(jobKey,
870 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
871 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
872 optLabel.ifPresent(label -> {
873 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
874 makeLFibTableEntry(dpnId, label, lfibinstructions,
875 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
876 makeTunnelTableEntry(dpnId, label, groupId, tx);
879 List<ListenableFuture<Void>> futures = new ArrayList<>();
880 futures.add(tx.submit());
885 return BigInteger.ZERO;
888 private boolean isVpnPresentInDpn(String rd, BigInteger dpnId) {
889 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
890 return FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id).isPresent();
893 private LabelRouteInfo getLabelRouteInfo(Long label) {
894 InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
895 .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build();
896 Optional<LabelRouteInfo> opResult = read(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid);
897 if (opResult.isPresent()) {
898 return opResult.get();
903 private boolean deleteLabelRouteInfo(LabelRouteInfo lri, String vpnInstanceName, WriteTransaction tx) {
904 LOG.debug("deleting LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
905 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
906 .child(LabelRouteInfo.class, new LabelRouteInfoKey(lri.getLabel())).build();
910 List<String> vpnInstancesList = lri.getVpnInstanceList() != null
911 ? lri.getVpnInstanceList() : new ArrayList<>();
912 if (vpnInstancesList.contains(vpnInstanceName)) {
913 LOG.debug("vpninstance {} name is present", vpnInstanceName);
914 vpnInstancesList.remove(vpnInstanceName);
916 if (vpnInstancesList.size() == 0) {
917 LOG.debug("deleting LRI instance object for label {}", lri.getLabel());
919 tx.delete(LogicalDatastoreType.OPERATIONAL, lriId);
921 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId);
925 LOG.debug("updating LRI instance object for label {}", lri.getLabel());
926 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri).setVpnInstanceList(vpnInstancesList);
927 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(),
928 FibUtil.DEFAULT_CALLBACK);
933 private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/,
934 WriteTransaction tx) {
935 List<ActionInfo> actionsInfos = Collections.singletonList(new ActionGroup(groupId));
937 createTerminatingServiceActions(dpId, (int) label, actionsInfos, tx);
939 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully",
940 dpId, label, groupId);
943 public void createTerminatingServiceActions(BigInteger destDpId, int label, List<ActionInfo> actionsInfos,
944 WriteTransaction tx) {
945 List<MatchInfo> mkMatches = new ArrayList<>();
947 LOG.debug("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}",
948 destDpId, label, actionsInfos);
951 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
952 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(label)));
954 List<InstructionInfo> mkInstructions = new ArrayList<>();
955 mkInstructions.add(new InstructionApplyActions(actionsInfos));
957 FlowEntity terminatingServiceTableFlowEntity =
958 MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
959 getTableMissFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE, label), 5,
960 String.format("%s:%d", "TST Flow Entry ", label),
961 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, mkInstructions);
963 FlowKey flowKey = new FlowKey(new FlowId(terminatingServiceTableFlowEntity.getFlowId()));
965 FlowBuilder flowbld = terminatingServiceTableFlowEntity.getFlowBuilder();
967 Node nodeDpn = buildDpnNode(terminatingServiceTableFlowEntity.getDpnId());
968 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
969 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
970 .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId()))
971 .child(Flow.class, flowKey).build();
972 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flowbld.build(), true);
975 private void removeTunnelTableEntry(BigInteger dpId, long label, WriteTransaction tx) {
976 FlowEntity flowEntity;
977 LOG.debug("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId, label);
978 List<MatchInfo> mkMatches = new ArrayList<>();
980 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(label)));
981 flowEntity = MDSALUtil.buildFlowEntity(dpId,
982 NwConstants.INTERNAL_TUNNEL_TABLE,
983 getTableMissFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int) label),
984 5, String.format("%s:%d", "TST Flow Entry ", label), 0, 0,
985 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
986 Node nodeDpn = buildDpnNode(flowEntity.getDpnId());
987 FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getFlowId()));
988 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
989 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
990 .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build();
992 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
993 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully", dpId, label);
996 public List<BigInteger> deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
997 List<BigInteger> returnLocalDpnId = new ArrayList<>();
998 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
999 String localNextHopIP = vrfEntry.getDestPrefix();
1001 if (localNextHopInfo == null) {
1002 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
1003 Routes extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1004 if (extraRoute != null) {
1005 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1006 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
1007 if (nextHopIp != null) {
1008 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp + "/32");
1009 localNextHopIP = nextHopIp + "/32";
1010 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
1011 vpnId, rd, vrfEntry, true /*isExtraRoute*/);
1012 if (!dpnId.equals(BigInteger.ZERO)) {
1013 returnLocalDpnId.add(dpnId);
1019 if (localNextHopInfo == null) {
1020 /* Imported VRF entry */
1021 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1022 if (optionalLabel.isPresent()) {
1023 Long label = optionalLabel.get();
1024 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
1025 LabelRouteInfo lri = getLabelRouteInfo(label);
1026 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
1027 VpnNexthopBuilder vpnNexthopBuilder = new VpnNexthopBuilder();
1028 vpnNexthopBuilder.setDpnId(lri.getDpnId());
1029 BigInteger dpnId = checkDeleteLocalFibEntry(vpnNexthopBuilder.build(), localNextHopIP,
1030 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
1031 if (!dpnId.equals(BigInteger.ZERO)) {
1032 returnLocalDpnId.add(dpnId);
1039 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
1040 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
1041 if (!dpnId.equals(BigInteger.ZERO)) {
1042 returnLocalDpnId.add(dpnId);
1046 return returnLocalDpnId;
1049 private BigInteger checkDeleteLocalFibEntry(VpnNexthop localNextHopInfo, final String localNextHopIP,
1050 final Long vpnId, final String rd,
1051 final VrfEntry vrfEntry, final boolean isExtraRoute) {
1052 if (localNextHopInfo != null) {
1053 final BigInteger dpnId = localNextHopInfo.getDpnId();
1054 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1055 dataStoreCoordinator.enqueueJob("FIB-" + vpnId.toString() + "-"
1056 + dpnId.toString() + "-" + vrfEntry.getDestPrefix(),
1058 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1059 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null /* instructions */,
1060 NwConstants.DEL_FLOW, tx);
1061 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1062 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
1063 makeLFibTableEntry(dpnId, label, null /* instructions */,
1064 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1065 removeTunnelTableEntry(dpnId, label, tx);
1068 List<ListenableFuture<Void>> futures = new ArrayList<>();
1069 futures.add(tx.submit());
1072 //TODO: verify below adjacency call need to be optimized (?)
1073 deleteLocalAdjacency(dpnId, vpnId, localNextHopIP, vrfEntry.getDestPrefix());
1076 return BigInteger.ZERO;
1079 static InstanceIdentifier<Routes> getVpnToExtrarouteIdentifier(String vpnName, String vrfId, String ipPrefix) {
1080 return InstanceIdentifier.builder(VpnToExtraroutes.class)
1081 .child(Vpn.class, new VpnKey(vpnName)).child(ExtraRoutes.class,
1082 new ExtraRoutesKey(vrfId)).child(Routes.class, new RoutesKey(ipPrefix)).build();
1085 public Routes getVpnToExtraroute(String vpnRd, String destPrefix) {
1086 Optional<String> optVpnName = FibUtil.getVpnNameFromRd(dataBroker, vpnRd);
1087 if (optVpnName.isPresent()) {
1088 InstanceIdentifier<Routes> vpnExtraRoutesId = getVpnToExtrarouteIdentifier(
1089 optVpnName.get(), vpnRd, destPrefix);
1090 return FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, vpnExtraRoutesId).orNull();
1095 private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
1097 Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
1098 new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
1099 RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
1100 if (!rpcResult.isSuccessful()) {
1101 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
1103 return rpcResult.getResult().getTunnelType();
1106 } catch (InterruptedException | ExecutionException e) {
1107 LOG.warn("Exception when getting tunnel interface Id for tunnel type", e);
1114 private void createRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, final VrfTablesKey vrfTableKey,
1115 final VrfEntry vrfEntry, WriteTransaction tx) {
1116 Boolean wrTxPresent = true;
1118 wrTxPresent = false;
1119 tx = dataBroker.newWriteOnlyTransaction();
1121 String rd = vrfTableKey.getRouteDistinguisher();
1122 LOG.debug("createremotefibentry: adding route {} for rd {} on remoteDpnId {}",
1123 vrfEntry.getDestPrefix(), rd, remoteDpnId);
1125 List<AdjacencyResult> adjacencyResults = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
1126 if (adjacencyResults.isEmpty()) {
1127 LOG.error("Could not get interface for route-paths: {} in vpn {}",
1128 vrfEntry.getRoutePaths(), rd);
1129 LOG.warn("Failed to add Route: {} in vpn: {}",
1130 vrfEntry.getDestPrefix(), rd);
1134 for (AdjacencyResult adjacencyResult : adjacencyResults) {
1135 List<ActionInfo> actionInfos = new ArrayList<>();
1136 String egressInterface = adjacencyResult.getInterfaceName();
1137 if (Tunnel.class.equals(adjacencyResult.getInterfaceType())) {
1138 addTunnelInterfaceActions(egressInterface, vpnId, vrfEntry, actionInfos);
1140 addRewriteDstMacAction(vpnId, vrfEntry, actionInfos);
1142 List<ActionInfo> egressActions = nextHopManager.getEgressActionsForInterface(egressInterface,
1143 actionInfos.size());
1144 if (egressActions.isEmpty()) {
1145 LOG.error("Failed to retrieve egress action for prefix {} route-paths {} interface {}. "
1146 + "Aborting remote FIB entry creation.",
1147 vrfEntry.getDestPrefix(), vrfEntry.getRoutePaths(), egressInterface);
1150 actionInfos.addAll(egressActions);
1151 List<InstructionInfo> instructions = new ArrayList<>();
1152 instructions.add(new InstructionApplyActions(actionInfos));
1153 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
1158 LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
1161 private void addRewriteDstMacAction(long vpnId, VrfEntry vrfEntry, List<ActionInfo> actionInfos) {
1162 String ipPrefix = vrfEntry.getDestPrefix();
1163 Prefixes prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, ipPrefix);
1164 if (prefixInfo == null) {
1165 LOG.debug("No prefix info found for prefix {}", ipPrefix);
1169 String ifName = prefixInfo.getVpnInterfaceName();
1170 if (ifName == null) {
1171 LOG.debug("Failed to get VPN interface for prefix {}", ipPrefix);
1175 String macAddress = FibUtil.getMacAddressFromPrefix(dataBroker, ifName, ipPrefix);
1176 if (macAddress == null) {
1177 LOG.warn("No MAC address found for VPN interface {} prefix {}", ifName, ipPrefix);
1181 actionInfos.add(new ActionSetFieldEthernetDestination(actionInfos.size(), new MacAddress(macAddress)));
1184 private void addTunnelInterfaceActions(String tunnelInterface, long vpnId, VrfEntry vrfEntry,
1185 List<ActionInfo> actionInfos) {
1186 Class<? extends TunnelTypeBase> tunnelType = getTunnelType(tunnelInterface);
1187 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1188 if (!optionalLabel.isPresent()) {
1189 LOG.warn("RoutePaths not available");
1192 long label = optionalLabel.get();
1193 if (tunnelType.equals(TunnelTypeMplsOverGre.class)) {
1194 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
1195 actionInfos.add(new ActionPushMpls());
1196 actionInfos.add(new ActionSetFieldMplsLabel(label));
1197 actionInfos.add(new ActionNxLoadInPort(BigInteger.ZERO));
1199 BigInteger tunnelId;
1200 // FIXME vxlan vni bit set is not working properly with OVS.need to
1202 if (tunnelType.equals(TunnelTypeVxlan.class)) {
1203 tunnelId = BigInteger.valueOf(label);
1205 tunnelId = BigInteger.valueOf(label);
1208 LOG.debug("adding set tunnel id action for label {}", label);
1209 actionInfos.add(new ActionSetFieldTunnelId(tunnelId));
1210 addRewriteDstMacAction(vpnId, vrfEntry, actionInfos);
1214 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
1215 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
1216 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1217 if (dpnInVpn.isPresent()) {
1218 List<VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
1219 VpnInterfaces currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
1221 if (vpnInterfaces.remove(currVpnInterface)) {
1222 if (vpnInterfaces.isEmpty()) {
1223 LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
1224 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1225 cleanUpDpnForVpn(dpnId, vpnId, rd, null);
1227 LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
1228 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id.child(
1229 VpnInterfaces.class,
1230 new VpnInterfacesKey(intfName)));
1236 private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
1237 /* Get interface info from prefix to interface mapping;
1238 Use the interface info to get the corresponding vpn interface op DS entry,
1239 remove the adjacency corresponding to this fib entry.
1240 If adjacency removed is the last adjacency, clean up the following:
1241 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
1242 - prefix to interface entry
1243 - vpn interface op DS
1245 LOG.debug("Cleanup of prefix {} in VPN {}", vrfEntry.getDestPrefix(), vpnId);
1246 Prefixes prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
1247 Routes extraRoute = null;
1248 if (prefixInfo == null) {
1249 extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1250 if (extraRoute != null) {
1251 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1252 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
1254 if (nextHopIp != null) {
1255 prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, nextHopIp + "/32");
1256 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1260 if (prefixInfo == null) {
1261 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1262 if (optionalLabel.isPresent()) {
1263 Long label = optionalLabel.get();
1264 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
1265 LabelRouteInfo lri = getLabelRouteInfo(label);
1266 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
1267 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
1268 prefixBuilder.setDpnId(lri.getDpnId());
1269 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
1270 prefixBuilder.setIpAddress(lri.getPrefix());
1271 prefixInfo = prefixBuilder.build();
1272 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
1273 label, prefixInfo.getVpnInterfaceName(), lri.getDpnId());
1274 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1279 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1283 private void checkCleanUpOpDataForFib(final Prefixes prefixInfo, final Long vpnId, final String rd,
1284 final VrfEntry vrfEntry, final Routes extraRoute) {
1286 if (prefixInfo == null) {
1287 LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for prefix {}", vrfEntry.getDestPrefix());
1288 return; //Don't have any info for this prefix (shouldn't happen); need to return
1291 if (Boolean.TRUE.equals(prefixInfo.isNatPrefix())) {
1292 LOG.debug("NAT Prefix {} with vpnId {} rd {}. Skip FIB processing",
1293 vrfEntry.getDestPrefix(), vpnId, rd);
1297 String ifName = prefixInfo.getVpnInterfaceName();
1298 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1299 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + ifName,
1300 new CleanupVpnInterfaceWorker(prefixInfo, vpnId, rd, vrfEntry, extraRoute));
1303 private class CleanupVpnInterfaceWorker implements Callable<List<ListenableFuture<Void>>> {
1304 Prefixes prefixInfo;
1310 CleanupVpnInterfaceWorker(final Prefixes prefixInfo, final Long vpnId, final String rd,
1311 final VrfEntry vrfEntry, final Routes extraRoute) {
1312 this.prefixInfo = prefixInfo;
1315 this.vrfEntry = vrfEntry;
1316 this.extraRoute = extraRoute;
1320 public List<ListenableFuture<Void>> call() throws Exception {
1321 // If another renderer(for eg : CSS) needs to be supported, check can be performed here
1322 // to call the respective helpers.
1323 WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
1325 //First Cleanup LabelRouteInfo
1326 FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> {
1327 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
1328 synchronized (label.toString().intern()) {
1329 LabelRouteInfo lri = getLabelRouteInfo(label);
1330 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
1331 && nextHopAddressList.contains(lri.getNextHopIpList().get(0))) {
1332 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
1333 FibUtil.getVpnInstanceOpData(dataBroker, rd);
1334 String vpnInstanceName = "";
1335 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1336 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1338 boolean lriRemoved = deleteLabelRouteInfo(lri, vpnInstanceName, writeOperTxn);
1340 String parentRd = lri.getParentVpnRd();
1341 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1342 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1345 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1346 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1350 String ifName = prefixInfo.getVpnInterfaceName();
1351 Optional<VpnInterface> optvpnInterface = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1352 FibUtil.getVpnInterfaceIdentifier(ifName));
1353 if (optvpnInterface.isPresent()) {
1354 long associatedVpnId = FibUtil.getVpnId(dataBroker, optvpnInterface.get().getVpnInstanceName());
1355 if (vpnId != associatedVpnId) {
1356 LOG.warn("Prefixes {} are associated with different vpn instance with id : {} rather than {}",
1357 vrfEntry.getDestPrefix(), associatedVpnId, vpnId);
1358 LOG.warn("Not proceeding with Cleanup op data for prefix {}", vrfEntry.getDestPrefix());
1361 LOG.debug("Processing cleanup of prefix {} associated with vpn {}",
1362 vrfEntry.getDestPrefix(), associatedVpnId);
1365 if (extraRoute != null) {
1366 Optional<String> optVpnName = FibUtil.getVpnNameFromRd(dataBroker, rd);
1367 if (optVpnName.isPresent()) {
1368 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
1369 getVpnToExtrarouteIdentifier(optVpnName.get(), rd, vrfEntry.getDestPrefix()));
1372 Optional<Adjacencies> optAdjacencies = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1373 FibUtil.getAdjListPath(ifName));
1375 if (optAdjacencies.isPresent()) {
1376 numAdj = optAdjacencies.get().getAdjacency().size();
1378 //remove adjacency corr to prefix
1380 boolean isPrimaryAdj = false;
1381 List<Adjacency> adjacencyList = optAdjacencies.get().getAdjacency();
1382 for (Adjacency adj : adjacencyList) {
1383 if (adj.getIpAddress().equals(vrfEntry.getDestPrefix())) {
1384 isPrimaryAdj = adj.isPrimaryAdjacency();
1388 //We should only delete secondary adjacencies, as primary adjacency is used to
1389 //cleanup prefix-to-interface in the subscriber vpnInterfaceOpListener
1390 if (!isPrimaryAdj) {
1391 LOG.info("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId,
1392 vrfEntry.getDestPrefix());
1393 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL,
1394 FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
1397 if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
1398 //clean up the vpn interface from DpnToVpn list
1399 LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
1400 writeOperTxn.delete(LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnInterfaceIdentifier(ifName));
1402 List<ListenableFuture<Void>> futures = new ArrayList<>();
1403 futures.add(writeOperTxn.submit());
1408 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1409 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1410 final String rd = vrfTableKey.getRouteDistinguisher();
1411 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1412 if (vpnInstance == null) {
1413 LOG.error("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1416 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1418 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1419 final java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1420 List<String> nextHopAddressList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
1421 if (subnetRoute != null) {
1422 elanTag = subnetRoute.getElantag();
1423 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
1424 rd, vrfEntry.getDestPrefix(), elanTag);
1425 if (vpnToDpnList != null) {
1426 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1427 dataStoreCoordinator.enqueueJob("FIB-" + rd + "-" + vrfEntry.getDestPrefix(),
1429 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1431 for (final VpnToDpnList curDpn : vpnToDpnList) {
1433 makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry,
1434 vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW, tx);
1435 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1436 optionalLabel.ifPresent(label -> {
1437 makeLFibTableEntry(curDpn.getDpnId(), label, null,
1438 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1442 List<ListenableFuture<Void>> futures = new ArrayList<>();
1443 futures.add(tx.submit());
1447 optionalLabel.ifPresent(label -> {
1448 synchronized (label.toString().intern()) {
1449 LabelRouteInfo lri = getLabelRouteInfo(label);
1450 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) {
1451 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
1452 FibUtil.getVpnInstanceOpData(dataBroker, rd);
1453 String vpnInstanceName = "";
1454 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1455 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1457 boolean lriRemoved = this.deleteLabelRouteInfo(lri, vpnInstanceName, null);
1459 String parentRd = lri.getParentVpnRd();
1460 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1461 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1462 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {} as "
1463 + "labelRouteInfo cleared", label, rd,
1464 vrfEntry.getDestPrefix());
1467 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1468 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1469 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {}",
1470 label, rd, vrfEntry.getDestPrefix());
1476 if (installRouterFibEntries(vrfEntry, vpnToDpnList, vpnInstance.getVpnId(), NwConstants.DEL_FLOW)) {
1480 final List<BigInteger> localDpnIdList = deleteLocalFibEntry(vpnInstance.getVpnId(),
1481 vrfTableKey.getRouteDistinguisher(), vrfEntry);
1482 if (vpnToDpnList != null) {
1483 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1484 dataStoreCoordinator.enqueueJob("FIB-" + rd + "-" + vrfEntry.getDestPrefix(),
1486 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1488 if (localDpnIdList.size() <= 0) {
1489 for (VpnToDpnList curDpn : vpnToDpnList) {
1490 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1491 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1492 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(),
1493 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1496 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(),
1497 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1501 for (BigInteger localDpnId : localDpnIdList) {
1502 for (VpnToDpnList curDpn : vpnToDpnList) {
1503 if (!curDpn.getDpnId().equals(localDpnId)) {
1504 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1505 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1506 deleteRemoteRoute(localDpnId, curDpn.getDpnId(),
1507 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1510 deleteRemoteRoute(localDpnId, curDpn.getDpnId(),
1511 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1517 List<ListenableFuture<Void>> futures = new ArrayList<>();
1518 futures.add(tx.submit());
1523 //The flow/group entry has been deleted from config DS; need to clean up associated operational
1524 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
1525 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
1527 // Remove all fib entries configured due to interVpnLink, when nexthop is the opposite endPoint
1528 // of the interVpnLink.
1529 Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(this.dataBroker, rd);
1530 if (optVpnUuid.isPresent()) {
1531 String vpnUuid = optVpnUuid.get();
1532 FibUtil.getFirstNextHopAddress(vrfEntry).ifPresent(routeNexthop -> {
1533 Optional<InterVpnLinkDataComposite> optInterVpnLink =
1534 InterVpnLinkCache.getInterVpnLinkByVpnId(vpnUuid);
1535 if (optInterVpnLink.isPresent()) {
1536 InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
1537 if (interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid)) {
1538 // This is route that points to the other endpoint of an InterVpnLink
1539 // In that case, we should look for the FIB table pointing to
1540 // LPortDispatcher table and remove it.
1541 removeInterVPNLinkRouteFlows(interVpnLink.getInterVpnLinkName(),
1542 interVpnLink.isFirstEndpointVpnName(rd),
1552 Please note that the following deleteFibEntries will be invoked only for BGP Imported Routes.
1553 The invocation of the following method is via delete() callback from the MDSAL Batching Infrastructure
1554 provided by ResourceBatchingManager
1556 private void deleteFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> identifier,
1557 final VrfEntry vrfEntry) {
1558 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1560 final String rd = vrfTableKey.getRouteDistinguisher();
1561 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1562 if (vpnInstance == null) {
1563 LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1566 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1567 if (vpnToDpnList != null) {
1568 for (VpnToDpnList curDpn : vpnToDpnList) {
1569 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1570 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(),
1571 vrfTableKey, vrfEntry, writeTx);
1577 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
1578 final long vpnId, final VrfTablesKey vrfTableKey,
1579 final VrfEntry vrfEntry, WriteTransaction tx) {
1581 Boolean wrTxPresent = true;
1583 wrTxPresent = false;
1584 tx = dataBroker.newWriteOnlyTransaction();
1587 LOG.debug("deleting remote route: prefix={}, vpnId={} localDpnId {} remoteDpnId {}",
1588 vrfEntry.getDestPrefix(), vpnId, localDpnId, remoteDpnId);
1589 String rd = vrfTableKey.getRouteDistinguisher();
1591 if (localDpnId != null) {
1592 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
1593 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1597 // below two reads are kept as is, until best way is found to identify dpnID
1598 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
1599 Routes extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1601 if (localNextHopInfo == null && extraRoute != null) {
1602 // Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
1603 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1604 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp);
1605 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1608 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1615 private boolean checkDpnDeleteFibEntry(VpnNexthop localNextHopInfo, BigInteger remoteDpnId, long vpnId,
1616 VrfEntry vrfEntry, String rd, WriteTransaction tx) {
1617 boolean isRemoteRoute = true;
1618 if (localNextHopInfo != null) {
1619 isRemoteRoute = !remoteDpnId.equals(localNextHopInfo.getDpnId());
1621 if (isRemoteRoute) {
1622 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1625 LOG.debug("Did not delete FIB entry: rd={}, vrfEntry={}, as it is local to dpnId={}",
1626 rd, vrfEntry.getDestPrefix(), remoteDpnId);
1631 private void deleteFibEntry(BigInteger remoteDpnId, long vpnId, VrfEntry vrfEntry, String rd, WriteTransaction tx) {
1632 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1633 LOG.debug("Successfully delete FIB entry: vrfEntry={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
1636 private long get(byte[] rawIpAddress) {
1637 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
1638 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
1641 private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
1642 List<InstructionInfo> instructions, int addOrRemove, WriteTransaction tx) {
1643 Boolean wrTxPresent = true;
1645 wrTxPresent = false;
1646 tx = dataBroker.newWriteOnlyTransaction();
1649 LOG.trace("makeConnectedRoute: vrfEntry {}", vrfEntry);
1650 String[] values = vrfEntry.getDestPrefix().split("/");
1651 String ipAddress = values[0];
1652 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
1653 if (addOrRemove == NwConstants.ADD_FLOW) {
1654 LOG.debug("Adding route to DPN {} for rd {} prefix {} ", dpId, rd, vrfEntry.getDestPrefix());
1656 LOG.debug("Removing route from DPN {} for rd {} prefix {}", dpId, rd, vrfEntry.getDestPrefix());
1658 InetAddress destPrefix;
1660 destPrefix = InetAddress.getByName(ipAddress);
1661 } catch (UnknownHostException e) {
1662 LOG.error("Failed to get destPrefix for prefix {} ", vrfEntry.getDestPrefix(), e);
1666 List<MatchInfo> matches = new ArrayList<>();
1668 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
1670 if (destPrefix instanceof Inet4Address) {
1671 matches.add(MatchEthernetType.IPV4);
1672 if (prefixLength != 0) {
1673 matches.add(new MatchIpv4Destination(destPrefix.getHostAddress(), Integer.toString(prefixLength)));
1676 matches.add(MatchEthernetType.IPV6);
1677 if (prefixLength != 0) {
1678 matches.add(new MatchIpv6Destination(destPrefix.getHostAddress() + "/" + prefixLength));
1682 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
1683 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, priority, destPrefix);
1684 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef, priority,
1686 COOKIE_VM_FIB_TABLE, matches, instructions);
1688 Flow flow = flowEntity.getFlowBuilder().build();
1689 String flowId = flowEntity.getFlowId();
1690 FlowKey flowKey = new FlowKey(new FlowId(flowId));
1691 Node nodeDpn = buildDpnNode(dpId);
1693 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1694 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1695 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1697 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1698 SubTransaction subTransaction = new SubTransactionImpl();
1699 if (addOrRemove == NwConstants.ADD_FLOW) {
1700 subTransaction.setInstanceIdentifier(flowInstanceId);
1701 subTransaction.setInstance(flow);
1702 subTransaction.setAction(SubTransaction.CREATE);
1704 subTransaction.setInstanceIdentifier(flowInstanceId);
1705 subTransaction.setAction(SubTransaction.DELETE);
1707 transactionObjects.add(subTransaction);
1710 if (addOrRemove == NwConstants.ADD_FLOW) {
1711 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
1713 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1721 //TODO: How to handle the below code, its a copy paste from MDSALManager.java
1722 private Node buildDpnNode(BigInteger dpnId) {
1723 NodeId nodeId = new NodeId("openflow:" + dpnId);
1724 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
1729 private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions, int priority,
1730 int addOrRemove, WriteTransaction tx) {
1731 Boolean wrTxPresent = true;
1733 wrTxPresent = false;
1734 tx = dataBroker.newWriteOnlyTransaction();
1737 List<MatchInfo> matches = new ArrayList<>();
1738 matches.add(MatchEthernetType.MPLS_UNICAST);
1739 matches.add(new MatchMplsLabel(label));
1741 // Install the flow entry in L3_LFIB_TABLE
1742 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, priority);
1744 FlowEntity flowEntity;
1745 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef, priority, flowRef, 0, 0,
1746 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
1747 Flow flow = flowEntity.getFlowBuilder().build();
1748 String flowId = flowEntity.getFlowId();
1749 FlowKey flowKey = new FlowKey(new FlowId(flowId));
1750 Node nodeDpn = buildDpnNode(dpId);
1751 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1752 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1753 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1755 if (addOrRemove == NwConstants.ADD_FLOW) {
1756 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
1758 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1764 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} : key {} {} successfully",
1765 dpId, label, instructions, flowKey, (NwConstants.ADD_FLOW == addOrRemove) ? "ADDED" : "REMOVED");
1768 private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress,
1769 final String ipPrefixAddress) {
1770 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}", dpId, vpnId, ipAddress);
1772 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress, ipPrefixAddress);
1773 } catch (NullPointerException e) {
1778 public void populateFibOnNewDpn(final BigInteger dpnId, final long vpnId, final String rd,
1779 final FutureCallback<List<Void>> callback) {
1780 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
1781 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1782 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1783 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1784 if (!vrfTable.isPresent()) {
1785 LOG.warn("VRF Table not yet available for RD {}", rd);
1786 if (callback != null) {
1787 List<ListenableFuture<Void>> futures = new ArrayList<>();
1788 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1789 Futures.addCallback(listenableFuture, callback);
1793 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1794 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1796 List<ListenableFuture<Void>> futures = new ArrayList<>();
1797 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1798 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1799 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1800 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1801 if (subnetRoute != null) {
1802 long elanTag = subnetRoute.getElantag();
1803 installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
1806 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
1807 if (routerInt != null) {
1808 LOG.trace("Router augmented vrfentry found rd:{}, uuid:{}, ip:{}, mac:{}",
1809 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
1810 installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(),
1811 routerInt.getIpAddress(),
1812 new MacAddress(routerInt.getMacAddress()), NwConstants.ADD_FLOW);
1815 //Handle local flow creation for imports
1816 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
1817 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
1818 if (optionalLabel.isPresent()) {
1819 List<String> nextHopList = FibUtil.getNextHopListFromRoutePaths(vrfEntry);
1820 LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get());
1821 if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList, lri)) {
1822 if (lri.getDpnId().equals(dpnId)) {
1823 createLocalFibEntry(vpnId, rd, vrfEntry);
1829 // Passing null as we don't know the dpn
1830 // to which prefix is attached at this point
1831 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1833 //TODO: if we have 100K entries in FIB, can it fit in one Tranasaction (?)
1834 futures.add(tx.submit());
1836 if (callback != null) {
1837 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1838 Futures.addCallback(listenableFuture, callback);
1845 public void populateExternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1846 final String localNextHopIp, final String remoteNextHopIp) {
1847 LOG.trace("populateExternalRoutesOnDpn : dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} ",
1848 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1849 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1850 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1851 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1852 if (vrfTable.isPresent()) {
1853 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1854 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1856 List<ListenableFuture<Void>> futures = new ArrayList<>();
1857 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1858 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
1859 vrfTable.get().getVrfEntry().stream()
1860 .filter(vrfEntry -> RouteOrigin.BGP == RouteOrigin.value(vrfEntry.getOrigin()))
1862 getConsumerForCreatingRemoteFib(dpnId, vpnId,
1863 rd, remoteNextHopIp, vrfTable,
1865 futures.add(writeCfgTxn.submit());
1872 public void populateInternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1873 final String localNextHopIp, final String remoteNextHopIp) {
1874 LOG.trace("populateInternalRoutesOnDpn : dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} ",
1875 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1876 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1877 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1878 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1879 if (vrfTable.isPresent()) {
1880 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1881 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1883 List<ListenableFuture<Void>> futures = new ArrayList<>();
1884 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1885 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
1886 // Handle Vpn Interface driven Routes only (i.e., STATIC and LOCAL)
1887 vrfTable.get().getVrfEntry().stream()
1888 .filter(vrfEntry -> {
1889 /* Ignore SubnetRoute entry */
1890 return (FibHelper.isControllerManagedVpnInterfaceRoute(RouteOrigin.value(
1891 vrfEntry.getOrigin())));
1893 .forEach(getConsumerForCreatingRemoteFib(dpnId, vpnId,
1894 rd, remoteNextHopIp, vrfTable,
1896 futures.add(writeCfgTxn.submit());
1903 public void manageRemoteRouteOnDPN(final boolean action,
1904 final BigInteger localDpnId,
1907 final String destPrefix,
1908 final String destTepIp,
1910 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1912 if (vpnInstance == null) {
1913 LOG.error("VpnInstance for rd {} not present for prefix {}", rd, destPrefix);
1916 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1917 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + localDpnId.toString(),
1919 List<ListenableFuture<Void>> futures = new ArrayList<>();
1920 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1921 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1922 VrfTablesKey vrfTablesKey = new VrfTablesKey(rd);
1923 VrfEntry vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1924 if (vrfEntry == null) {
1927 LOG.trace("manageRemoteRouteOnDPN :: action {}, DpnId {}, vpnId {}, rd {}, destPfx {}",
1928 action, localDpnId, vpnId, rd, destPrefix);
1929 List<RoutePaths> routePathList = vrfEntry.getRoutePaths();
1930 VrfEntry modVrfEntry;
1931 if (routePathList == null || (routePathList.isEmpty())) {
1932 modVrfEntry = FibHelper.getVrfEntryBuilder(vrfEntry, label,
1933 Collections.singletonList(destTepIp),
1934 RouteOrigin.value(vrfEntry.getOrigin()))
1937 modVrfEntry = vrfEntry;
1940 if (action == true) {
1941 LOG.trace("manageRemoteRouteOnDPN updated(add) vrfEntry :: {}", modVrfEntry);
1942 createRemoteFibEntry(localDpnId, vpnId, vrfTablesKey, modVrfEntry, writeTransaction);
1944 LOG.trace("manageRemoteRouteOnDPN updated(remove) vrfEntry :: {}", modVrfEntry);
1945 deleteRemoteRoute(null, localDpnId, vpnId, vrfTablesKey, modVrfEntry, writeTransaction);
1947 futures.add(writeTransaction.submit());
1953 public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd,
1954 final FutureCallback<List<Void>> callback) {
1955 LOG.trace("cleanUpDpnForVpn: Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
1956 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1957 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1958 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1959 if (vrfTable.isPresent()) {
1960 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1961 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1963 List<ListenableFuture<Void>> futures = new ArrayList<>();
1964 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1965 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1966 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1967 /* Handle subnet routes here */
1968 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1969 if (subnetRoute != null) {
1970 LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn",
1971 vrfEntry.getDestPrefix(),
1973 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1974 java.util.Optional.ofNullable(vrfEntry.getRoutePaths()).ifPresent(routePaths -> {
1975 routePaths.stream().forEach(routePath -> {
1976 makeLFibTableEntry(dpnId, routePath.getLabel(), null, DEFAULT_FIB_FLOW_PRIORITY,
1977 NwConstants.DEL_FLOW, tx);
1978 LOG.trace("cleanUpDpnForVpn: Released subnetroute label {} for rd {} prefix {}",
1979 routePath.getLabel(), rd,
1980 vrfEntry.getDestPrefix());
1985 // ping responder for router interfaces
1986 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
1987 if (routerInt != null) {
1988 LOG.trace("Router augmented vrfentry found for rd:{}, uuid:{}, ip:{}, mac:{}",
1989 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
1990 installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(),
1991 routerInt.getIpAddress(),
1992 new MacAddress(routerInt.getMacAddress()), NwConstants.DEL_FLOW);
1995 // Passing null as we don't know the dpn
1996 // to which prefix is attached at this point
1997 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1999 futures.add(tx.submit());
2000 if (callback != null) {
2001 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
2002 Futures.addCallback(listenableFuture, callback);
2010 public void cleanUpExternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
2011 final String localNextHopIp, final String remoteNextHopIp) {
2012 LOG.trace("cleanUpExternalRoutesOnDpn : cleanup remote routes on dpn {} for vpn {}, rd {}, "
2013 + " localNexthopIp {} , remoteNexhtHopIp {}",
2014 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
2015 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
2016 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
2017 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2018 if (vrfTable.isPresent()) {
2019 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
2020 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
2022 List<ListenableFuture<Void>> futures = new ArrayList<>();
2023 synchronized (vpnInstance.getVpnInstanceName().intern()) {
2024 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
2025 vrfTable.get().getVrfEntry().stream()
2026 .filter(vrfEntry -> RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP)
2027 .forEach(getConsumerForDeletingRemoteFib(dpnId, vpnId, rd,
2028 remoteNextHopIp, vrfTable, writeCfgTxn));
2029 futures.add(writeCfgTxn.submit());
2036 public void cleanUpInternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
2037 final String localNextHopIp, final String remoteNextHopIp) {
2038 LOG.trace("cleanUpInternalRoutesOnDpn : cleanup remote routes on dpn {} for vpn {}, rd {}, "
2039 + " localNexthopIp {} , remoteNexhtHopIp {}",
2040 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
2041 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
2042 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
2043 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2044 if (vrfTable.isPresent()) {
2045 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
2046 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
2048 List<ListenableFuture<Void>> futures = new ArrayList<>();
2049 synchronized (vpnInstance.getVpnInstanceName().intern()) {
2050 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
2051 vrfTable.get().getVrfEntry().stream()
2052 .filter(vrfEntry -> {
2053 /* Ignore SubnetRoute entry */
2054 return (FibHelper.isControllerManagedVpnInterfaceRoute(
2055 RouteOrigin.value(vrfEntry.getOrigin())));
2057 .forEach(getConsumerForDeletingRemoteFib(dpnId, vpnId,
2058 rd, remoteNextHopIp, vrfTable, writeCfgTxn));
2059 futures.add(writeCfgTxn.submit());
2066 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
2067 InstanceIdentifierBuilder<VrfTables> idBuilder =
2068 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
2069 InstanceIdentifier<VrfTables> id = idBuilder.build();
2073 private String getFlowRef(BigInteger dpnId, short tableId, long label, int priority) {
2074 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + label
2075 + NwConstants.FLOWID_SEPARATOR + priority;
2078 private String getFlowRef(BigInteger dpnId, short tableId, String rd, int priority, InetAddress destPrefix) {
2079 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + rd
2080 + NwConstants.FLOWID_SEPARATOR + priority + NwConstants.FLOWID_SEPARATOR + destPrefix.getHostAddress();
2083 private String getInterVpnFibFlowRef(String interVpnLinkName, String prefix, String nextHop) {
2084 return FLOWID_PREFIX + interVpnLinkName + NwConstants.FLOWID_SEPARATOR + prefix + NwConstants
2085 .FLOWID_SEPARATOR + nextHop;
2088 protected List<AdjacencyResult> resolveAdjacency(final BigInteger remoteDpnId, final long vpnId,
2089 final VrfEntry vrfEntry, String rd) {
2090 List<AdjacencyResult> adjacencyList = new ArrayList<>();
2091 List<String> prefixIpList = new ArrayList<>();
2092 LOG.trace("resolveAdjacency called with remotedDpnId {}, vpnId{}, VrfEntry {}",
2093 remoteDpnId, vpnId, vrfEntry);
2095 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
2096 Routes extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
2097 if (extraRoute == null) {
2098 prefixIpList = Collections.singletonList(vrfEntry.getDestPrefix());
2100 prefixIpList = new ArrayList<>();
2101 for (String extraRouteIp : extraRoute.getNexthopIpList()) {
2102 prefixIpList.add(extraRouteIp + "/32");
2106 prefixIpList = Collections.singletonList(vrfEntry.getDestPrefix());
2109 for (String prefixIp : prefixIpList) {
2110 adjacencyList.addAll(vrfEntry.getRoutePaths().stream()
2112 LOG.debug("NextHop IP for destination {} is {}", prefixIp,
2113 routePath.getNexthopAddress());
2114 return nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId,
2115 prefixIp, routePath.getNexthopAddress());
2117 .filter(adjacencyResult -> adjacencyResult != null && !adjacencyList.contains(adjacencyResult))
2119 .collect(Collectors.toList()));
2121 } catch (NullPointerException e) {
2124 return adjacencyList;
2127 protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
2128 InstanceIdentifier<VpnInstanceOpDataEntry> id =
2129 InstanceIdentifier.create(VpnInstanceOpData.class)
2130 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
2131 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData =
2132 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
2133 return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null;
2136 private String getTableMissFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
2137 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR
2138 + tableMiss + FLOWID_PREFIX;
2142 * Install flow entry in protocol table to forward mpls
2143 * coming through gre tunnel to LFIB table.
2145 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
2146 final BigInteger cookieProtocolTable = new BigInteger("1070000", 16);
2147 // Instruction to goto L3 InterfaceTable
2148 List<InstructionInfo> instructions = new ArrayList<>();
2149 instructions.add(new InstructionGotoTable(NwConstants.L3_LFIB_TABLE));
2150 List<MatchInfo> matches = new ArrayList<>();
2151 matches.add(MatchEthernetType.MPLS_UNICAST);
2152 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2153 getTableMissFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2154 NwConstants.L3_LFIB_TABLE),
2155 DEFAULT_FIB_FLOW_PRIORITY,
2156 "Protocol Table For LFIB",
2158 cookieProtocolTable,
2159 matches, instructions);
2161 if (addOrRemove == NwConstants.ADD_FLOW) {
2162 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
2163 mdsalManager.installFlow(flowEntityToLfib);
2165 mdsalManager.removeFlow(flowEntityToLfib);
2169 public List<String> printFibEntries() {
2170 List<String> result = new ArrayList<>();
2171 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s", "RD", "Prefix", "NextHop", "Label", "Origin"));
2172 result.add("-------------------------------------------------------------------");
2173 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
2174 Optional<FibEntries> fibEntries = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2175 if (fibEntries.isPresent()) {
2176 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
2177 for (VrfTables vrfTable : vrfTables) {
2178 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
2179 List<RoutePaths> routePaths = vrfEntry.getRoutePaths();
2180 for (RoutePaths routePath : routePaths) {
2181 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s",
2182 vrfTable.getRouteDistinguisher(),
2183 vrfEntry.getDestPrefix(), routePath.getNexthopAddress(),
2184 routePath.getLabel(), vrfEntry.getOrigin()));
2186 if (routePaths.isEmpty()) {
2187 result.add(String.format(" %-7s %-20s %-20s %-7s",
2188 vrfTable.getRouteDistinguisher(),
2189 vrfEntry.getDestPrefix(), "local", vrfEntry.getOrigin()));
2198 private VrfEntry getVrfEntry(DataBroker broker, String rd, String ipPrefix) {
2199 InstanceIdentifier<VrfEntry> vrfEntryId = InstanceIdentifier.builder(FibEntries.class)
2200 .child(VrfTables.class, new VrfTablesKey(rd))
2201 .child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2202 Optional<VrfEntry> vrfEntry = read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
2203 if (vrfEntry.isPresent()) {
2204 return vrfEntry.get();
2209 private InstanceIdentifier<VrfEntry> getVrfEntryId(String rd, String ipPrefix) {
2210 InstanceIdentifier<VrfEntry> vrfEntryId = InstanceIdentifier.builder(FibEntries.class)
2211 .child(VrfTables.class, new VrfTablesKey(rd))
2212 .child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2216 protected Boolean isIpv4Address(String ipAddress) {
2218 InetAddress address = InetAddress.getByName(ipAddress);
2219 if (address instanceof Inet4Address) {
2222 } catch (UnknownHostException e) {
2223 LOG.warn("Invalid ip address {}", ipAddress, e);
2229 protected Boolean installRouterFibEntries(final VrfEntry vrfEntry, final Collection<VpnToDpnList> vpnToDpnList,
2230 long vpnId, int addOrRemove) {
2231 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
2232 if (routerInt != null && vpnToDpnList != null) {
2233 String routerId = routerInt.getUuid();
2234 String macAddress = routerInt.getMacAddress();
2235 String ipValue = routerInt.getIpAddress();
2236 LOG.trace("createFibEntries - Router augmented vrfentry found for for router uuid:{}, ip:{}, mac:{}",
2237 routerId, ipValue, macAddress);
2238 for (VpnToDpnList vpnDpn : vpnToDpnList) {
2239 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
2240 installRouterFibEntry(vrfEntry, vpnDpn.getDpnId(), vpnId, routerId, ipValue,
2241 new MacAddress(macAddress), addOrRemove);
2249 public void installRouterFibEntry(final VrfEntry vrfEntry, BigInteger dpnId, long vpnId, String routerUuid,
2250 String routerInternalIp, MacAddress routerMac, int addOrRemove) {
2251 String[] subSplit = routerInternalIp.split("/");
2252 if (!isIpv4Address(subSplit[0])) {
2253 // Ping responder using OpenFlow rules is only supported for IPv4, hence skipping.
2257 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
2258 if (!optionalLabel.isPresent()) {
2259 LOG.warn("Routes paths not present. Exiting installRouterFibEntry");
2262 String addRemoveStr = (addOrRemove == NwConstants.ADD_FLOW) ? "ADD_FLOW" : "DELETE_FLOW";
2263 LOG.trace("{}: bulding Echo Flow entity for dpid:{}, router_ip:{}, vpnId:{}, subSplit:{} ", addRemoveStr,
2264 dpnId, routerInternalIp, vpnId, subSplit[0]);
2266 List<MatchInfo> matches = new ArrayList<>();
2268 matches.add(MatchIpProtocol.ICMP);
2269 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
2270 matches.add(new MatchIcmpv4((short) 8, (short) 0));
2271 matches.add(MatchEthernetType.IPV4);
2272 matches.add(new MatchIpv4Destination(subSplit[0], "32"));
2274 List<ActionInfo> actionsInfos = new ArrayList<>();
2276 // Set Eth Src and Eth Dst
2277 actionsInfos.add(new ActionMoveSourceDestinationEth());
2278 actionsInfos.add(new ActionSetFieldEthernetSource(routerMac));
2280 // Move Ip Src to Ip Dst
2281 actionsInfos.add(new ActionMoveSourceDestinationIp());
2282 actionsInfos.add(new ActionSetSourceIp(subSplit[0], "32"));
2284 // Set the ICMP type to 0 (echo reply)
2285 actionsInfos.add(new ActionSetIcmpType((short) 0));
2287 actionsInfos.add(new ActionNxLoadInPort(BigInteger.ZERO));
2289 actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
2291 List<InstructionInfo> instructions = new ArrayList<>();
2293 instructions.add(new InstructionApplyActions(actionsInfos));
2295 int priority = FibConstants.DEFAULT_FIB_FLOW_PRIORITY + FibConstants.DEFAULT_PREFIX_LENGTH;
2296 String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, optionalLabel.get(),
2299 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef,
2300 0, 0, NwConstants.COOKIE_VM_FIB_TABLE, matches, instructions);
2302 if (addOrRemove == NwConstants.ADD_FLOW) {
2303 mdsalManager.installFlow(flowEntity);
2305 mdsalManager.removeFlow(flowEntity);
2309 public void removeInterVPNLinkRouteFlows(final String interVpnLinkName,
2310 final boolean isVpnFirstEndPoint,
2311 final VrfEntry vrfEntry) {
2312 Preconditions.checkArgument(vrfEntry.getRoutePaths() != null
2313 && vrfEntry.getRoutePaths().size() == 1);
2314 Optional<InterVpnLinkState> interVpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLinkName);
2316 if (!interVpnLinkState.isPresent()) {
2317 LOG.warn("Could not find State for InterVpnLink {}", interVpnLinkName);
2321 List<BigInteger> targetDpns =
2322 isVpnFirstEndPoint ? interVpnLinkState.get().getFirstEndpointState().getDpId()
2323 : interVpnLinkState.get().getSecondEndpointState().getDpId();
2325 java.util.Optional<String> optionalNextHop = FibUtil.getFirstNextHopAddress(vrfEntry);
2326 java.util.Optional<Long> optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry);
2330 optionalNextHop.ifPresent(nextHop -> {
2331 String flowRef = getInterVpnFibFlowRef(interVpnLinkName, vrfEntry.getDestPrefix(), nextHop);
2332 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
2333 Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef))
2334 .setTableId(NwConstants.L3_FIB_TABLE).setFlowName(flowRef).build();
2336 LOG.trace("Removing flow in FIB table for interVpnLink {} key {}",
2337 interVpnLinkName, flowRef);
2339 for (BigInteger dpId : targetDpns) {
2340 LOG.debug("Removing flow: VrfEntry=[prefix={} nexthop={}] dpn {} for InterVpnLink {} in FIB",
2341 vrfEntry.getDestPrefix(), nextHop,
2342 dpId, interVpnLinkName);
2344 mdsalManager.removeFlow(dpId, flow);
2350 optionalLabel.ifPresent(label -> {
2351 LOG.trace("Removing flow in FIB table for interVpnLink {}", interVpnLinkName);
2353 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
2354 for (BigInteger dpId : targetDpns) {
2355 LOG.debug("Removing flow: VrfEntry=[prefix={} label={}] dpn {} for InterVpnLink {} in LFIB",
2356 vrfEntry.getDestPrefix(), label,
2357 dpId, interVpnLinkName);
2358 makeLFibTableEntry(dpId, label, null /* no instructions */,
2359 LFIB_INTERVPN_PRIORITY, NwConstants.DEL_FLOW, tx);
2365 private Consumer<? super VrfEntry> getConsumerForCreatingRemoteFib(
2366 final BigInteger dpnId, final long vpnId, final String rd,
2367 final String remoteNextHopIp, final Optional<VrfTables> vrfTable,
2368 WriteTransaction writeCfgTxn) {
2369 return vrfEntry -> vrfEntry.getRoutePaths().stream()
2370 .filter(routes -> !routes.getNexthopAddress().isEmpty()
2371 && remoteNextHopIp.trim().equals(routes.getNexthopAddress().trim()))
2373 .ifPresent(routes -> {
2374 LOG.trace("creating remote FIB entry for prefix {} rd {} on Dpn {}",
2375 vrfEntry.getDestPrefix(), rd, dpnId);
2376 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeCfgTxn);
2380 private Consumer<? super VrfEntry> getConsumerForDeletingRemoteFib(
2381 final BigInteger dpnId, final long vpnId, final String rd,
2382 final String remoteNextHopIp, final Optional<VrfTables> vrfTable,
2383 WriteTransaction writeCfgTxn) {
2384 return vrfEntry -> vrfEntry.getRoutePaths().stream()
2385 .filter(routes -> !routes.getNexthopAddress().isEmpty()
2386 && remoteNextHopIp.trim().equals(routes.getNexthopAddress().trim()))
2388 .ifPresent(routes -> {
2389 LOG.trace(" deleting remote FIB entry {}", vrfEntry);
2390 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeCfgTxn);
2394 private boolean isPrefixAndNextHopPresentInLri(String prefix,
2395 List<String> nextHopAddressList, LabelRouteInfo lri) {
2396 return lri != null && lri.getPrefix().equals(prefix)
2397 && nextHopAddressList.contains(lri.getNextHopIpList().get(0));