2 * Copyright (c) 2015 - 2016 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;
15 import java.math.BigInteger;
16 import java.net.Inet4Address;
17 import java.net.InetAddress;
18 import java.net.UnknownHostException;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.List;
24 import java.util.concurrent.BlockingQueue;
25 import java.util.concurrent.Callable;
26 import java.util.concurrent.ExecutionException;
27 import java.util.concurrent.Future;
28 import java.util.concurrent.LinkedBlockingQueue;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
31 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
34 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
35 import org.opendaylight.genius.mdsalutil.ActionInfo;
36 import org.opendaylight.genius.mdsalutil.FlowEntity;
37 import org.opendaylight.genius.mdsalutil.InstructionInfo;
38 import org.opendaylight.genius.mdsalutil.MDSALUtil;
39 import org.opendaylight.genius.mdsalutil.MatchInfo;
40 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
41 import org.opendaylight.genius.mdsalutil.NwConstants;
42 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
43 import org.opendaylight.genius.mdsalutil.actions.ActionMoveSourceDestinationEth;
44 import org.opendaylight.genius.mdsalutil.actions.ActionMoveSourceDestinationIp;
45 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
46 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
47 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
48 import org.opendaylight.genius.mdsalutil.actions.ActionPushMpls;
49 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetDestination;
50 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
51 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldMplsLabel;
52 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
53 import org.opendaylight.genius.mdsalutil.actions.ActionSetIcmpType;
54 import org.opendaylight.genius.mdsalutil.actions.ActionSetSourceIp;
55 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
56 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
57 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
58 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
59 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
60 import org.opendaylight.genius.mdsalutil.matches.MatchIcmpv4;
61 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
62 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
63 import org.opendaylight.genius.mdsalutil.matches.MatchIpv6Destination;
64 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
65 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
66 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
67 import org.opendaylight.genius.utils.ServiceIndex;
68 import org.opendaylight.genius.utils.batching.ActionableResource;
69 import org.opendaylight.genius.utils.batching.ActionableResourceImpl;
70 import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
71 import org.opendaylight.genius.utils.batching.ResourceHandler;
72 import org.opendaylight.genius.utils.batching.SubTransaction;
73 import org.opendaylight.genius.utils.batching.SubTransactionImpl;
74 import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
75 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
76 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
77 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
78 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
79 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
80 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
81 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetTunnelTypeInputBuilder;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetTunnelTypeOutput;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthopBuilder;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroute;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesBuilder;
121 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
122 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
123 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
124 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;
125 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder;
126 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey;
127 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn;
128 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.VpnKey;
129 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute;
130 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey;
131 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
132 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState.State;
133 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
134 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
135 import org.opendaylight.yangtools.yang.binding.DataObject;
136 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
137 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
138 import org.opendaylight.yangtools.yang.common.RpcResult;
139 import org.slf4j.Logger;
140 import org.slf4j.LoggerFactory;
142 public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry, VrfEntryListener>
143 implements AutoCloseable, ResourceHandler {
145 private static final Logger LOG = LoggerFactory.getLogger(VrfEntryListener.class);
146 private static final String FLOWID_PREFIX = "L3.";
147 private final DataBroker dataBroker;
148 private final IMdsalApiManager mdsalManager;
149 private IVpnManager vpnmanager;
150 private final NexthopManager nextHopManager;
151 private ItmRpcService itmManager;
152 private final OdlInterfaceRpcService interfaceManager;
153 private final IdManagerService idManager;
154 private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16);
155 private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
156 private static final int LFIB_INTERVPN_PRIORITY = 1;
157 private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16);
158 private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0);
159 public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
160 List<SubTransaction> transactionObjects;
161 private static final int PERIODICITY = 500;
162 private static Integer batchSize;
163 private static Integer batchInterval;
164 private static final int BATCH_SIZE = 1000;
165 private static BlockingQueue<ActionableResource> vrfEntryBufferQ = new LinkedBlockingQueue<>();
166 private final ResourceBatchingManager resourceBatchingManager;
168 public VrfEntryListener(final DataBroker dataBroker, final IMdsalApiManager mdsalApiManager,
169 final NexthopManager nexthopManager, final OdlInterfaceRpcService interfaceManager,
170 final IdManagerService idManager) {
171 super(VrfEntry.class, VrfEntryListener.class);
172 this.dataBroker = dataBroker;
173 this.mdsalManager = mdsalApiManager;
174 this.nextHopManager = nexthopManager;
175 this.interfaceManager = interfaceManager;
176 this.idManager = idManager;
178 batchSize = Integer.getInteger("batch.size");
179 if (batchSize == null) {
180 batchSize = BATCH_SIZE;
182 batchInterval = Integer.getInteger("batch.wait.time");
183 if (batchInterval == null) {
184 batchInterval = PERIODICITY;
186 resourceBatchingManager = ResourceBatchingManager.getInstance();
187 resourceBatchingManager.registerBatchableResource("FIB-VRFENTRY", vrfEntryBufferQ, this);
188 transactionObjects = new ArrayList<>();
191 public void start() {
192 LOG.info("{} start", getClass().getSimpleName());
193 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
197 protected VrfEntryListener getDataTreeChangeListener() {
198 return VrfEntryListener.this;
202 protected InstanceIdentifier<VrfEntry> getWildCardPath() {
203 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
207 public DataBroker getResourceBroker() {
212 protected void add(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
213 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
214 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
215 LOG.debug("ADD: Adding Fib Entry rd {} prefix {} nexthop {} label {}",
216 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
217 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
218 createFibEntries(identifier, vrfEntry);
220 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + vrfEntry.getDestPrefix());
221 actResource.setAction(ActionableResource.CREATE);
222 actResource.setInstanceIdentifier(identifier);
223 actResource.setInstance(vrfEntry);
224 vrfEntryBufferQ.add(actResource);
226 leakRouteIfNeeded(identifier, vrfEntry, NwConstants.ADD_FLOW);
227 LOG.info("ADD: Added Fib Entry rd {} prefix {} nexthop {} label {}",
228 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
232 protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
233 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
234 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
235 LOG.debug("REMOVE: Removing Fib Entry rd {} prefix {} nexthop {} label {}",
236 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
237 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
238 deleteFibEntries(identifier, vrfEntry);
240 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + vrfEntry.getDestPrefix());
241 actResource.setAction(ActionableResource.DELETE);
242 actResource.setInstanceIdentifier(identifier);
243 actResource.setInstance(vrfEntry);
244 vrfEntryBufferQ.add(actResource);
246 leakRouteIfNeeded(identifier, vrfEntry, NwConstants.DEL_FLOW);
247 LOG.info("REMOVE: Removed Fib Entry rd {} prefix {} nexthop {} label {}",
248 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
252 protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
253 Preconditions.checkNotNull(update, "VrfEntry should not be null or empty.");
255 final String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
256 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
257 LOG.debug("UPDATE: Updating Fib Entries to rd {} prefix {} nexthop {} label {}",
258 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
259 // Handle BGP Routes first
260 if (RouteOrigin.value(update.getOrigin()) == RouteOrigin.BGP) {
261 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + update.getDestPrefix());
262 actResource.setAction(ActionableResource.UPDATE);
263 actResource.setInstanceIdentifier(identifier);
264 actResource.setInstance(update);
265 actResource.setOldInstance(original);
266 vrfEntryBufferQ.add(actResource);
267 LOG.info("UPDATE: Updated Fib Entries to rd {} prefix {} nexthop {} label {}",
268 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
272 // Handle Internal Routes next (ie., STATIC only)
273 if (FibUtil.isControllerManagedNonInterVpnLinkRoute(RouteOrigin.value(update.getOrigin()))) {
274 SubnetRoute subnetRoute = update.getAugmentation(SubnetRoute.class);
275 /* Ignore SubnetRoute entry, as it will be driven by createFibEntries call down below */
276 if (subnetRoute == null) {
277 List<String> origNhList = original.getNextHopAddressList();
278 List<String> updateNhList = update.getNextHopAddressList();
279 //final SubnetRoute subnetRoute = update.getAugmentation(SubnetRoute.class);
280 LOG.info("UPDATE: Original nexthop {} updateNextHop {} ", origNhList, updateNhList);
282 // If original VRF Entry had nexthop null , but update VRF Entry
283 // has nexthop , route needs to be created on remote Dpns
284 if (((origNhList == null) || (origNhList.isEmpty())
285 && (updateNhList != null) && (!updateNhList.isEmpty()))) {
286 // TODO(vivek): Though ugly, Not handling this code now, as each
287 // tep add event will invoke flow addition
288 LOG.trace("Original VRF entry NH is null for destprefix {}. This event is IGNORED here.",
289 update.getDestPrefix());
293 // If original VRF Entry had valid nexthop , but update VRF Entry
294 // has nexthop empty'ed out, route needs to be removed from remote Dpns
295 if (((updateNhList == null) || (updateNhList.isEmpty())
296 && (origNhList != null) && (!origNhList.isEmpty()))) {
297 LOG.trace("Original VRF entry had valid NH for destprefix {}. This event is IGNORED here.",
298 update.getDestPrefix());
302 createFibEntries(identifier, update);
303 LOG.info("UPDATE: Updated Fib Entries to rd {} prefix {} nexthop {} label {}",
304 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
308 /* Handl all other route origins */
309 createFibEntries(identifier, update);
311 LOG.info("UPDATE: Updated Fib Entries to rd {} prefix {} nexthop {} label {}",
312 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
316 public void update(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier,
317 Object original, Object update, List<SubTransaction> transactionObjects) {
318 this.transactionObjects = transactionObjects;
319 if ((original instanceof VrfEntry) && (update instanceof VrfEntry)) {
320 createFibEntries(tx, identifier, (VrfEntry) update);
325 public void create(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier,
326 Object vrfEntry, List<SubTransaction> transactionObjects) {
327 this.transactionObjects = transactionObjects;
328 if (vrfEntry instanceof VrfEntry) {
329 createFibEntries(tx, identifier, (VrfEntry) vrfEntry);
334 public void delete(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier,
335 Object vrfEntry, List<SubTransaction> transactionObjects) {
336 this.transactionObjects = transactionObjects;
337 if (vrfEntry instanceof VrfEntry) {
338 deleteFibEntries(tx, identifier, (VrfEntry) vrfEntry);
343 public int getBatchSize() {
348 public int getBatchInterval() {
349 return batchInterval;
353 public LogicalDatastoreType getDatastoreType() {
354 return LogicalDatastoreType.CONFIGURATION;
357 private void createFibEntries(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
358 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
360 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
361 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
362 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId()
363 + " has null vpnId!");
365 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
366 final Long vpnId = vpnInstance.getVpnId();
367 final String rd = vrfTableKey.getRouteDistinguisher();
368 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
369 if (subnetRoute != null) {
370 final long elanTag = subnetRoute.getElantag();
371 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
372 rd, vrfEntry.getDestPrefix(), elanTag);
373 if (vpnToDpnList != null) {
374 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
375 dataStoreCoordinator.enqueueJob("FIB-" + rd.toString() + "-" + vrfEntry.getDestPrefix(),
377 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
378 for (final VpnToDpnList curDpn : vpnToDpnList) {
379 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
380 installSubnetRouteInFib(curDpn.getDpnId(), elanTag, rd, vpnId.longValue(),
384 List<ListenableFuture<Void>> futures = new ArrayList<>();
385 futures.add(tx.submit());
391 // ping responder for router interfaces
392 if (installRouterFibEntries(vrfEntry, vpnToDpnList, vpnId, NwConstants.ADD_FLOW)) {
396 final List<BigInteger> localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry);
398 if (vpnToDpnList != null) {
399 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
400 dataStoreCoordinator.enqueueJob("FIB-" + rd.toString() + "-" + vrfEntry.getDestPrefix(),
402 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
403 for (VpnToDpnList vpnDpn : vpnToDpnList) {
404 if (!localDpnIdList.contains(vpnDpn.getDpnId())) {
405 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
406 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(),
407 vrfTableKey, vrfEntry, tx);
411 List<ListenableFuture<Void>> futures = new ArrayList<>();
412 futures.add(tx.submit());
417 Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(dataBroker, rd);
418 if (optVpnUuid.isPresent()) {
419 Optional<InterVpnLinkDataComposite> optInterVpnLink =
420 InterVpnLinkCache.getInterVpnLinkByVpnId(optVpnUuid.get());
421 LOG.debug("InterVpnLink {} found in Cache: {}", optVpnUuid.get(), optInterVpnLink.isPresent());
422 if (optInterVpnLink.isPresent()) {
423 InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
424 String vpnUuid = optVpnUuid.get();
425 String routeNexthop = vrfEntry.getNextHopAddressList().get(0);
426 if (interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid)) {
427 // This is an static route that points to the other endpoint of an InterVpnLink
428 // In that case, we should add another entry in FIB table pointing to LPortDispatcher table.
429 installIVpnLinkSwitchingFlows(interVpnLink, vpnUuid, vrfEntry, vpnId);
430 installInterVpnRouteInLFib(rd, vrfEntry);
438 Please note that the following createFibEntries will be invoked only for BGP Imported Routes.
439 The invocation of the following method is via create() callback from the MDSAL Batching Infrastructure
440 provided by ResourceBatchingManager
442 private void createFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> vrfEntryIid,
443 final VrfEntry vrfEntry) {
444 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
446 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
447 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
448 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId()
449 + " has null vpnId!");
451 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
452 final String rd = vrfTableKey.getRouteDistinguisher();
453 if (vpnToDpnList != null) {
454 for (VpnToDpnList vpnDpn : vpnToDpnList) {
455 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
456 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, writeTx);
462 private boolean originMustBeLeaked(InterVpnLink ivpnLink, RouteOrigin routeOrigin) {
463 return routeOrigin == RouteOrigin.BGP && ivpnLink.isBgpRoutesLeaking()
464 || routeOrigin == RouteOrigin.STATIC && ivpnLink.isStaticRoutesLeaking()
465 || routeOrigin == RouteOrigin.CONNECTED && ivpnLink.isConnectedRoutesLeaking();
468 // FIXME: Refactoring needed here.
469 // This kind of logic must be taken to an 'upper' layer like BgpManager or VpnManager
470 private void leakRouteIfNeeded(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry,
472 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
473 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
475 String rd = vrfTableKey.getRouteDistinguisher();
476 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
477 if (vpnInstance == null) {
478 LOG.error("VPN Instance not available for route with prefix {} label {} nextHop {} RD {}. Returning...",
479 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), rd);
482 String vpnUuid = vpnInstance.getVpnInstanceName();
483 Preconditions.checkArgument(vpnUuid != null && !vpnUuid.isEmpty(),
484 "Could not find suitable VPN UUID for Route-Distinguisher=" + rd);
486 // if the new vrfEntry has been learned by Quagga BGP, its necessary to check if it's
487 // there an interVpnLink for the involved vpn in order to make learn the new route to
488 // the other part of the inter-vpn-link.
490 // For leaking, we need the InterVpnLink to be active. For removal, we just need a InterVpnLink.
491 Optional<InterVpnLink> interVpnLink =
492 (addOrRemove == NwConstants.ADD_FLOW) ? FibUtil.getActiveInterVpnLinkFromRd(dataBroker, rd)
493 : FibUtil.getInterVpnLinkByRd(dataBroker, rd);
494 if (!interVpnLink.isPresent()) {
495 LOG.debug("Could not find an InterVpnLink for Route-Distinguisher={}", rd);
499 // Ok, at this point everything is ready for the leaking/removal... but should it be performed?
500 // For removal, we remove all leaked routes, but we only leak a route if the corresponding flag is enabled.
502 addOrRemove == NwConstants.DEL_FLOW || originMustBeLeaked(interVpnLink.get(),
503 RouteOrigin.value(vrfEntry.getOrigin()));
506 boolean isVpnFirstEndpoint = interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid);
508 String theOtherVpnId = isVpnFirstEndpoint ? interVpnLink.get().getSecondEndpoint().getVpnUuid().getValue()
509 : interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue();
510 String dstVpnRd = FibUtil.getVpnRd(dataBroker, theOtherVpnId);
511 String endpointIp = isVpnFirstEndpoint ? interVpnLink.get().getFirstEndpoint().getIpAddress().getValue()
512 : interVpnLink.get().getSecondEndpoint().getIpAddress().getValue();
514 InstanceIdentifier<VrfEntry> vrfEntryIidInOtherVpn =
515 InstanceIdentifier.builder(FibEntries.class)
516 .child(VrfTables.class, new VrfTablesKey(dstVpnRd))
517 .child(VrfEntry.class, new VrfEntryKey(vrfEntry.getDestPrefix()))
519 if (addOrRemove == NwConstants.ADD_FLOW) {
520 LOG.debug("Leaking route (destination={}, nexthop={}) from Vrf={} to Vrf={}",
521 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), rd, dstVpnRd);
522 String key = rd + FibConstants.SEPARATOR + vrfEntry.getDestPrefix();
523 long label = FibUtil.getUniqueId(idManager, FibConstants.VPN_IDPOOL_NAME, key);
524 VrfEntry newVrfEntry = new VrfEntryBuilder(vrfEntry).setNextHopAddressList(Arrays.asList(endpointIp))
526 .setOrigin(RouteOrigin.INTERVPN.getValue())
528 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
529 vrfEntryIidInOtherVpn, newVrfEntry);
531 LOG.debug("Removing leaked vrfEntry={}", vrfEntryIidInOtherVpn.toString());
532 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn);
537 private Prefixes updateVpnReferencesInLri(LabelRouteInfo lri, String vpnInstanceName, boolean isPresentInList) {
538 LOG.debug("updating LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
539 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
540 prefixBuilder.setDpnId(lri.getDpnId());
541 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
542 prefixBuilder.setIpAddress(lri.getPrefix());
543 // Increment the refCount here
544 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
545 .child(LabelRouteInfo.class, new LabelRouteInfoKey(lri.getLabel())).build();
546 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri);
547 if (!isPresentInList) {
548 LOG.debug("vpnName {} is not present in LRI with label {}..", vpnInstanceName, lri.getLabel());
549 List<String> vpnInstanceNames = lri.getVpnInstanceList();
550 vpnInstanceNames.add(vpnInstanceName);
551 builder.setVpnInstanceList(vpnInstanceNames);
552 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(),
553 FibUtil.DEFAULT_CALLBACK);
555 LOG.debug("vpnName {} is present in LRI with label {}..", vpnInstanceName, lri.getLabel());
557 return prefixBuilder.build();
560 private void installSubnetRouteInFib(final BigInteger dpnId, final long elanTag, final String rd,
561 final long vpnId, final VrfEntry vrfEntry, WriteTransaction tx) {
562 Boolean wrTxPresent = true;
565 tx = dataBroker.newWriteOnlyTransaction();
567 synchronized (vrfEntry.getLabel().toString().intern()) {
568 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
569 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
570 && vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
572 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
573 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
574 FibUtil.getVpnInstanceOpData(dataBroker, rd);
575 if (vpnInstanceOpDataEntryOptional.isPresent()) {
576 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
577 if (!lri.getVpnInstanceList().contains(vpnInstanceName)) {
578 updateVpnReferencesInLri(lri, vpnInstanceName, false);
582 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
583 vrfEntry.getLabel(), lri.getVpnInterfaceName(), lri.getDpnId());
586 final List<InstructionInfo> instructions = new ArrayList<>();
587 BigInteger subnetRouteMeta = ((BigInteger.valueOf(elanTag)).shiftLeft(32))
588 .or((BigInteger.valueOf(vpnId).shiftLeft(1)));
589 instructions.add(new InstructionWriteMetadata(subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE));
590 instructions.add(new InstructionGotoTable(NwConstants.L3_SUBNET_ROUTE_TABLE));
591 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
593 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
594 List<ActionInfo> actionsInfos = new ArrayList<>();
595 // reinitialize instructions list for LFIB Table
596 final List<InstructionInfo> LFIBinstructions = new ArrayList<>();
598 actionsInfos.add(new ActionPopMpls());
599 LFIBinstructions.add(new InstructionApplyActions(actionsInfos));
600 LFIBinstructions.add(new InstructionWriteMetadata(subnetRouteMeta,
601 MetaDataUtil.METADATA_MASK_SUBNET_ROUTE));
602 LFIBinstructions.add(new InstructionGotoTable(NwConstants.L3_SUBNET_ROUTE_TABLE));
604 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), LFIBinstructions, DEFAULT_FIB_FLOW_PRIORITY,
605 NwConstants.ADD_FLOW, tx);
613 * For a given route, it installs a flow in LFIB that sets the lportTag of the other endpoint and sends to
614 * LportDispatcher table (via table 80)
616 private void installInterVpnRouteInLFib(final String rd, final VrfEntry vrfEntry) {
617 // INTERVPN routes are routes in a Vpn1 that have been leaked to Vpn2. In DC-GW, this Vpn2 route is pointing
618 // to a list of DPNs where Vpn2's VpnLink was instantiated. In these DPNs LFIB must be programmed so that the
619 // packet is commuted from Vpn2 to Vpn1.
620 Optional<String> vpnNameOpc = FibUtil.getVpnNameFromRd(dataBroker, rd);
621 if (!vpnNameOpc.isPresent()) {
622 LOG.warn("Could not find VpnInstanceName for Route-Distinguisher {}", rd);
626 String vpnName = vpnNameOpc.get();
627 List<InterVpnLink> interVpnLinks = FibUtil.getAllInterVpnLinks(dataBroker);
628 boolean interVpnLinkFound = false;
629 for (InterVpnLink interVpnLink : interVpnLinks) {
630 boolean vpnIs1stEndpoint = interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName);
631 boolean vpnIs2ndEndpoint = !vpnIs1stEndpoint
632 && interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnName);
633 if (vpnIs1stEndpoint || vpnIs2ndEndpoint) {
634 interVpnLinkFound = true;
636 Optional<InterVpnLinkState> vpnLinkState =
637 FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName());
638 if (!vpnLinkState.isPresent()
639 || !vpnLinkState.get().getState().equals(InterVpnLinkState.State.Active)) {
640 LOG.warn("InterVpnLink {}, linking VPN {} and {}, is not in Active state",
641 interVpnLink.getName(), interVpnLink.getFirstEndpoint().getVpnUuid().getValue(),
642 interVpnLink.getSecondEndpoint().getVpnUuid().getValue());
646 List<BigInteger> targetDpns = vpnIs1stEndpoint ? vpnLinkState.get().getFirstEndpointState().getDpId()
647 : vpnLinkState.get().getSecondEndpointState().getDpId();
648 Long lportTag = vpnIs1stEndpoint ? vpnLinkState.get().getSecondEndpointState().getLportTag()
649 : vpnLinkState.get().getFirstEndpointState().getLportTag();
651 LOG.trace("Installing flow in LFIB table for interVpnLink {}", interVpnLink.getName());
653 for (BigInteger dpId : targetDpns) {
654 List<ActionInfo> actionsInfos = Collections.singletonList(new ActionPopMpls());
656 List<InstructionInfo> instructions =
657 Arrays.asList(new InstructionApplyActions(actionsInfos),
658 new InstructionWriteMetadata(
659 MetaDataUtil.getMetaDataForLPortDispatcher(lportTag.intValue(),
660 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME,
661 NwConstants.L3VPN_SERVICE_INDEX)),
662 MetaDataUtil.getMetaDataMaskForLPortDispatcher()),
663 new InstructionGotoTable(NwConstants.L3_INTERFACE_TABLE));
665 LOG.debug("Installing flow: VrfEntry=[prefix={} label={} nexthop={}] dpn {} for "
666 + "InterVpnLink {} in LFIB",
667 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(),
668 dpId, interVpnLink.getName());
670 makeLFibTableEntry(dpId, vrfEntry.getLabel(), instructions, LFIB_INTERVPN_PRIORITY,
671 NwConstants.ADD_FLOW, null);
678 if (!interVpnLinkFound) {
679 LOG.warn("VrfEntry=[prefix={} label={} nexthop={}] for VPN {} has origin INTERVPN but "
680 + "no InterVpnLink could be found",
681 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), rd);
687 * Installs the flows in FIB table that, for a given route, do the switching from one VPN to the other.
689 private void installIVpnLinkSwitchingFlows(final InterVpnLinkDataComposite interVpnLink, final String vpnUuid,
690 final VrfEntry vrfEntry, long vpnTag) {
691 Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
692 Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null
693 && vrfEntry.getNextHopAddressList().size() == 1);
694 String destination = vrfEntry.getDestPrefix();
695 String nextHop = vrfEntry.getNextHopAddressList().get(0);
696 String interVpnLinkName = interVpnLink.getInterVpnLinkName();
698 // After having received a static route, we should check if the vpn is part of an inter-vpn-link.
699 // In that case, we should populate the FIB table of the VPN pointing to LPortDisptacher table
700 // using as metadata the LPortTag associated to that vpn in the inter-vpn-link.
701 if (interVpnLink.getState().or(State.Error) != State.Active) {
702 LOG.warn("Route to {} with nexthop={} cannot be installed because the interVpnLink {} is not active",
703 destination, nextHop, interVpnLinkName);
707 Optional<Long> optOtherEndpointLportTag = interVpnLink.getOtherEndpointLportTagByVpnName(vpnUuid);
708 if (!optOtherEndpointLportTag.isPresent()) {
709 LOG.warn("Could not find suitable LportTag for the endpoint opposite to vpn {} in interVpnLink {}",
710 vpnUuid, interVpnLinkName);
714 List<BigInteger> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnUuid);
715 if (targetDpns.isEmpty()) {
716 LOG.warn("Could not find DPNs for endpoint opposite to vpn {} in interVpnLink {}",
717 vpnUuid, interVpnLinkName);
721 String[] values = destination.split("/");
722 String destPrefixIpAddress = values[0];
723 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
725 List<MatchInfo> matches = new ArrayList<>();
726 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnTag), MetaDataUtil.METADATA_MASK_VRFID));
727 matches.add(MatchEthernetType.IPV4);
729 if (prefixLength != 0) {
730 matches.add(new MatchIpv4Destination(destPrefixIpAddress, Integer.toString(prefixLength)));
733 List<Instruction> instructions =
734 Arrays.asList(new InstructionWriteMetadata(
735 MetaDataUtil.getMetaDataForLPortDispatcher(optOtherEndpointLportTag.get().intValue(),
736 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants
737 .L3VPN_SERVICE_INDEX)),
738 MetaDataUtil.getMetaDataMaskForLPortDispatcher()).buildInstruction(0),
739 new InstructionGotoTable(NwConstants.L3_INTERFACE_TABLE).buildInstruction(1));
741 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
742 String flowRef = getInterVpnFibFlowRef(interVpnLinkName, destination, nextHop);
743 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
744 COOKIE_VM_FIB_TABLE, matches, instructions);
746 LOG.trace("Installing flow in FIB table for vpn {} interVpnLink {} nextHop {} key {}",
747 vpnUuid, interVpnLink.getInterVpnLinkName(), nextHop, flowRef);
749 for (BigInteger dpId : targetDpns) {
751 LOG.debug("Installing flow: VrfEntry=[prefix={} label={} nextHop={}] dpn {} for InterVpnLink {} in FIB",
752 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(),
753 dpId, interVpnLink.getInterVpnLinkName());
755 mdsalManager.installFlow(dpId, flowEntity);
760 // TODO Clean up the exception handling
761 @SuppressWarnings("checkstyle:IllegalCatch")
762 private <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
763 InstanceIdentifier<T> path) {
765 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
767 Optional<T> result = Optional.absent();
769 result = tx.read(datastoreType, path).get();
770 } catch (Exception e) {
771 throw new RuntimeException(e);
777 private List<BigInteger> getDpnIdForPrefix(DataBroker broker, Long vpnId, String rd, VrfEntry vrfEntry) {
778 List<BigInteger> returnLocalDpnId = new ArrayList<>();
779 Prefixes localNextHopInfo = FibUtil.getPrefixToInterface(broker, vpnId, vrfEntry.getDestPrefix());
781 if (localNextHopInfo == null) {
782 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
783 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
784 if (extraRoute != null) {
785 for (String nextHopIp : extraRoute.getNexthopIpList()) {
786 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
787 if (nextHopIp != null) {
788 localNextHopInfo = FibUtil.getPrefixToInterface(broker, vpnId, nextHopIp + "/32");
789 if (localNextHopInfo != null) {
790 returnLocalDpnId.add(localNextHopInfo.getDpnId());
796 returnLocalDpnId.add(localNextHopInfo.getDpnId());
799 return returnLocalDpnId;
802 private List<BigInteger> createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
803 List<BigInteger> returnLocalDpnId = new ArrayList<>();
804 Prefixes localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
805 String localNextHopIP = vrfEntry.getDestPrefix();
807 if (localNextHopInfo == null) {
808 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
809 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
810 if (extraRoute != null) {
811 for (String nextHopIp : extraRoute.getNexthopIpList()) {
812 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
813 if (nextHopIp != null) {
814 localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, nextHopIp + "/32");
815 localNextHopIP = nextHopIp + "/32";
816 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId,
817 rd, vrfEntry, vpnId);
818 returnLocalDpnId.add(dpnId);
822 if (localNextHopInfo == null) {
823 /* imported routes case */
824 synchronized (vrfEntry.getLabel().toString().intern()) {
825 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
826 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
827 && vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
828 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
829 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
830 FibUtil.getVpnInstanceOpData(dataBroker, rd);
831 if (vpnInstanceOpDataEntryOptional.isPresent()) {
832 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
833 if (lri.getVpnInstanceList().contains(vpnInstanceName)) {
834 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, true);
835 localNextHopIP = lri.getPrefix();
837 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, false);
838 localNextHopIP = lri.getPrefix();
841 if (localNextHopInfo != null) {
842 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
843 vrfEntry.getLabel(), localNextHopInfo.getVpnInterfaceName(), lri.getDpnId());
844 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP,
845 vpnId, rd, vrfEntry, lri.getParentVpnid());
846 returnLocalDpnId.add(dpnId);
853 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, vpnId);
854 returnLocalDpnId.add(dpnId);
857 return returnLocalDpnId;
860 private BigInteger checkCreateLocalFibEntry(Prefixes localNextHopInfo, String localNextHopIP,
861 final Long vpnId, final String rd,
862 final VrfEntry vrfEntry, Long parentVpnId) {
863 if (localNextHopInfo != null) {
864 final BigInteger dpnId = localNextHopInfo.getDpnId();
865 if (!isVpnPresentInDpn(rd, dpnId)) {
866 LOG.error("The vpnName with vpnId {} rd {} is not available on dpn {}", vpnId, rd, dpnId.toString());
867 return BigInteger.ZERO;
870 final long groupId = nextHopManager.createLocalNextHop(parentVpnId, dpnId,
871 localNextHopInfo.getVpnInterfaceName(), localNextHopIP, vrfEntry.getDestPrefix());
873 LOG.error("Unable to create Group for local prefix {} on rd {} for vpninterface {} on Node {}",
874 vrfEntry.getDestPrefix(), rd, localNextHopInfo.getVpnInterfaceName(), dpnId.toString());
875 return BigInteger.ZERO;
877 final List<InstructionInfo> instructions = Collections.singletonList(
878 new InstructionApplyActions(
879 Collections.singletonList(new ActionGroup(groupId))));
880 final List<InstructionInfo> lfibinstructions = Collections.singletonList(
881 new InstructionApplyActions(
882 Arrays.asList(new ActionPopMpls(), new ActionGroup(groupId))));
883 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
884 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
885 dpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
887 LOG.debug("Route with rd {} prefix {} label {} nexthop {} for vpn {} is an imported route. "
888 + "LFib and Terminating table entries will not be created.",
889 rd, vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), vpnId);
891 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
892 dataStoreCoordinator.enqueueJob("FIB-" + vpnId.toString()
893 + "-" + dpnId.toString() + "-" + vrfEntry.getDestPrefix(),
895 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
896 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
897 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
898 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), lfibinstructions,
899 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
900 makeTunnelTableEntry(dpnId, vrfEntry.getLabel(), groupId, tx);
902 List<ListenableFuture<Void>> futures = new ArrayList<>();
903 futures.add(tx.submit());
908 return BigInteger.ZERO;
911 private boolean isVpnPresentInDpn(String rd, BigInteger dpnId) {
912 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
913 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
914 if (dpnInVpn.isPresent()) {
920 private LabelRouteInfo getLabelRouteInfo(Long label) {
921 InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
922 .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build();
923 Optional<LabelRouteInfo> opResult = read(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid);
924 if (opResult.isPresent()) {
925 return opResult.get();
930 private boolean deleteLabelRouteInfo(LabelRouteInfo lri, String vpnInstanceName) {
931 LOG.debug("deleting LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
932 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
933 .child(LabelRouteInfo.class, new LabelRouteInfoKey(lri.getLabel())).build();
937 List<String> vpnInstancesList = lri.getVpnInstanceList() != null
938 ? lri.getVpnInstanceList() : new ArrayList<>();
939 if (vpnInstancesList.contains(vpnInstanceName)) {
940 LOG.debug("vpninstance {} name is present", vpnInstanceName);
941 vpnInstancesList.remove(vpnInstanceName);
943 if (vpnInstancesList.size() == 0) {
944 LOG.debug("deleting LRI instance object for label {}", lri.getLabel());
945 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId);
948 LOG.debug("updating LRI instance object for label {}", lri.getLabel());
949 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri).setVpnInstanceList(vpnInstancesList);
950 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(),
951 FibUtil.DEFAULT_CALLBACK);
956 private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/,
957 WriteTransaction tx) {
958 List<ActionInfo> actionsInfos = Collections.singletonList(new ActionGroup(groupId));
960 createTerminatingServiceActions(dpId, (int) label, actionsInfos, tx);
962 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully",
963 dpId, label, groupId);
966 public void createTerminatingServiceActions(BigInteger destDpId, int label, List<ActionInfo> actionsInfos,
967 WriteTransaction tx) {
968 List<MatchInfo> mkMatches = new ArrayList<>();
970 LOG.debug("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}",
971 destDpId, label, actionsInfos);
974 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
975 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(label)));
977 List<InstructionInfo> mkInstructions = new ArrayList<>();
978 mkInstructions.add(new InstructionApplyActions(actionsInfos));
980 FlowEntity terminatingServiceTableFlowEntity =
981 MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
982 getTableMissFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE, label), 5,
983 String.format("%s:%d", "TST Flow Entry ", label),
984 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, mkInstructions);
986 FlowKey flowKey = new FlowKey(new FlowId(terminatingServiceTableFlowEntity.getFlowId()));
988 FlowBuilder flowbld = terminatingServiceTableFlowEntity.getFlowBuilder();
990 Node nodeDpn = buildDpnNode(terminatingServiceTableFlowEntity.getDpnId());
991 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
992 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
993 .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId()))
994 .child(Flow.class, flowKey).build();
995 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flowbld.build(), true);
998 private void removeTunnelTableEntry(BigInteger dpId, long label, WriteTransaction tx) {
999 FlowEntity flowEntity;
1000 LOG.debug("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId, label);
1001 List<MatchInfo> mkMatches = new ArrayList<>();
1002 // Matching metadata
1003 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(label)));
1004 flowEntity = MDSALUtil.buildFlowEntity(dpId,
1005 NwConstants.INTERNAL_TUNNEL_TABLE,
1006 getTableMissFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int) label),
1007 5, String.format("%s:%d", "TST Flow Entry ", label), 0, 0,
1008 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
1009 Node nodeDpn = buildDpnNode(flowEntity.getDpnId());
1010 FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getFlowId()));
1011 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1012 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1013 .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build();
1015 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1016 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully", dpId, label);
1019 public List<BigInteger> deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
1020 List<BigInteger> returnLocalDpnId = new ArrayList<>();
1021 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
1022 String localNextHopIP = vrfEntry.getDestPrefix();
1024 if (localNextHopInfo == null) {
1025 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
1026 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1027 if (extraRoute != null) {
1028 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1029 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
1030 if (nextHopIp != null) {
1031 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp + "/32");
1032 localNextHopIP = nextHopIp + "/32";
1033 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
1034 vpnId, rd, vrfEntry, true /*isExtraRoute*/);
1035 if (!dpnId.equals(BigInteger.ZERO)) {
1036 returnLocalDpnId.add(dpnId);
1042 if (localNextHopInfo == null) {
1043 /* Imported VRF entry */
1044 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1045 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
1046 && vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1047 VpnNexthopBuilder vpnNexthopBuilder = new VpnNexthopBuilder();
1048 vpnNexthopBuilder.setDpnId(lri.getDpnId());
1049 BigInteger dpnId = checkDeleteLocalFibEntry(vpnNexthopBuilder.build(), localNextHopIP,
1050 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
1051 if (!dpnId.equals(BigInteger.ZERO)) {
1052 returnLocalDpnId.add(dpnId);
1058 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
1059 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
1060 if (!dpnId.equals(BigInteger.ZERO)) {
1061 returnLocalDpnId.add(dpnId);
1065 return returnLocalDpnId;
1068 private BigInteger checkDeleteLocalFibEntry(VpnNexthop localNextHopInfo, final String localNextHopIP,
1069 final Long vpnId, final String rd,
1070 final VrfEntry vrfEntry, final boolean isExtraRoute) {
1071 if (localNextHopInfo != null) {
1072 final BigInteger dpnId = localNextHopInfo.getDpnId();
1073 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1074 dataStoreCoordinator.enqueueJob("FIB-" + vpnId.toString() + "-"
1075 + dpnId.toString() + "-" + vrfEntry.getDestPrefix(),
1077 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1078 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null /* instructions */,
1079 NwConstants.DEL_FLOW, tx);
1080 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1081 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null /* instructions */,
1082 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1083 removeTunnelTableEntry(dpnId, vrfEntry.getLabel(), tx);
1085 List<ListenableFuture<Void>> futures = new ArrayList<>();
1086 futures.add(tx.submit());
1089 //TODO: verify below adjacency call need to be optimized (?)
1090 deleteLocalAdjacency(dpnId, vpnId, localNextHopIP, vrfEntry.getDestPrefix());
1093 return BigInteger.ZERO;
1096 private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
1097 return InstanceIdentifier.builder(VpnToExtraroute.class)
1098 .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class,
1099 new ExtrarouteKey(ipPrefix)).build();
1102 private Extraroute getVpnToExtraroute(String rd, String ipPrefix) {
1103 Optional<Extraroute> extraRouteInfo =
1104 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix));
1105 return extraRouteInfo.isPresent() ? extraRouteInfo.get() : null;
1109 private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
1111 Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
1112 new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
1113 RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
1114 if (!rpcResult.isSuccessful()) {
1115 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
1117 return rpcResult.getResult().getTunnelType();
1120 } catch (InterruptedException | ExecutionException e) {
1121 LOG.warn("Exception when getting tunnel interface Id for tunnel type", e);
1128 private void createRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, final VrfTablesKey vrfTableKey,
1129 final VrfEntry vrfEntry, WriteTransaction tx) {
1130 Boolean wrTxPresent = true;
1132 wrTxPresent = false;
1133 tx = dataBroker.newWriteOnlyTransaction();
1135 String rd = vrfTableKey.getRouteDistinguisher();
1136 LOG.debug("createremotefibentry: adding route {} for rd {} on remoteDpnId {}",
1137 vrfEntry.getDestPrefix(), rd, remoteDpnId);
1139 List<AdjacencyResult> adjacencyResults = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
1140 if (adjacencyResults.isEmpty()) {
1141 LOG.error("Could not get interface for nexthop: {} in vpn {}",
1142 vrfEntry.getNextHopAddressList(), rd);
1143 LOG.warn("Failed to add Route: {} in vpn: {}",
1144 vrfEntry.getDestPrefix(), rd);
1148 for (AdjacencyResult adjacencyResult : adjacencyResults) {
1149 List<ActionInfo> actionInfos = new ArrayList<>();
1150 String egressInterface = adjacencyResult.getInterfaceName();
1151 if (Tunnel.class.equals(adjacencyResult.getInterfaceType())) {
1152 addTunnelInterfaceActions(egressInterface, vpnId, vrfEntry, actionInfos);
1154 addRewriteDstMacAction(vpnId, vrfEntry, actionInfos);
1156 List<ActionInfo> egressActions = nextHopManager.getEgressActionsForInterface(egressInterface);
1157 if (egressActions.isEmpty()) {
1158 LOG.error("Failed to retrieve egress action for prefix {} nextHop {} interface {}. "
1159 + "Aborting remote FIB entry creation.",
1160 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), egressInterface);
1163 actionInfos.addAll(egressActions);
1164 List<InstructionInfo> instructions = new ArrayList<>();
1165 instructions.add(new InstructionApplyActions(actionInfos));
1166 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
1171 LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
1174 private void addRewriteDstMacAction(long vpnId, VrfEntry vrfEntry, List<ActionInfo> actionInfos) {
1175 String ipPrefix = vrfEntry.getDestPrefix();
1176 Prefixes prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, ipPrefix);
1177 if (prefixInfo == null) {
1178 LOG.debug("No prefix info found for prefix {}", ipPrefix);
1182 String ifName = prefixInfo.getVpnInterfaceName();
1183 if (ifName == null) {
1184 LOG.warn("Failed to get VPN interface for prefix {}", ipPrefix);
1188 String macAddress = FibUtil.getMacAddressFromPrefix(dataBroker, ifName, ipPrefix);
1189 if (macAddress == null) {
1190 LOG.warn("No MAC address found for VPN interface {} prefix {}", ifName, ipPrefix);
1194 actionInfos.add(new ActionSetFieldEthernetDestination(actionInfos.size(), new MacAddress(macAddress)));
1197 private void addTunnelInterfaceActions(String tunnelInterface, long vpnId, VrfEntry vrfEntry,
1198 List<ActionInfo> actionInfos) {
1199 Class<? extends TunnelTypeBase> tunnelType = getTunnelType(tunnelInterface);
1200 if (tunnelType.equals(TunnelTypeMplsOverGre.class)) {
1201 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
1202 actionInfos.add(new ActionPushMpls());
1203 actionInfos.add(new ActionSetFieldMplsLabel(vrfEntry.getLabel()));
1204 actionInfos.add(new ActionNxLoadInPort(BigInteger.ZERO));
1206 int label = vrfEntry.getLabel().intValue();
1207 BigInteger tunnelId;
1208 // FIXME vxlan vni bit set is not working properly with OVS.need to
1210 if (tunnelType.equals(TunnelTypeVxlan.class)) {
1211 tunnelId = BigInteger.valueOf(label);
1213 tunnelId = BigInteger.valueOf(label);
1216 LOG.debug("adding set tunnel id action for label {}", label);
1217 actionInfos.add(new ActionSetFieldTunnelId(tunnelId));
1218 addRewriteDstMacAction(vpnId, vrfEntry, actionInfos);
1222 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
1223 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
1224 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1225 if (dpnInVpn.isPresent()) {
1226 List<VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
1227 VpnInterfaces currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
1229 if (vpnInterfaces.remove(currVpnInterface)) {
1230 if (vpnInterfaces.isEmpty()) {
1231 LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
1232 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1233 cleanUpDpnForVpn(dpnId, vpnId, rd, null);
1235 LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
1236 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id.child(
1237 VpnInterfaces.class,
1238 new VpnInterfacesKey(intfName)));
1244 private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
1245 /* Get interface info from prefix to interface mapping;
1246 Use the interface info to get the corresponding vpn interface op DS entry,
1247 remove the adjacency corresponding to this fib entry.
1248 If adjacency removed is the last adjacency, clean up the following:
1249 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
1250 - prefix to interface entry
1251 - vpn interface op DS
1253 LOG.debug("Cleanup of prefix {} in VPN {}", vrfEntry.getDestPrefix(), vpnId);
1254 Prefixes prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
1255 Extraroute extraRoute = null;
1256 if (prefixInfo == null) {
1257 extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1258 if (extraRoute != null) {
1259 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1260 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
1262 if (nextHopIp != null) {
1263 prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, nextHopIp + "/32");
1264 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1268 if (prefixInfo == null) {
1269 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1270 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
1271 && vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1272 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
1273 prefixBuilder.setDpnId(lri.getDpnId());
1274 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
1275 prefixBuilder.setIpAddress(lri.getPrefix());
1276 prefixInfo = prefixBuilder.build();
1277 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
1278 vrfEntry.getLabel(), prefixInfo.getVpnInterfaceName(), lri.getDpnId());
1279 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1283 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1287 private void checkCleanUpOpDataForFib(final Prefixes prefixInfo, final Long vpnId, final String rd,
1288 final VrfEntry vrfEntry, final Extraroute extraRoute) {
1290 if (prefixInfo == null) {
1291 LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for prefix {}", vrfEntry.getDestPrefix());
1292 return; //Don't have any info for this prefix (shouldn't happen); need to return
1295 String ifName = prefixInfo.getVpnInterfaceName();
1296 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1297 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + ifName,
1298 new CleanupVpnInterfaceWorker(prefixInfo, vpnId, rd, vrfEntry, extraRoute));
1301 private class CleanupVpnInterfaceWorker implements Callable<List<ListenableFuture<Void>>> {
1302 Prefixes prefixInfo;
1306 Extraroute extraRoute;
1308 CleanupVpnInterfaceWorker(final Prefixes prefixInfo, final Long vpnId, final String rd,
1309 final VrfEntry vrfEntry, final Extraroute extraRoute) {
1310 this.prefixInfo = prefixInfo;
1313 this.vrfEntry = vrfEntry;
1314 this.extraRoute = extraRoute;
1318 public List<ListenableFuture<Void>> call() throws Exception {
1319 // If another renderer(for eg : CSS) needs to be supported, check can be performed here
1320 // to call the respective helpers.
1322 //First Cleanup LabelRouteInfo
1323 synchronized (vrfEntry.getLabel().toString().intern()) {
1324 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1325 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
1326 && vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1327 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
1328 FibUtil.getVpnInstanceOpData(dataBroker, rd);
1329 String vpnInstanceName = "";
1330 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1331 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1333 boolean lriRemoved = deleteLabelRouteInfo(lri, vpnInstanceName);
1335 String parentRd = lri.getParentVpnRd();
1336 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1337 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1340 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1341 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1344 String ifName = prefixInfo.getVpnInterfaceName();
1345 Optional<VpnInterface> optvpnInterface = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1346 FibUtil.getVpnInterfaceIdentifier(ifName));
1347 if (optvpnInterface.isPresent()) {
1348 long associatedVpnId = FibUtil.getVpnId(dataBroker, optvpnInterface.get().getVpnInstanceName());
1349 if (vpnId != associatedVpnId) {
1350 LOG.warn("Prefixes {} are associated with different vpn instance with id : {} rather than {}",
1351 vrfEntry.getDestPrefix(), associatedVpnId, vpnId);
1352 LOG.warn("Not proceeding with Cleanup op data for prefix {}", vrfEntry.getDestPrefix());
1355 LOG.debug("Processing cleanup of prefix {} associated with vpn {}",
1356 vrfEntry.getDestPrefix(), associatedVpnId);
1359 if (extraRoute != null) {
1360 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1361 FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
1363 Optional<Adjacencies> optAdjacencies = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1364 FibUtil.getAdjListPath(ifName));
1366 if (optAdjacencies.isPresent()) {
1367 numAdj = optAdjacencies.get().getAdjacency().size();
1369 //remove adjacency corr to prefix
1371 LOG.info("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix());
1372 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1373 FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
1375 if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
1376 //clean up the vpn interface from DpnToVpn list
1377 LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
1378 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1379 FibUtil.getVpnInterfaceIdentifier(ifName));
1385 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1386 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1387 final String rd = vrfTableKey.getRouteDistinguisher();
1388 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1389 if (vpnInstance == null) {
1390 LOG.error("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1393 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1395 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1396 if (subnetRoute != null) {
1397 elanTag = subnetRoute.getElantag();
1398 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
1399 rd, vrfEntry.getDestPrefix(), elanTag);
1400 if (vpnToDpnList != null) {
1401 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1402 dataStoreCoordinator.enqueueJob("FIB-" + rd.toString() + "-" + vrfEntry.getDestPrefix(),
1404 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1406 for (final VpnToDpnList curDpn : vpnToDpnList) {
1408 makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry,
1409 vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW, tx);
1410 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1411 makeLFibTableEntry(curDpn.getDpnId(), vrfEntry.getLabel(), null,
1412 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1415 List<ListenableFuture<Void>> futures = new ArrayList<>();
1416 futures.add(tx.submit());
1420 synchronized (vrfEntry.getLabel().toString().intern()) {
1421 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1422 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
1423 && vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1424 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
1425 FibUtil.getVpnInstanceOpData(dataBroker, rd);
1426 String vpnInstanceName = "";
1427 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1428 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1430 boolean lriRemoved = this.deleteLabelRouteInfo(lri, vpnInstanceName);
1432 String parentRd = lri.getParentVpnRd();
1433 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1434 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1435 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {} as "
1436 + "labelRouteInfo cleared", vrfEntry.getLabel(), rd,
1437 vrfEntry.getDestPrefix());
1440 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1441 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1442 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {}",
1443 vrfEntry.getLabel(), rd, vrfEntry.getDestPrefix());
1448 if (installRouterFibEntries(vrfEntry, vpnToDpnList, vpnInstance.getVpnId(), NwConstants.DEL_FLOW)) {
1452 final List<BigInteger> localDpnIdList = deleteLocalFibEntry(vpnInstance.getVpnId(),
1453 vrfTableKey.getRouteDistinguisher(), vrfEntry);
1454 if (vpnToDpnList != null) {
1455 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1456 dataStoreCoordinator.enqueueJob("FIB-" + rd.toString() + "-" + vrfEntry.getDestPrefix(),
1458 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1460 if (localDpnIdList.size() <= 0) {
1461 for (VpnToDpnList curDpn : vpnToDpnList) {
1462 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1463 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1464 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(),
1465 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1468 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(),
1469 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1473 for (BigInteger localDpnId : localDpnIdList) {
1474 for (VpnToDpnList curDpn : vpnToDpnList) {
1475 if (!curDpn.getDpnId().equals(localDpnId)) {
1476 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1477 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1478 deleteRemoteRoute(localDpnId, curDpn.getDpnId(),
1479 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1482 deleteRemoteRoute(localDpnId, curDpn.getDpnId(),
1483 vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1489 List<ListenableFuture<Void>> futures = new ArrayList<>();
1490 futures.add(tx.submit());
1495 //The flow/group entry has been deleted from config DS; need to clean up associated operational
1496 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
1497 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
1499 // Remove all fib entries configured due to interVpnLink, when nexthop is the opposite endPoint
1500 // of the interVpnLink.
1501 Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(this.dataBroker, rd);
1502 if (optVpnUuid.isPresent()) {
1503 String vpnUuid = optVpnUuid.get();
1504 List<String> routeNexthoplist = vrfEntry.getNextHopAddressList();
1505 if (routeNexthoplist.isEmpty()) {
1506 LOG.trace("NextHopList is empty for VrfEntry {}", vrfEntry);
1509 String routeNexthop = routeNexthoplist.get(0);
1510 Optional<InterVpnLinkDataComposite> optInterVpnLink = InterVpnLinkCache.getInterVpnLinkByVpnId(vpnUuid);
1511 if (optInterVpnLink.isPresent()) {
1512 InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
1513 if (interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid)) {
1514 // This is route that points to the other endpoint of an InterVpnLink
1515 // In that case, we should look for the FIB table pointing to LPortDispatcher table and remove it.
1516 removeInterVPNLinkRouteFlows(interVpnLink.getInterVpnLinkName(),
1517 interVpnLink.isFirstEndpointVpnName(rd),
1526 Please note that the following deleteFibEntries will be invoked only for BGP Imported Routes.
1527 The invocation of the following method is via delete() callback from the MDSAL Batching Infrastructure
1528 provided by ResourceBatchingManager
1530 private void deleteFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> identifier,
1531 final VrfEntry vrfEntry) {
1532 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1534 final String rd = vrfTableKey.getRouteDistinguisher();
1535 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1536 if (vpnInstance == null) {
1537 LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1540 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1541 if (vpnToDpnList != null) {
1542 for (VpnToDpnList curDpn : vpnToDpnList) {
1543 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1544 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(),
1545 vrfTableKey, vrfEntry, writeTx);
1551 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
1552 final long vpnId, final VrfTablesKey vrfTableKey,
1553 final VrfEntry vrfEntry, WriteTransaction tx) {
1555 Boolean wrTxPresent = true;
1557 wrTxPresent = false;
1558 tx = dataBroker.newWriteOnlyTransaction();
1561 LOG.debug("deleting remote route: prefix={}, vpnId={} localDpnId {} remoteDpnId {}",
1562 vrfEntry.getDestPrefix(), vpnId, localDpnId, remoteDpnId);
1563 String rd = vrfTableKey.getRouteDistinguisher();
1565 if (localDpnId != null) {
1566 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
1567 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1571 // below two reads are kept as is, until best way is found to identify dpnID
1572 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
1573 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1575 if (localNextHopInfo == null && extraRoute != null) {
1576 // Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
1577 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1578 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp);
1579 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1582 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1589 private boolean checkDpnDeleteFibEntry(VpnNexthop localNextHopInfo, BigInteger remoteDpnId, long vpnId,
1590 VrfEntry vrfEntry, String rd, WriteTransaction tx) {
1591 boolean isRemoteRoute = true;
1592 if (localNextHopInfo != null) {
1593 isRemoteRoute = !remoteDpnId.equals(localNextHopInfo.getDpnId());
1595 if (isRemoteRoute) {
1596 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1599 LOG.debug("Did not delete FIB entry: rd={}, vrfEntry={}, as it is local to dpnId={}",
1600 rd, vrfEntry.getDestPrefix(), remoteDpnId);
1605 private void deleteFibEntry(BigInteger remoteDpnId, long vpnId, VrfEntry vrfEntry, String rd, WriteTransaction tx) {
1606 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1607 LOG.debug("Successfully delete FIB entry: vrfEntry={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
1610 private long get(byte[] rawIpAddress) {
1611 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
1612 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
1615 private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
1616 List<InstructionInfo> instructions, int addOrRemove, WriteTransaction tx) {
1617 Boolean wrTxPresent = true;
1619 wrTxPresent = false;
1620 tx = dataBroker.newWriteOnlyTransaction();
1623 LOG.trace("makeConnectedRoute: vrfEntry {}", vrfEntry);
1624 String[] values = vrfEntry.getDestPrefix().split("/");
1625 String ipAddress = values[0];
1626 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
1627 if (addOrRemove == NwConstants.ADD_FLOW) {
1628 LOG.debug("Adding route to DPN {} for rd {} prefix {} ", dpId, rd, vrfEntry.getDestPrefix());
1630 LOG.debug("Removing route from DPN {} for rd {} prefix {}", dpId, rd, vrfEntry.getDestPrefix());
1632 InetAddress destPrefix;
1634 destPrefix = InetAddress.getByName(ipAddress);
1635 } catch (UnknownHostException e) {
1636 LOG.error("Failed to get destPrefix for prefix {} ", vrfEntry.getDestPrefix(), e);
1640 List<MatchInfo> matches = new ArrayList<>();
1642 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
1644 if (destPrefix instanceof Inet4Address) {
1645 matches.add(MatchEthernetType.IPV4);
1646 if (prefixLength != 0) {
1647 matches.add(new MatchIpv4Destination(destPrefix.getHostAddress(), Integer.toString(prefixLength)));
1650 matches.add(MatchEthernetType.IPV6);
1651 if (prefixLength != 0) {
1652 matches.add(new MatchIpv6Destination(destPrefix.getHostAddress() + "/" + prefixLength));
1656 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
1657 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, priority, destPrefix);
1658 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef, priority,
1660 COOKIE_VM_FIB_TABLE, matches, instructions);
1662 Flow flow = flowEntity.getFlowBuilder().build();
1663 String flowId = flowEntity.getFlowId();
1664 FlowKey flowKey = new FlowKey(new FlowId(flowId));
1665 Node nodeDpn = buildDpnNode(dpId);
1667 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1668 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1669 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1671 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1672 SubTransaction subTransaction = new SubTransactionImpl();
1673 if (addOrRemove == NwConstants.ADD_FLOW) {
1674 subTransaction.setInstanceIdentifier(flowInstanceId);
1675 subTransaction.setInstance(flow);
1676 subTransaction.setAction(SubTransaction.CREATE);
1678 subTransaction.setInstanceIdentifier(flowInstanceId);
1679 subTransaction.setAction(SubTransaction.DELETE);
1681 transactionObjects.add(subTransaction);
1684 if (addOrRemove == NwConstants.ADD_FLOW) {
1685 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
1687 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1695 //TODO: How to handle the below code, its a copy paste from MDSALManager.java
1696 private Node buildDpnNode(BigInteger dpnId) {
1697 NodeId nodeId = new NodeId("openflow:" + dpnId);
1698 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
1703 private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions, int priority,
1704 int addOrRemove, WriteTransaction tx) {
1705 Boolean wrTxPresent = true;
1707 wrTxPresent = false;
1708 tx = dataBroker.newWriteOnlyTransaction();
1711 List<MatchInfo> matches = new ArrayList<>();
1712 matches.add(MatchEthernetType.MPLS_UNICAST);
1713 matches.add(new MatchMplsLabel(label));
1715 // Install the flow entry in L3_LFIB_TABLE
1716 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, priority);
1718 FlowEntity flowEntity;
1719 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef, priority, flowRef, 0, 0,
1720 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
1721 Flow flow = flowEntity.getFlowBuilder().build();
1722 String flowId = flowEntity.getFlowId();
1723 FlowKey flowKey = new FlowKey(new FlowId(flowId));
1724 Node nodeDpn = buildDpnNode(dpId);
1725 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1726 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1727 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1729 if (addOrRemove == NwConstants.ADD_FLOW) {
1730 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow, true);
1732 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1738 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} : key {} {} successfully",
1739 dpId, label, instructions, flowKey, (NwConstants.ADD_FLOW == addOrRemove) ? "ADDED" : "REMOVED");
1742 private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress,
1743 final String ipPrefixAddress) {
1744 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}", dpId, vpnId, ipAddress);
1746 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress, ipPrefixAddress);
1747 } catch (NullPointerException e) {
1752 public void populateFibOnNewDpn(final BigInteger dpnId, final long vpnId, final String rd,
1753 final FutureCallback<List<Void>> callback) {
1754 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
1755 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1756 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1757 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1758 if (!vrfTable.isPresent()) {
1759 LOG.warn("VRF Table not yet available for RD {}", rd);
1760 if (callback != null) {
1761 List<ListenableFuture<Void>> futures = new ArrayList<>();
1762 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1763 Futures.addCallback(listenableFuture, callback);
1767 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1768 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1770 List<ListenableFuture<Void>> futures = new ArrayList<>();
1771 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1772 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1773 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1774 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1775 if (subnetRoute != null) {
1776 long elanTag = subnetRoute.getElantag();
1777 installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
1780 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
1781 if (routerInt != null) {
1782 LOG.trace("Router augmented vrfentry found rd:{}, uuid:{}, ip:{}, mac:{}",
1783 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
1784 installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(),
1785 routerInt.getIpAddress(),
1786 new MacAddress(routerInt.getMacAddress()), NwConstants.ADD_FLOW);
1789 //Handle local flow creation for imports
1790 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
1791 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1792 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
1793 && vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1794 if (lri.getDpnId().equals(dpnId)) {
1795 createLocalFibEntry(vpnId, rd, vrfEntry);
1800 // Passing null as we don't know the dpn
1801 // to which prefix is attached at this point
1802 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1804 //TODO: if we have 100K entries in FIB, can it fit in one Tranasaction (?)
1805 futures.add(tx.submit());
1807 if (callback != null) {
1808 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1809 Futures.addCallback(listenableFuture, callback);
1816 public void populateExternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1817 final String localNextHopIp, final String remoteNextHopIp) {
1818 LOG.trace("populateExternalRoutesOnDpn : dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} ",
1819 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1820 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1821 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1822 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1823 if (vrfTable.isPresent()) {
1824 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1825 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1827 List<ListenableFuture<Void>> futures = new ArrayList<>();
1828 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1829 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
1830 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1831 if (!vrfEntry.getNextHopAddressList().isEmpty()) {
1832 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1833 if (remoteNextHopIp.trim()
1834 .equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1835 LOG.trace(" creating remote FIB entry for prefix {} rd {}",
1836 vrfEntry.getDestPrefix(), rd);
1837 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(),
1838 vrfEntry, writeCfgTxn);
1843 futures.add(writeCfgTxn.submit());
1850 public void populateInternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1851 final String localNextHopIp, final String remoteNextHopIp) {
1852 LOG.trace("populateInternalRoutesOnDpn : dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} ",
1853 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1854 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1855 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1856 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1857 if (vrfTable.isPresent()) {
1858 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1859 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1861 List<ListenableFuture<Void>> futures = new ArrayList<>();
1862 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1863 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
1864 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1865 // Handle Internal Routes only (i.e., STATIC for now)
1866 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.STATIC) {
1867 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1868 /* Ignore SubnetRoute entry */
1869 if (subnetRoute == null) {
1870 if (!vrfEntry.getNextHopAddressList().isEmpty()) {
1871 if (remoteNextHopIp.trim()
1872 .equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1873 LOG.trace(" creating remote FIB entry for prefix {} rd {} on Dpn {}",
1874 vrfEntry.getDestPrefix(), rd, dpnId);
1875 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry,
1882 futures.add(writeCfgTxn.submit());
1889 public void manageRemoteRouteOnDPN(final boolean action,
1890 final BigInteger localDpnId,
1893 final String destPrefix,
1894 final String destTepIp) {
1895 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1897 if (vpnInstance == null) {
1898 LOG.error("VpnInstance for rd {} not present for prefix {}", rd, destPrefix);
1901 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1902 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + localDpnId.toString(),
1904 List<ListenableFuture<Void>> futures = new ArrayList<>();
1905 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1906 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1907 VrfTablesKey vrfTablesKey = new VrfTablesKey(rd);
1908 VrfEntry vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1909 if (vrfEntry == null) {
1912 LOG.trace("manageRemoteRouteOnDPN :: action {}, DpnId {}, vpnId {}, rd {}, destPfx {}",
1913 action, localDpnId, vpnId, rd, destPrefix);
1914 List<String> nextHopAddressList = vrfEntry.getNextHopAddressList();
1915 VrfEntry modVrfEntry;
1916 if (nextHopAddressList == null || (nextHopAddressList.isEmpty())) {
1917 List<String> nhList = Arrays.asList(destTepIp);
1918 modVrfEntry = new VrfEntryBuilder(vrfEntry).setNextHopAddressList(nhList).build();
1920 modVrfEntry = vrfEntry;
1923 if (action == true) {
1924 LOG.trace("manageRemoteRouteOnDPN updated(add) vrfEntry :: {}", modVrfEntry);
1925 createRemoteFibEntry(localDpnId, vpnId, vrfTablesKey, modVrfEntry, writeTransaction);
1927 LOG.trace("manageRemoteRouteOnDPN updated(remove) vrfEntry :: {}", modVrfEntry);
1928 deleteRemoteRoute(null, localDpnId, vpnId, vrfTablesKey, modVrfEntry, writeTransaction);
1930 futures.add(writeTransaction.submit());
1936 public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd,
1937 final FutureCallback<List<Void>> callback) {
1938 LOG.trace("cleanUpDpnForVpn: Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
1939 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1940 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1941 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1942 if (vrfTable.isPresent()) {
1943 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1944 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1946 List<ListenableFuture<Void>> futures = new ArrayList<>();
1947 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1948 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1949 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1950 /* Handle subnet routes here */
1951 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1952 if (subnetRoute != null) {
1953 LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn",
1954 vrfEntry.getDestPrefix(),
1956 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1957 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null, DEFAULT_FIB_FLOW_PRIORITY,
1958 NwConstants.DEL_FLOW, tx);
1959 LOG.trace("cleanUpDpnForVpn: Released subnetroute label {} for rd {} prefix {}",
1960 vrfEntry.getLabel(), rd,
1961 vrfEntry.getDestPrefix());
1964 // ping responder for router interfaces
1965 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
1966 if (routerInt != null) {
1967 LOG.trace("Router augmented vrfentry found for rd:{}, uuid:{}, ip:{}, mac:{}",
1968 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
1969 installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(),
1970 routerInt.getIpAddress(),
1971 new MacAddress(routerInt.getMacAddress()), NwConstants.DEL_FLOW);
1974 // Passing null as we don't know the dpn
1975 // to which prefix is attached at this point
1976 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1978 futures.add(tx.submit());
1979 if (callback != null) {
1980 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1981 Futures.addCallback(listenableFuture, callback);
1989 public void cleanUpExternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1990 final String localNextHopIp, final String remoteNextHopIp) {
1991 LOG.trace("cleanUpExternalRoutesOnDpn : cleanup remote routes on dpn {} for vpn {}, rd {}, "
1992 + " localNexthopIp {} , remoteNexhtHopIp {}",
1993 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1994 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1995 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1996 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1997 if (vrfTable.isPresent()) {
1998 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1999 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
2001 List<ListenableFuture<Void>> futures = new ArrayList<>();
2002 synchronized (vpnInstance.getVpnInstanceName().intern()) {
2003 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
2004 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
2005 if (!vrfEntry.getNextHopAddressList().isEmpty()) {
2006 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
2007 if (remoteNextHopIp.trim()
2008 .equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
2009 LOG.trace(" deleting remote FIB entry {}", vrfEntry);
2010 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(),
2011 vrfEntry, writeTransaction);
2016 futures.add(writeTransaction.submit());
2023 public void cleanUpInternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
2024 final String localNextHopIp, final String remoteNextHopIp) {
2025 LOG.trace("cleanUpInternalRoutesOnDpn : cleanup remote routes on dpn {} for vpn {}, rd {}, "
2026 + " localNexthopIp {} , remoteNexhtHopIp {}",
2027 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
2028 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
2029 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
2030 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2031 if (vrfTable.isPresent()) {
2032 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
2033 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
2035 List<ListenableFuture<Void>> futures = new ArrayList<>();
2036 synchronized (vpnInstance.getVpnInstanceName().intern()) {
2037 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
2038 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
2039 // Handle Internal Routes only (i.e, STATIC for now)
2040 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.STATIC) {
2041 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
2042 /* Ignore SubnetRoute entry */
2043 if (subnetRoute == null) {
2044 if (!vrfEntry.getNextHopAddressList().isEmpty()) {
2045 if (remoteNextHopIp.trim()
2046 .equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
2047 LOG.trace(" deleting remote FIB entry {}", vrfEntry);
2048 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(),
2049 vrfEntry, writeTransaction);
2055 futures.add(writeTransaction.submit());
2062 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
2063 InstanceIdentifierBuilder<VrfTables> idBuilder =
2064 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
2065 InstanceIdentifier<VrfTables> id = idBuilder.build();
2069 private String getFlowRef(BigInteger dpnId, short tableId, long label, int priority) {
2070 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
2071 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(label).append(NwConstants.FLOWID_SEPARATOR)
2072 .append(priority).toString();
2075 private String getFlowRef(BigInteger dpnId, short tableId, String rd, int priority, InetAddress destPrefix) {
2076 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
2077 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
2078 .append(rd).append(NwConstants.FLOWID_SEPARATOR)
2079 .append(priority).append(NwConstants.FLOWID_SEPARATOR)
2080 .append(destPrefix.getHostAddress()).toString();
2083 private String getInterVpnFibFlowRef(String interVpnLinkName, String prefix, String nextHop) {
2084 return new StringBuilder(64).append(FLOWID_PREFIX)
2085 .append(interVpnLinkName).append(NwConstants.FLOWID_SEPARATOR)
2086 .append(prefix).append(NwConstants.FLOWID_SEPARATOR)
2087 .append(nextHop).toString();
2090 protected List<AdjacencyResult> resolveAdjacency(final BigInteger remoteDpnId, final long vpnId,
2091 final VrfEntry vrfEntry, String rd) {
2092 List<AdjacencyResult> adjacencyList = new ArrayList<>();
2093 List<String> prefixIpList = new ArrayList<>();
2094 LOG.trace("resolveAdjacency called with remotedDpnId {}, vpnId{}, VrfEntry {}",
2095 remoteDpnId, vpnId, vrfEntry);
2097 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
2098 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
2099 if (extraRoute == null) {
2100 prefixIpList = Arrays.asList(vrfEntry.getDestPrefix());
2102 prefixIpList = new ArrayList<>();
2103 for (String extraRouteIp : extraRoute.getNexthopIpList()) {
2104 prefixIpList.add(extraRouteIp + "/32");
2108 prefixIpList = Arrays.asList(vrfEntry.getDestPrefix());
2111 for (String prefixIp : prefixIpList) {
2112 for (String nextHopIp : vrfEntry.getNextHopAddressList()) {
2113 LOG.debug("NextHop IP for destination {} is {}", prefixIp, nextHopIp);
2114 AdjacencyResult adjacencyResult = nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId,
2115 prefixIp, nextHopIp);
2116 if (adjacencyResult != null && !adjacencyList.contains(adjacencyResult)) {
2117 adjacencyList.add(adjacencyResult);
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 new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
2138 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
2139 .append(FLOWID_PREFIX).toString();
2143 * Install flow entry in protocol table to forward mpls
2144 * coming through gre tunnel to LFIB table.
2146 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
2147 final BigInteger cookieProtocolTable = new BigInteger("1070000", 16);
2148 // Instruction to goto L3 InterfaceTable
2149 List<InstructionInfo> instructions = new ArrayList<>();
2150 instructions.add(new InstructionGotoTable(NwConstants.L3_LFIB_TABLE));
2151 List<MatchInfo> matches = new ArrayList<>();
2152 matches.add(MatchEthernetType.MPLS_UNICAST);
2153 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2154 getTableMissFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2155 NwConstants.L3_LFIB_TABLE),
2156 DEFAULT_FIB_FLOW_PRIORITY,
2157 "Protocol Table For LFIB",
2159 cookieProtocolTable,
2160 matches, instructions);
2162 if (addOrRemove == NwConstants.ADD_FLOW) {
2163 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
2164 mdsalManager.installFlow(flowEntityToLfib);
2166 mdsalManager.removeFlow(flowEntityToLfib);
2170 public List<String> printFibEntries() {
2171 List<String> result = new ArrayList<>();
2172 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s", "RD", "Prefix", "NextHop", "Label", "Origin"));
2173 result.add("-------------------------------------------------------------------");
2174 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
2175 Optional<FibEntries> fibEntries = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2176 if (fibEntries.isPresent()) {
2177 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
2178 for (VrfTables vrfTable : vrfTables) {
2179 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
2180 for (String nextHop : vrfEntry.getNextHopAddressList()) {
2181 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s",
2182 vrfTable.getRouteDistinguisher(),
2183 vrfEntry.getDestPrefix(), nextHop, vrfEntry.getLabel(), vrfEntry.getOrigin()));
2185 if (vrfEntry.getNextHopAddressList().isEmpty()) {
2186 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s",
2187 vrfTable.getRouteDistinguisher(),
2188 vrfEntry.getDestPrefix(), "local", vrfEntry.getLabel(), vrfEntry.getOrigin()));
2197 private VrfEntry getVrfEntry(DataBroker broker, String rd, String ipPrefix) {
2198 InstanceIdentifier<VrfEntry> vrfEntryId = InstanceIdentifier.builder(FibEntries.class)
2199 .child(VrfTables.class, new VrfTablesKey(rd))
2200 .child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2201 Optional<VrfEntry> vrfEntry = read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
2202 if (vrfEntry.isPresent()) {
2203 return vrfEntry.get();
2208 private InstanceIdentifier<VrfEntry> getVrfEntryId(String rd, String ipPrefix) {
2209 InstanceIdentifier<VrfEntry> vrfEntryId = InstanceIdentifier.builder(FibEntries.class)
2210 .child(VrfTables.class, new VrfTablesKey(rd))
2211 .child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2215 protected Boolean isIpv4Address(String ipAddress) {
2217 InetAddress address = InetAddress.getByName(ipAddress);
2218 if (address instanceof Inet4Address) {
2221 } catch (UnknownHostException e) {
2222 LOG.warn("Invalid ip address {}", ipAddress, e);
2228 protected Boolean installRouterFibEntries(final VrfEntry vrfEntry, final Collection<VpnToDpnList> vpnToDpnList,
2229 long vpnId, int addOrRemove) {
2230 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
2231 if (routerInt != null && vpnToDpnList != null) {
2232 String routerId = routerInt.getUuid();
2233 String macAddress = routerInt.getMacAddress();
2234 String ipValue = routerInt.getIpAddress();
2235 LOG.trace("createFibEntries - Router augmented vrfentry found for for router uuid:{}, ip:{}, mac:{}",
2236 routerId, ipValue, macAddress);
2237 for (VpnToDpnList vpnDpn : vpnToDpnList) {
2238 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
2239 installRouterFibEntry(vrfEntry, vpnDpn.getDpnId(), vpnId, routerId, ipValue,
2240 new MacAddress(macAddress), addOrRemove);
2248 public void installRouterFibEntry(final VrfEntry vrfEntry, BigInteger dpnId, long vpnId, String routerUuid,
2249 String routerInternalIp, MacAddress routerMac, int addOrRemove) {
2250 String[] subSplit = routerInternalIp.split("/");
2251 if (!isIpv4Address(subSplit[0])) {
2252 // Ping responder using OpenFlow rules is only supported for IPv4, hence skipping.
2256 String addRemoveStr = (addOrRemove == NwConstants.ADD_FLOW) ? "ADD_FLOW" : "DELETE_FLOW";
2257 LOG.trace("{}: bulding Echo Flow entity for dpid:{}, router_ip:{}, vpnId:{}, subSplit:{} ", addRemoveStr,
2258 dpnId, routerInternalIp, vpnId, subSplit[0]);
2260 List<MatchInfo> matches = new ArrayList<>();
2262 matches.add(MatchIpProtocol.ICMP);
2263 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
2264 matches.add(new MatchIcmpv4((short) 8, (short) 0));
2265 matches.add(MatchEthernetType.IPV4);
2266 matches.add(new MatchIpv4Destination(subSplit[0], "32"));
2268 List<ActionInfo> actionsInfos = new ArrayList<>();
2270 // Set Eth Src and Eth Dst
2271 actionsInfos.add(new ActionMoveSourceDestinationEth());
2272 actionsInfos.add(new ActionSetFieldEthernetSource(routerMac));
2274 // Move Ip Src to Ip Dst
2275 actionsInfos.add(new ActionMoveSourceDestinationIp());
2276 actionsInfos.add(new ActionSetSourceIp(subSplit[0], "32"));
2278 // Set the ICMP type to 0 (echo reply)
2279 actionsInfos.add(new ActionSetIcmpType((short) 0));
2281 actionsInfos.add(new ActionNxLoadInPort(BigInteger.ZERO));
2283 actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
2285 List<InstructionInfo> instructions = new ArrayList<>();
2287 instructions.add(new InstructionApplyActions(actionsInfos));
2289 int priority = FibConstants.DEFAULT_FIB_FLOW_PRIORITY + FibConstants.DEFAULT_PREFIX_LENGTH;
2290 String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, vrfEntry.getLabel(), priority);
2292 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef,
2293 0, 0, NwConstants.COOKIE_VM_FIB_TABLE, matches, instructions);
2295 if (addOrRemove == NwConstants.ADD_FLOW) {
2296 mdsalManager.installFlow(flowEntity);
2298 mdsalManager.removeFlow(flowEntity);
2302 public void removeInterVPNLinkRouteFlows(final String interVpnLinkName,
2303 final boolean isVpnFirstEndPoint,
2304 final VrfEntry vrfEntry) {
2305 Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null
2306 && vrfEntry.getNextHopAddressList().size() == 1);
2307 Optional<InterVpnLinkState> interVpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLinkName);
2309 if (!interVpnLinkState.isPresent()) {
2310 LOG.warn("Could not find State for InterVpnLink {}", interVpnLinkName);
2314 List<BigInteger> targetDpns =
2315 isVpnFirstEndPoint ? interVpnLinkState.get().getFirstEndpointState().getDpId()
2316 : interVpnLinkState.get().getSecondEndpointState().getDpId();
2318 String nextHop = vrfEntry.getNextHopAddressList().get(0);
2322 String flowRef = getInterVpnFibFlowRef(interVpnLinkName, vrfEntry.getDestPrefix(), nextHop);
2323 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
2324 Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef)).setTableId(NwConstants.L3_FIB_TABLE)
2325 .setFlowName(flowRef).build();
2327 LOG.trace("Removing flow in FIB table for interVpnLink {} key {}",
2328 interVpnLinkName, flowRef);
2330 for (BigInteger dpId : targetDpns) {
2331 LOG.debug("Removing flow: VrfEntry=[prefix={} label={} nexthop={}] dpn {} for InterVpnLink {} in FIB",
2332 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), nextHop,
2333 dpId, interVpnLinkName);
2335 mdsalManager.removeFlow(dpId, flow);
2340 LOG.trace("Removing flow in FIB table for interVpnLink {}", interVpnLinkName);
2342 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
2343 for (BigInteger dpId : targetDpns) {
2344 LOG.debug("Removing flow: VrfEntry=[prefix={} label={} nexthop={}] dpn {} for InterVpnLink {} in LFIB",
2345 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), nextHop,
2346 dpId, interVpnLinkName);
2347 makeLFibTableEntry(dpId, vrfEntry.getLabel(), null /* no instructions */,
2348 LFIB_INTERVPN_PRIORITY, NwConstants.DEL_FLOW, tx);