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.List;
23 import java.util.concurrent.BlockingQueue;
24 import java.util.concurrent.Callable;
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.Future;
27 import java.util.concurrent.LinkedBlockingQueue;
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
30 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
31 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
32 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
33 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
34 import org.opendaylight.genius.mdsalutil.ActionInfo;
35 import org.opendaylight.genius.mdsalutil.ActionType;
36 import org.opendaylight.genius.mdsalutil.FlowEntity;
37 import org.opendaylight.genius.mdsalutil.InstructionInfo;
38 import org.opendaylight.genius.mdsalutil.InstructionType;
39 import org.opendaylight.genius.mdsalutil.MDSALUtil;
40 import org.opendaylight.genius.mdsalutil.MatchFieldType;
41 import org.opendaylight.genius.mdsalutil.MatchInfo;
42 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
43 import org.opendaylight.genius.mdsalutil.NwConstants;
44 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
45 import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
46 import org.opendaylight.genius.utils.ServiceIndex;
47 import org.opendaylight.genius.utils.batching.ActionableResource;
48 import org.opendaylight.genius.utils.batching.ActionableResourceImpl;
49 import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
50 import org.opendaylight.genius.utils.batching.ResourceHandler;
51 import org.opendaylight.genius.utils.batching.SubTransaction;
52 import org.opendaylight.genius.utils.batching.SubTransactionImpl;
53 import org.opendaylight.netvirt.elanmanager.api.IElanService;
54 import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
55 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
56 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
57 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
58 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
59 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetTunnelTypeInputBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetTunnelTypeOutput;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthopBuilder;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroute;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIds;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIdsKey;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesBuilder;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
108 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;
109 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;
110 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;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.VpnKey;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState.State;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
119 import org.opendaylight.yangtools.yang.binding.DataObject;
120 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
121 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
122 import org.opendaylight.yangtools.yang.common.RpcResult;
123 import org.slf4j.Logger;
124 import org.slf4j.LoggerFactory;
126 public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry, VrfEntryListener> implements AutoCloseable, ResourceHandler {
127 private static final Logger LOG = LoggerFactory.getLogger(VrfEntryListener.class);
128 private static final String FLOWID_PREFIX = "L3.";
129 private final DataBroker dataBroker;
130 private final IMdsalApiManager mdsalManager;
131 private IVpnManager vpnmanager;
132 private final NexthopManager nextHopManager;
133 private ItmRpcService itmManager;
134 private final OdlInterfaceRpcService interfaceManager;
135 private final IdManagerService idManager;
136 private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16);
137 private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
138 private static final int LFIB_INTERVPN_PRIORITY = 1;
139 private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16);
140 private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0);
141 public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
142 List<SubTransaction> transactionObjects;
143 private static final int PERIODICITY = 500;
144 private static Integer batchSize;
145 private static Integer batchInterval;
146 private static final int BATCH_SIZE = 1000;
147 private static BlockingQueue<ActionableResource> vrfEntryBufferQ = new LinkedBlockingQueue<>();
148 private final ResourceBatchingManager resourceBatchingManager;
150 public VrfEntryListener(final DataBroker dataBroker, final IMdsalApiManager mdsalApiManager,
151 final NexthopManager nexthopManager, final OdlInterfaceRpcService interfaceManager,
152 final IdManagerService idManager) {
153 super(VrfEntry.class, VrfEntryListener.class);
154 this.dataBroker = dataBroker;
155 this.mdsalManager = mdsalApiManager;
156 this.nextHopManager = nexthopManager;
157 this.interfaceManager = interfaceManager;
158 this.idManager = idManager;
160 batchSize = Integer.getInteger("batch.size");
161 if (batchSize == null) {
162 batchSize = BATCH_SIZE;
164 batchInterval = Integer.getInteger("batch.wait.time");
165 if (batchInterval == null) {
166 batchInterval = PERIODICITY;
168 resourceBatchingManager = ResourceBatchingManager.getInstance();
169 resourceBatchingManager.registerBatchableResource("FIB-VRFENTRY",vrfEntryBufferQ, this);
170 transactionObjects = new ArrayList<>();
173 public void start() {
174 LOG.info("{} start", getClass().getSimpleName());
175 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
179 protected VrfEntryListener getDataTreeChangeListener() { return VrfEntryListener.this; }
182 protected InstanceIdentifier<VrfEntry> getWildCardPath() {
183 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
187 public DataBroker getResourceBroker() {
192 protected void add(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
193 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
194 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
195 LOG.debug("ADD: Adding Fib Entry rd {} prefix {} nexthop {} label {}",
196 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
197 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
198 createFibEntries(identifier, vrfEntry);
200 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + vrfEntry.getDestPrefix());
201 actResource.setAction(ActionableResource.CREATE);
202 actResource.setInstanceIdentifier(identifier);
203 actResource.setInstance(vrfEntry);
204 vrfEntryBufferQ.add(actResource);
205 leakRouteIfNeeded(identifier, vrfEntry, NwConstants.ADD_FLOW);
207 LOG.info("ADD: Added Fib Entry rd {} prefix {} nexthop {} label {}",
208 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
212 protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
213 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
214 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
215 LOG.debug("REMOVE: Removing Fib Entry rd {} prefix {} nexthop {} label {}",
216 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
217 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
218 deleteFibEntries(identifier, vrfEntry);
220 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + vrfEntry.getDestPrefix());
221 actResource.setAction(ActionableResource.DELETE);
222 actResource.setInstanceIdentifier(identifier);
223 actResource.setInstance(vrfEntry);
224 vrfEntryBufferQ.add(actResource);
225 leakRouteIfNeeded(identifier, vrfEntry, NwConstants.DEL_FLOW);
227 LOG.info("REMOVE: Removed Fib Entry rd {} prefix {} nexthop {} label {}",
228 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
232 protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
233 Preconditions.checkNotNull(update, "VrfEntry should not be null or empty.");
235 final String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
236 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
237 LOG.debug("UPDATE: Updating Fib Entries to rd {} prefix {} nexthop {} label {}",
238 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
239 // Handle BGP Routes first
240 if (RouteOrigin.value(update.getOrigin()) == RouteOrigin.BGP) {
241 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + update.getDestPrefix());
242 actResource.setAction(ActionableResource.UPDATE);
243 actResource.setInstanceIdentifier(identifier);
244 actResource.setInstance(update);
245 actResource.setOldInstance(original);
246 vrfEntryBufferQ.add(actResource);
247 LOG.info("UPDATE: Updated Fib Entries to rd {} prefix {} nexthop {} label {}",
248 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
252 // Handle Internal Routes next (ie., STATIC only)
253 if (FibUtil.isControllerManagedNonInterVpnLinkRoute(RouteOrigin.value(update.getOrigin()))) {
254 SubnetRoute subnetRoute = update.getAugmentation(SubnetRoute.class);
255 /* Ignore SubnetRoute entry, as it will be driven by createFibEntries call down below */
256 if (subnetRoute == null) {
257 List<String> origNhList = original.getNextHopAddressList();
258 List<String> updateNhList = update.getNextHopAddressList();
259 //final SubnetRoute subnetRoute = update.getAugmentation(SubnetRoute.class);
260 LOG.info("UPDATE: Original nexthop {} updateNextHop {} ", origNhList, updateNhList);
262 // If original VRF Entry had nexthop null , but update VRF Entry
263 // has nexthop , route needs to be created on remote Dpns
264 if (((origNhList == null) || (origNhList.isEmpty()) &&
265 (updateNhList != null) && (!updateNhList.isEmpty()))) {
266 // TODO(vivek): Though ugly, Not handling this code now, as each
267 // tep add event will invoke flow addition
268 LOG.trace("Original VRF entry NH is null for destprefix {}. This event is IGNORED here.", update.getDestPrefix());
272 // If original VRF Entry had valid nexthop , but update VRF Entry
273 // has nexthop empty'ed out, route needs to be removed from remote Dpns
274 if (((updateNhList == null) || (updateNhList.isEmpty()) &&
275 (origNhList != null) && (!origNhList.isEmpty()))) {
276 LOG.trace("Original VRF entry had valid NH for destprefix {}. This event is IGNORED here.", update.getDestPrefix());
280 createFibEntries(identifier, update);
281 LOG.info("UPDATE: Updated Fib Entries to rd {} prefix {} nexthop {} label {}",
282 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
286 /* Handl all other route origins */
287 createFibEntries(identifier, update);
289 LOG.info("UPDATE: Updated Fib Entries to rd {} prefix {} nexthop {} label {}",
290 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
294 public void create(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object vrfEntry, List<SubTransaction> transactionObjects) {
295 this.transactionObjects = transactionObjects;
296 if (vrfEntry instanceof VrfEntry) {
297 createFibEntries(tx, identifier, (VrfEntry)vrfEntry);
302 public void delete(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object vrfEntry, List<SubTransaction> transactionObjects) {
303 this.transactionObjects = transactionObjects;
304 if (vrfEntry instanceof VrfEntry) {
305 deleteFibEntries(tx, identifier, (VrfEntry) vrfEntry);
310 public void update(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object original,
311 Object update, List<SubTransaction> transactionObjects) {
312 this.transactionObjects = transactionObjects;
313 if ((original instanceof VrfEntry) && (update instanceof VrfEntry)) {
314 createFibEntries(tx, identifier, (VrfEntry)update);
319 public int getBatchSize() {
324 public int getBatchInterval() {
325 return batchInterval;
329 public LogicalDatastoreType getDatastoreType() {
330 return LogicalDatastoreType.CONFIGURATION;
333 private void createFibEntries(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
334 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
336 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
337 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
338 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
340 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
341 final Long vpnId = vpnInstance.getVpnId();
342 final String rd = vrfTableKey.getRouteDistinguisher();
343 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
344 if (subnetRoute != null) {
345 final long elanTag = subnetRoute.getElantag();
346 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
347 rd, vrfEntry.getDestPrefix(), elanTag);
348 if (vpnToDpnList != null) {
349 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
350 dataStoreCoordinator.enqueueJob("FIB-"+ rd.toString() + "-" + vrfEntry.getDestPrefix(),
351 new Callable<List<ListenableFuture<Void>>>() {
353 public List<ListenableFuture<Void>> call() throws Exception {
354 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
355 for (final VpnToDpnList curDpn : vpnToDpnList) {
356 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
357 installSubnetRouteInFib(curDpn.getDpnId(), elanTag, rd, vpnId.longValue(), vrfEntry, tx);
360 List<ListenableFuture<Void>> futures = new ArrayList<>();
361 futures.add(tx.submit());
368 // ping responder for router interfaces
369 if (installRouterFibEntries(vrfEntry, vpnToDpnList, vpnId, NwConstants.ADD_FLOW)) {
373 final List<BigInteger> localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry);
375 if (vpnToDpnList != null) {
376 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
377 dataStoreCoordinator.enqueueJob("FIB-"+ rd.toString() + "-" + vrfEntry.getDestPrefix(),
378 new Callable<List<ListenableFuture<Void>>>() {
380 public List<ListenableFuture<Void>> call() throws Exception {
381 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
382 for (VpnToDpnList vpnDpn : vpnToDpnList) {
383 if ( !localDpnIdList.contains(vpnDpn.getDpnId())) {
384 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
385 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
389 List<ListenableFuture<Void>> futures = new ArrayList<>();
390 futures.add(tx.submit());
396 Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(dataBroker, rd);
397 if ( optVpnUuid.isPresent() ) {
398 Optional<InterVpnLinkDataComposite> optInterVpnLink = InterVpnLinkCache.getInterVpnLinkByVpnId(optVpnUuid.get());
399 LOG.debug("InterVpnLink {} found in Cache: {}", optVpnUuid.get(), optInterVpnLink.isPresent());
400 if ( optInterVpnLink.isPresent() ) {
401 InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
402 String vpnUuid = optVpnUuid.get();
403 String routeNexthop = vrfEntry.getNextHopAddressList().get(0);
404 if ( interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid) ) {
405 // This is an static route that points to the other endpoint of an InterVpnLink
406 // In that case, we should add another entry in FIB table pointing to LPortDispatcher table.
407 installIVpnLinkSwitchingFlows(interVpnLink, vpnUuid, vrfEntry, vpnId);
408 installInterVpnRouteInLFib(rd, vrfEntry);
416 Please note that the following createFibEntries will be invoked only for BGP Imported Routes.
417 The invocation of the following method is via create() callback from the MDSAL Batching Infrastructure
418 provided by ResourceBatchingManager
420 private void createFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
421 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
423 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
424 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
425 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
427 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
428 final String rd = vrfTableKey.getRouteDistinguisher();
429 if (vpnToDpnList != null) {
430 for (VpnToDpnList vpnDpn : vpnToDpnList) {
431 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
432 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, writeTx);
438 // FIXME: Refactoring needed here.
439 // This kind of logic must be taken to an 'upper' layer like BgpManager or VpnManager
440 private void leakRouteIfNeeded(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry,
442 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
443 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
445 String rd = vrfTableKey.getRouteDistinguisher();
446 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
447 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
448 if (vpnInstance == null) {
449 LOG.error("Vpn Instance not available for external route with prefix {} label {} nexthop {}. Returning...", vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList());
453 Preconditions.checkNotNull(vpnInstance,
454 "Vpn Instance not available with rd " + vrfTableKey.getRouteDistinguisher());
456 String vpnUuid = vpnInstance.getVpnInstanceName();
457 Preconditions.checkArgument(vpnUuid != null && !vpnUuid.isEmpty(),
458 "Could not find suitable VPN UUID for Route-Distinguisher=" + rd);
460 // if the new vrfEntry has been learned by Quagga BGP, its necessary to check if it's
461 // there an interVpnLink for the involved vpn in order to make learn the new route to
462 // the other part of the inter-vpn-link.
464 // For leaking, we need the InterVpnLink to be active. For removal, we just need a InterVpnLink.
465 Optional<InterVpnLink> interVpnLink =
466 (addOrRemove == NwConstants.ADD_FLOW) ? FibUtil.getActiveInterVpnLinkFromRd(dataBroker, rd)
467 : FibUtil.getInterVpnLinkByRd(dataBroker, rd);
468 if ( !interVpnLink.isPresent() ) {
469 LOG.debug("Could not find an InterVpnLink for Route-Distinguisher={}", rd);
473 // Ok, at this point everything is ready for the leaking/removal... but should it be performed?
474 // For removal, we remove all leaked routes, but we only leak a route if the corresponding flag is enabled.
476 (addOrRemove == NwConstants.DEL_FLOW) || ( RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP
477 && interVpnLink.get().isBgpRoutesLeaking() );
480 boolean isVpnFirstEndpoint = interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid);
482 String theOtherVpnId = isVpnFirstEndpoint ? interVpnLink.get().getSecondEndpoint().getVpnUuid().getValue()
484 String dstVpnRd = FibUtil.getVpnRd(dataBroker, theOtherVpnId);
485 String endpointIp = isVpnFirstEndpoint ? interVpnLink.get().getFirstEndpoint().getIpAddress().getValue()
486 : interVpnLink.get().getSecondEndpoint().getIpAddress().getValue();
488 InstanceIdentifier<VrfEntry> vrfEntryIidInOtherVpn =
489 InstanceIdentifier.builder(FibEntries.class)
490 .child(VrfTables.class, new VrfTablesKey(dstVpnRd))
491 .child(VrfEntry.class, new VrfEntryKey(vrfEntry.getDestPrefix()))
493 if ( addOrRemove == NwConstants.ADD_FLOW ) {
494 LOG.debug("Leaking route (destination={}, nexthop={}) from Vrf={} to Vrf={}",
495 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), rd, dstVpnRd);
496 String key = rd + FibConstants.SEPARATOR + vrfEntry.getDestPrefix();
497 long label = FibUtil.getUniqueId(idManager, FibConstants.VPN_IDPOOL_NAME, key);
498 VrfEntry newVrfEntry = new VrfEntryBuilder(vrfEntry).setNextHopAddressList(Arrays.asList(endpointIp))
500 .setOrigin(RouteOrigin.INTERVPN.getValue())
502 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn, newVrfEntry);
504 LOG.debug("Removing leaked vrfEntry={}", vrfEntryIidInOtherVpn.toString());
505 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn);
510 private Prefixes updateVpnReferencesInLri(LabelRouteInfo lri, String vpnInstanceName, boolean isPresentInList) {
511 LOG.debug("updating LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
512 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
513 prefixBuilder.setDpnId(lri.getDpnId());
514 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
515 prefixBuilder.setIpAddress(lri.getPrefix());
516 // Increment the refCount here
517 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
518 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long)lri.getLabel())).build();
519 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri);
520 if (!isPresentInList) {
521 LOG.debug("vpnName {} is not present in LRI with label {}..", vpnInstanceName, lri.getLabel());
522 List<String> vpnInstanceNames = lri.getVpnInstanceList();
523 vpnInstanceNames.add(vpnInstanceName);
524 builder.setVpnInstanceList(vpnInstanceNames);
525 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(), FibUtil.DEFAULT_CALLBACK);
527 LOG.debug("vpnName {} is present in LRI with label {}..", vpnInstanceName, lri.getLabel());
529 return prefixBuilder.build();
532 private void installSubnetRouteInFib(final BigInteger dpnId, final long elanTag, final String rd,
533 final long vpnId, final VrfEntry vrfEntry, WriteTransaction tx){
534 Boolean wrTxPresent = true;
537 tx = dataBroker.newWriteOnlyTransaction();
539 synchronized (vrfEntry.getLabel().toString().intern()) {
540 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
541 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
542 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
544 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
545 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
546 if (vpnInstanceOpDataEntryOptional.isPresent()) {
547 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
548 if (!lri.getVpnInstanceList().contains(vpnInstanceName)) {
549 updateVpnReferencesInLri(lri, vpnInstanceName, false);
553 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
554 vrfEntry.getLabel(), lri.getVpnInterfaceName(), lri.getDpnId());
557 final List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
558 BigInteger subnetRouteMeta = ((BigInteger.valueOf(elanTag)).shiftLeft(32)).or((BigInteger.valueOf(vpnId).shiftLeft(1)));
559 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE }));
560 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
561 makeConnectedRoute(dpnId,vpnId,vrfEntry,rd,instructions,NwConstants.ADD_FLOW, tx);
563 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
564 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
565 // reinitialize instructions list for LFIB Table
566 final List<InstructionInfo> LFIBinstructions = new ArrayList<InstructionInfo>();
568 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
569 LFIBinstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
570 LFIBinstructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE }));
571 LFIBinstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
573 makeLFibTableEntry(dpnId,vrfEntry.getLabel(), LFIBinstructions, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
581 * For a given route, it installs a flow in LFIB that sets the lportTag of the other endpoint and sends to
582 * LportDispatcher table (via table 80)
584 private void installInterVpnRouteInLFib(final String rd, final VrfEntry vrfEntry) {
585 // INTERVPN routes are routes in a Vpn1 that have been leaked to Vpn2. In DC-GW, this Vpn2 route is pointing
586 // to a list of DPNs where Vpn2's VpnLink was instantiated. In these DPNs LFIB must be programmed so that the
587 // packet is commuted from Vpn2 to Vpn1.
588 Optional<String> vpnNameOpc = FibUtil.getVpnNameFromRd(dataBroker, rd);
589 if ( !vpnNameOpc.isPresent() ) {
590 LOG.warn("Could not find VpnInstanceName for Route-Distinguisher {}", rd);
594 String vpnName = vpnNameOpc.get();
595 List<InterVpnLink> interVpnLinks = FibUtil.getAllInterVpnLinks(dataBroker);
596 boolean interVpnLinkFound = false;
597 for ( InterVpnLink interVpnLink : interVpnLinks ) {
598 boolean vpnIs1stEndpoint = interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName);
599 boolean vpnIs2ndEndpoint = !vpnIs1stEndpoint
600 && interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnName);
601 if ( vpnIs1stEndpoint || vpnIs2ndEndpoint ) {
602 interVpnLinkFound = true;
604 Optional<InterVpnLinkState> vpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName());
605 if ( !vpnLinkState.isPresent()
606 || !vpnLinkState.get().getState().equals(InterVpnLinkState.State.Active) ) {
607 LOG.warn("InterVpnLink {}, linking VPN {} and {}, is not in Active state",
608 interVpnLink.getName(), interVpnLink.getFirstEndpoint().getVpnUuid().getValue(),
609 interVpnLink.getSecondEndpoint().getVpnUuid().getValue() );
613 List<BigInteger> targetDpns = vpnIs1stEndpoint ? vpnLinkState.get().getFirstEndpointState().getDpId()
614 : vpnLinkState.get().getSecondEndpointState().getDpId();
615 Long lportTag = vpnIs1stEndpoint ? vpnLinkState.get().getSecondEndpointState().getLportTag()
616 : vpnLinkState.get().getFirstEndpointState().getLportTag();
618 LOG.trace("Installing flow in LFIB table for interVpnLink {}", interVpnLink.getName());
620 for ( BigInteger dpId : targetDpns ) {
621 List<ActionInfo> actionsInfos = Arrays.asList(new ActionInfo(ActionType.pop_mpls, new String[]{}));
623 BigInteger[] metadata = new BigInteger[] {
624 MetaDataUtil.getMetaDataForLPortDispatcher(lportTag.intValue(), ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
625 MetaDataUtil.getMetaDataMaskForLPortDispatcher()
627 List<InstructionInfo> instructions =
628 Arrays.asList(new InstructionInfo(InstructionType.apply_actions, actionsInfos),
629 new InstructionInfo(InstructionType.write_metadata, metadata),
630 new InstructionInfo(InstructionType.goto_table,
631 new long[] { NwConstants.L3_INTERFACE_TABLE }));
633 LOG.debug("Installing flow: VrfEntry=[prefix={} label={} nexthop={}] dpn {} for InterVpnLink {} in LFIB",
634 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(),
635 dpId, interVpnLink.getName());
637 makeLFibTableEntry(dpId, vrfEntry.getLabel(), instructions, LFIB_INTERVPN_PRIORITY,
638 NwConstants.ADD_FLOW, null);
645 if ( !interVpnLinkFound ) {
646 LOG.warn("VrfEntry=[prefix={} label={} nexthop={}] for VPN {} has origin INTERVPN but no InterVpnLink could be found",
647 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), rd);
653 * Installs the flows in FIB table that, for a given route, do the switching from one VPN to the other.
655 private void installIVpnLinkSwitchingFlows(final InterVpnLinkDataComposite interVpnLink, final String vpnUuid,
656 final VrfEntry vrfEntry, long vpnTag) {
657 Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
658 Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null
659 && vrfEntry.getNextHopAddressList().size() == 1);
660 String destination = vrfEntry.getDestPrefix();
661 String nextHop = vrfEntry.getNextHopAddressList().get(0);
662 String iVpnLinkName = interVpnLink.getInterVpnLinkName();
664 // After having received a static route, we should check if the vpn is part of an inter-vpn-link.
665 // In that case, we should populate the FIB table of the VPN pointing to LPortDisptacher table
666 // using as metadata the LPortTag associated to that vpn in the inter-vpn-link.
667 if ( interVpnLink.getState().or(State.Error) != State.Active ) {
668 LOG.warn("Route to {} with nexthop={} cannot be installed because the interVpnLink {} is not active",
669 destination, nextHop, iVpnLinkName);
673 Optional<Long> optOtherEndpointLportTag = interVpnLink.getOtherEndpointLportTagByVpnName(vpnUuid);
674 if ( !optOtherEndpointLportTag.isPresent() ) {
675 LOG.warn("Could not find suitable LportTag for the endpoint opposite to vpn {} in interVpnLink {}",
676 vpnUuid, iVpnLinkName);
680 List<BigInteger> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnUuid);
681 if ( targetDpns.isEmpty() ) {
682 LOG.warn("Could not find DPNs for endpoint opposite to vpn {} in interVpnLink {}", vpnUuid, iVpnLinkName);
686 BigInteger[] metadata = new BigInteger[] {
687 MetaDataUtil.getMetaDataForLPortDispatcher(optOtherEndpointLportTag.get().intValue(),
688 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
689 MetaDataUtil.getMetaDataMaskForLPortDispatcher()
691 List<Instruction> instructions =
692 Arrays.asList(new InstructionInfo(InstructionType.write_metadata, metadata).buildInstruction(0),
693 new InstructionInfo(InstructionType.goto_table,
694 new long[] { NwConstants.L3_INTERFACE_TABLE }).buildInstruction(1));
696 String values[] = destination.split("/");
697 String destPrefixIpAddress = values[0];
698 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
700 List<MatchInfo> matches = new ArrayList<>();
701 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { MetaDataUtil.getVpnIdMetadata(vpnTag),
702 MetaDataUtil.METADATA_MASK_VRFID }));
703 matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_IPV4 }));
705 if (prefixLength != 0) {
706 matches.add(new MatchInfo(MatchFieldType.ipv4_destination,
707 new String[] { destPrefixIpAddress, Integer.toString(prefixLength) }));
710 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
711 String flowRef = getInterVpnFibFlowRef(iVpnLinkName, destination, nextHop);
712 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
713 COOKIE_VM_FIB_TABLE, matches, instructions);
715 LOG.trace("Installing flow in FIB table for vpn {} interVpnLink {} nextHop {} key {}" ,
716 vpnUuid, interVpnLink.getInterVpnLinkName(), nextHop, flowRef);
718 for ( BigInteger dpId : targetDpns ) {
720 LOG.debug("Installing flow: VrfEntry=[prefix={} label={} nextHop={}] dpn {} for InterVpnLink {} in FIB",
721 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(),
722 dpId, interVpnLink.getInterVpnLinkName());
724 mdsalManager.installFlow(dpId, flowEntity);
729 private <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
730 InstanceIdentifier<T> path) {
732 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
734 Optional<T> result = Optional.absent();
736 result = tx.read(datastoreType, path).get();
737 } catch (Exception e) {
738 throw new RuntimeException(e);
744 private List<BigInteger> getDpnIdForPrefix(DataBroker broker, Long vpnId, String rd, VrfEntry vrfEntry) {
745 List<BigInteger> returnLocalDpnId = new ArrayList<BigInteger>();
746 Prefixes localNextHopInfo = FibUtil.getPrefixToInterface(broker, vpnId, vrfEntry.getDestPrefix());
748 if (localNextHopInfo == null) {
749 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
750 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
751 if (extraRoute != null) {
752 for (String nextHopIp : extraRoute.getNexthopIpList()) {
753 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
754 if (nextHopIp != null) {
755 localNextHopInfo = FibUtil.getPrefixToInterface(broker, vpnId, nextHopIp + "/32");
756 if (localNextHopInfo != null) {
757 returnLocalDpnId.add(localNextHopInfo.getDpnId());
763 returnLocalDpnId.add(localNextHopInfo.getDpnId());
766 return returnLocalDpnId;
769 private List<BigInteger> createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
770 List<BigInteger> returnLocalDpnId = new ArrayList<>();
771 Prefixes localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
772 String localNextHopIP = vrfEntry.getDestPrefix();
774 if (localNextHopInfo == null) {
775 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
776 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
777 if (extraRoute != null) {
778 for (String nextHopIp : extraRoute.getNexthopIpList()) {
779 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
780 if (nextHopIp != null) {
781 localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, nextHopIp + "/32");
782 localNextHopIP = nextHopIp + "/32";
783 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, vpnId);
784 returnLocalDpnId.add(dpnId);
788 if (localNextHopInfo == null) {
789 /* imported routes case */
790 synchronized (vrfEntry.getLabel().toString().intern()) {
791 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
792 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
793 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
794 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
795 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
796 if (vpnInstanceOpDataEntryOptional.isPresent()) {
797 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
798 if (lri.getVpnInstanceList().contains(vpnInstanceName)) {
799 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, true);
800 localNextHopIP = lri.getPrefix();
802 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, false);
803 localNextHopIP = lri.getPrefix();
806 if (localNextHopInfo != null) {
807 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
808 vrfEntry.getLabel(), localNextHopInfo.getVpnInterfaceName(), lri.getDpnId());
809 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, lri.getParentVpnid());
810 returnLocalDpnId.add(dpnId);
817 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, vpnId);
818 returnLocalDpnId.add(dpnId);
821 return returnLocalDpnId;
824 private BigInteger checkCreateLocalFibEntry(Prefixes localNextHopInfo, String localNextHopIP, final Long vpnId, final String rd,
825 final VrfEntry vrfEntry, Long parentVpnId){
826 if (localNextHopInfo != null) {
827 final BigInteger dpnId = localNextHopInfo.getDpnId();
828 if (!isVpnPresentInDpn(rd, dpnId)) {
829 LOG.error("The vpnName with vpnId {} rd {} is not available on dpn {}", vpnId, rd, dpnId.toString());
830 return BigInteger.ZERO;
833 final long groupId = nextHopManager.createLocalNextHop(parentVpnId, dpnId,
834 localNextHopInfo.getVpnInterfaceName(), localNextHopIP, vrfEntry.getDestPrefix());
836 LOG.error("Unable to create Group for local prefix {} on rd {} for vpninterface {} on Node {}",
837 vrfEntry.getDestPrefix(), rd, localNextHopInfo.getVpnInterfaceName(), dpnId.toString());
838 return BigInteger.ZERO;
840 List<ActionInfo> actionsInfos =
841 Arrays.asList(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
842 final List<InstructionInfo> instructions =
843 Arrays.asList(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
844 actionsInfos = Arrays.asList(new ActionInfo(ActionType.pop_mpls, new String[]{}),
845 new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }) );
846 final List<InstructionInfo> lfibinstructions = Arrays.asList(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
847 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
848 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
849 dpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
851 LOG.debug("Route with rd {} prefix {} label {} nexthop {} for vpn {} is an imported route. LFib and Terminating table entries will not be created.", rd, vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), vpnId);
853 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
854 dataStoreCoordinator.enqueueJob("FIB-"+ vpnId.toString() + "-" + dpnId.toString() + "-" + vrfEntry.getDestPrefix(),
855 new Callable<List<ListenableFuture<Void>>>() {
857 public List<ListenableFuture<Void>> call() throws Exception {
858 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
859 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
860 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
861 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), lfibinstructions , DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
862 makeTunnelTableEntry(dpnId, vrfEntry.getLabel(), groupId, tx);
864 List<ListenableFuture<Void>> futures = new ArrayList<>();
865 futures.add(tx.submit());
871 return BigInteger.ZERO;
874 private boolean isVpnPresentInDpn(String rd, BigInteger dpnId) {
875 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
876 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
877 if (dpnInVpn.isPresent()) {
883 private LabelRouteInfo getLabelRouteInfo(Long label) {
884 InstanceIdentifier<LabelRouteInfo>lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
885 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long)label)).build();
886 Optional<LabelRouteInfo> opResult = read(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid);
887 if (opResult.isPresent()) {
888 return opResult.get();
893 private boolean deleteLabelRouteInfo(LabelRouteInfo lri, String vpnInstanceName) {
894 LOG.debug("deleting LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
895 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
896 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long) lri.getLabel())).build();
900 List<String> vpnInstancesList = lri.getVpnInstanceList() != null ? lri.getVpnInstanceList() : new ArrayList<String>();
901 if (vpnInstancesList.contains(vpnInstanceName)) {
902 LOG.debug("vpninstance {} name is present", vpnInstanceName);
903 vpnInstancesList.remove(vpnInstanceName);
905 if (vpnInstancesList.size() == 0) {
906 LOG.debug("deleting LRI instance object for label {}", lri.getLabel());
907 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId);
910 LOG.debug("updating LRI instance object for label {}", lri.getLabel());
911 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri).setVpnInstanceList(vpnInstancesList);
912 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(), FibUtil.DEFAULT_CALLBACK);
917 private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/,
918 WriteTransaction tx) {
919 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
920 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
923 createTerminatingServiceActions(dpId, (int)label, actionsInfos, tx);
925 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully",
926 dpId, label, groupId);
929 public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos,
930 WriteTransaction tx) {
931 List<MatchInfo> mkMatches = new ArrayList<>();
933 LOG.debug("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
936 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
937 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
939 List<InstructionInfo> mkInstructions = new ArrayList<>();
940 mkInstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
942 FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
943 getTableMissFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
944 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
946 FlowKey flowKey = new FlowKey( new FlowId(terminatingServiceTableFlowEntity.getFlowId()) );
948 FlowBuilder flowbld = terminatingServiceTableFlowEntity.getFlowBuilder();
950 Node nodeDpn = buildDpnNode(terminatingServiceTableFlowEntity.getDpnId());
951 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
952 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
953 .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId())).child(Flow.class,flowKey).build();
954 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flowbld.build(),true );
957 private void removeTunnelTableEntry(BigInteger dpId, long label, WriteTransaction tx) {
958 FlowEntity flowEntity;
959 LOG.debug("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
960 List<MatchInfo> mkMatches = new ArrayList<>();
962 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
963 flowEntity = MDSALUtil.buildFlowEntity(dpId,
964 NwConstants.INTERNAL_TUNNEL_TABLE,
965 getTableMissFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
966 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
967 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
968 Node nodeDpn = buildDpnNode(flowEntity.getDpnId());
969 FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getFlowId()));
970 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
971 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
972 .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build();
974 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
975 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully", dpId, label);
979 * Delete local FIB entry
985 public List<BigInteger> deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
986 List<BigInteger> returnLocalDpnId = new ArrayList<>();
987 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
988 String localNextHopIP = vrfEntry.getDestPrefix();
990 if (localNextHopInfo == null) {
991 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
992 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
993 if (extra_route != null) {
994 for (String nextHopIp : extra_route.getNexthopIpList()) {
995 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
996 if (nextHopIp != null) {
997 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp + "/32");
998 localNextHopIP = nextHopIp + "/32";
999 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
1000 vpnId, rd, vrfEntry, true /*isExtraRoute*/);
1001 if (!dpnId.equals(BigInteger.ZERO)) {
1002 returnLocalDpnId.add(dpnId);
1008 if (localNextHopInfo == null) {
1009 /* Imported VRF entry */
1010 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1011 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
1012 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1013 VpnNexthopBuilder vpnNexthopBuilder = new VpnNexthopBuilder();
1014 vpnNexthopBuilder.setDpnId(lri.getDpnId());
1015 BigInteger dpnId = checkDeleteLocalFibEntry(vpnNexthopBuilder.build(), localNextHopIP,
1016 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
1017 if (!dpnId.equals(BigInteger.ZERO)) {
1018 returnLocalDpnId.add(dpnId);
1025 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
1026 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
1027 if (!dpnId.equals(BigInteger.ZERO)) {
1028 returnLocalDpnId.add(dpnId);
1032 return returnLocalDpnId;
1035 private BigInteger checkDeleteLocalFibEntry(VpnNexthop localNextHopInfo, final String localNextHopIP,
1036 final Long vpnId, final String rd,
1037 final VrfEntry vrfEntry, final boolean isExtraRoute) {
1038 if (localNextHopInfo != null) {
1039 final BigInteger dpnId = localNextHopInfo.getDpnId();;
1040 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1041 dataStoreCoordinator.enqueueJob("FIB-"+ vpnId.toString() + "-" + dpnId.toString() + "-" + vrfEntry.getDestPrefix(),
1042 new Callable<List<ListenableFuture<Void>>>() {
1044 public List<ListenableFuture<Void>> call() throws Exception {
1045 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1046 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null /* instructions */,
1047 NwConstants.DEL_FLOW, tx);
1048 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1049 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null /* instructions */,
1050 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1051 removeTunnelTableEntry(dpnId, vrfEntry.getLabel(), tx);
1053 List<ListenableFuture<Void>> futures = new ArrayList<>();
1054 futures.add(tx.submit());
1058 //TODO: verify below adjacency call need to be optimized (?)
1059 deleteLocalAdjacency(dpnId, vpnId, localNextHopIP, vrfEntry.getDestPrefix());
1062 return BigInteger.ZERO;
1065 private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
1066 return InstanceIdentifier.builder(VpnToExtraroute.class)
1067 .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class,
1068 new ExtrarouteKey(ipPrefix)).build();
1071 private Extraroute getVpnToExtraroute(String rd, String ipPrefix) {
1072 Optional<Extraroute> extraRouteInfo =
1073 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix));
1074 return extraRouteInfo.isPresent() ? extraRouteInfo.get() : null;
1078 private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
1080 Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
1081 new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
1082 RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
1083 if(!rpcResult.isSuccessful()) {
1084 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
1086 return rpcResult.getResult().getTunnelType();
1089 } catch (InterruptedException | ExecutionException e) {
1090 LOG.warn("Exception when getting tunnel interface Id for tunnel type", e);
1096 private void createRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, final VrfTablesKey vrfTableKey,
1097 final VrfEntry vrfEntry, WriteTransaction tx) {
1098 Boolean wrTxPresent = true;
1100 wrTxPresent = false;
1101 tx = dataBroker.newWriteOnlyTransaction();
1103 String rd = vrfTableKey.getRouteDistinguisher();
1104 LOG.debug( "createremotefibentry: adding route {} for rd {} on remoteDpnId {}",
1105 vrfEntry.getDestPrefix(), rd, remoteDpnId);
1106 /********************************************/
1107 List<AdjacencyResult> adjacencyResults = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
1109 if (adjacencyResults.isEmpty()) {
1110 LOG.error("Could not get interface for nexthop: {} in vpn {}",
1111 vrfEntry.getNextHopAddressList(), rd);
1112 LOG.warn("Failed to add Route: {} in vpn: {}",
1113 vrfEntry.getDestPrefix(), rd);
1117 for (AdjacencyResult adjacencyResult : adjacencyResults) {
1118 List<InstructionInfo> instructions = new ArrayList<>();
1119 List<ActionInfo> actionInfos = new ArrayList<>();
1120 String egressInterface = adjacencyResult.getInterfaceName();
1121 if (Tunnel.class.equals(adjacencyResult.getInterfaceType())) {
1122 addTunnelInterfaceActions(egressInterface, vpnId, vrfEntry, actionInfos);
1124 addRewriteDstMacAction(vpnId, vrfEntry, actionInfos);
1126 List<ActionInfo> egressActions = nextHopManager.getEgressActionsForInterface(egressInterface);
1127 if (egressActions.isEmpty()) {
1129 "Failed to retrieve egress action for prefix {} nextHop {} interface {}. Aborting remote FIB entry creation.",
1130 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), egressInterface);
1133 actionInfos.addAll(egressActions);
1134 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionInfos));
1135 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
1140 LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
1143 private void addRewriteDstMacAction(long vpnId, VrfEntry vrfEntry, List<ActionInfo> actionInfos) {
1144 String ipPrefix = vrfEntry.getDestPrefix();
1145 Prefixes prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, ipPrefix);
1146 if (prefixInfo == null) {
1147 LOG.debug("No prefix info found for prefix {}", ipPrefix);
1151 String ifName = prefixInfo.getVpnInterfaceName();
1152 if (ifName == null) {
1153 LOG.warn("Failed to get VPN interface for prefix {}", ipPrefix);
1157 String macAddress = FibUtil.getMacAddressFromPrefix(dataBroker, ifName, ipPrefix);
1158 if (macAddress == null) {
1159 LOG.warn("No MAC address found for VPN interface {} prefix {}", ifName, ipPrefix);
1163 actionInfos.add(new ActionInfo(ActionType.set_field_eth_dest, new String[] { macAddress }, actionInfos.size()));
1166 private void addTunnelInterfaceActions(String tunnelInterface, long vpnId, VrfEntry vrfEntry,
1167 List<ActionInfo> actionInfos) {
1168 Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
1169 if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
1170 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
1171 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
1172 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label,
1173 new String[] { Long.toString(vrfEntry.getLabel()) }));
1174 actionInfos.add(new ActionInfo(ActionType.nx_load_in_port, new BigInteger[]{BigInteger.ZERO}));
1176 int label = vrfEntry.getLabel().intValue();
1177 BigInteger tunnelId;
1178 // FIXME vxlan vni bit set is not working properly with OVS.need to
1180 if (tunnel_type.equals(TunnelTypeVxlan.class)) {
1181 tunnelId = BigInteger.valueOf(label);
1183 tunnelId = BigInteger.valueOf(label);
1186 LOG.debug("adding set tunnel id action for label {}", label);
1187 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] { tunnelId }));
1188 addRewriteDstMacAction(vpnId, vrfEntry, actionInfos);
1192 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
1193 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
1194 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1195 if (dpnInVpn.isPresent()) {
1196 List<VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
1197 VpnInterfaces currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
1199 if (vpnInterfaces.remove(currVpnInterface)) {
1200 if (vpnInterfaces.isEmpty()) {
1201 LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
1202 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1203 cleanUpDpnForVpn(dpnId, vpnId, rd, null);
1205 LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
1206 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id.child(
1207 VpnInterfaces.class,
1208 new VpnInterfacesKey(intfName)));
1214 private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
1215 /* Get interface info from prefix to interface mapping;
1216 Use the interface info to get the corresponding vpn interface op DS entry,
1217 remove the adjacency corresponding to this fib entry.
1218 If adjacency removed is the last adjacency, clean up the following:
1219 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
1220 - prefix to interface entry
1221 - vpn interface op DS
1223 LOG.debug("Cleanup of prefix {} in VPN {}", vrfEntry.getDestPrefix(), vpnId);
1224 Prefixes prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
1225 Extraroute extraRoute = null;
1226 if (prefixInfo == null) {
1227 extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1228 if(extraRoute != null) {
1229 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1230 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
1232 if (nextHopIp != null) {
1233 prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, nextHopIp + "/32");
1234 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1238 if (prefixInfo == null) {
1239 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1240 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
1241 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1242 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
1243 prefixBuilder.setDpnId(lri.getDpnId());
1244 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
1245 prefixBuilder.setIpAddress(lri.getPrefix());
1246 prefixInfo = prefixBuilder.build();
1247 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
1248 vrfEntry.getLabel(), prefixInfo.getVpnInterfaceName(), lri.getDpnId());
1249 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1253 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1257 private void checkCleanUpOpDataForFib(final Prefixes prefixInfo, final Long vpnId, final String rd,
1258 final VrfEntry vrfEntry, final Extraroute extraRoute) {
1260 if (prefixInfo == null) {
1261 LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for prefix {}", vrfEntry.getDestPrefix());
1262 return; //Don't have any info for this prefix (shouldn't happen); need to return
1265 String ifName = prefixInfo.getVpnInterfaceName();
1266 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1267 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + ifName,
1268 new CleanupVpnInterfaceWorker(prefixInfo, vpnId, rd, vrfEntry, extraRoute));
1271 private class CleanupVpnInterfaceWorker implements Callable<List<ListenableFuture<Void>>> {
1272 Prefixes prefixInfo;
1276 Extraroute extraRoute;
1278 public CleanupVpnInterfaceWorker(final Prefixes prefixInfo, final Long vpnId, final String rd,
1279 final VrfEntry vrfEntry, final Extraroute extraRoute) {
1280 this.prefixInfo = prefixInfo;
1283 this.vrfEntry= vrfEntry;
1284 this.extraRoute = extraRoute;
1288 public List<ListenableFuture<Void>> call() throws Exception {
1289 // If another renderer(for eg : CSS) needs to be supported, check can be performed here
1290 // to call the respective helpers.
1292 //First Cleanup LabelRouteInfo
1293 synchronized (vrfEntry.getLabel().toString().intern()) {
1294 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1295 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
1296 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1297 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
1298 String vpnInstanceName = "";
1299 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1300 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1302 boolean lriRemoved = deleteLabelRouteInfo(lri, vpnInstanceName);
1304 String parentRd = lri.getParentVpnRd();
1305 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1306 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1309 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1310 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1313 String ifName = prefixInfo.getVpnInterfaceName();
1314 Optional<VpnInterface> optvpnInterface = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1315 FibUtil.getVpnInterfaceIdentifier(ifName));
1316 if (optvpnInterface.isPresent()) {
1317 long associatedVpnId = FibUtil.getVpnId(dataBroker, optvpnInterface.get().getVpnInstanceName());
1318 if (vpnId != associatedVpnId) {
1319 LOG.warn("Prefixes {} are associated with different vpn instance with id : {} rather than {}",
1320 vrfEntry.getDestPrefix(), associatedVpnId, vpnId);
1321 LOG.warn("Not proceeding with Cleanup op data for prefix {}", vrfEntry.getDestPrefix());
1324 LOG.debug("Processing cleanup of prefix {} associated with vpn {}",
1325 vrfEntry.getDestPrefix(), associatedVpnId);
1328 if (extraRoute != null) {
1329 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1330 FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
1332 Optional<Adjacencies> optAdjacencies = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1333 FibUtil.getAdjListPath(ifName));
1335 if (optAdjacencies.isPresent()) {
1336 numAdj = optAdjacencies.get().getAdjacency().size();
1338 //remove adjacency corr to prefix
1340 LOG.info("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix());
1341 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1342 FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
1344 if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
1345 //clean up the vpn interface from DpnToVpn list
1346 LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
1347 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1348 FibUtil.getVpnInterfaceIdentifier(ifName));
1354 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1355 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1356 final String rd = vrfTableKey.getRouteDistinguisher();
1357 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1358 if (vpnInstance == null) {
1359 LOG.error("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1362 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1364 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1365 if (subnetRoute != null) {
1366 elanTag = subnetRoute.getElantag();
1367 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
1368 rd, vrfEntry.getDestPrefix(), elanTag);
1369 if (vpnToDpnList != null) {
1370 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1371 dataStoreCoordinator.enqueueJob("FIB-" + rd.toString() + "-" + vrfEntry.getDestPrefix(),
1372 new Callable<List<ListenableFuture<Void>>>() {
1374 public List<ListenableFuture<Void>> call() throws Exception {
1375 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1377 for (final VpnToDpnList curDpn : vpnToDpnList) {
1379 makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry,
1380 vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW, tx);
1381 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1382 makeLFibTableEntry(curDpn.getDpnId(), vrfEntry.getLabel(), null,
1383 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1386 List<ListenableFuture<Void>> futures = new ArrayList<>();
1387 futures.add(tx.submit());
1392 synchronized (vrfEntry.getLabel().toString().intern()) {
1393 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1394 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) && vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1395 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
1396 String vpnInstanceName = "";
1397 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1398 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1400 boolean lriRemoved = this.deleteLabelRouteInfo(lri, vpnInstanceName);
1402 String parentRd = lri.getParentVpnRd();
1403 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1404 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1405 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {} as labelRouteInfo cleared", vrfEntry.getLabel(), rd,
1406 vrfEntry.getDestPrefix());
1409 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1410 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1411 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd,
1412 vrfEntry.getDestPrefix());
1417 if (installRouterFibEntries(vrfEntry, vpnToDpnList, vpnInstance.getVpnId(), NwConstants.DEL_FLOW)) {
1421 final List<BigInteger> localDpnIdList = deleteLocalFibEntry(vpnInstance.getVpnId(),
1422 vrfTableKey.getRouteDistinguisher(), vrfEntry);
1423 if (vpnToDpnList != null) {
1424 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1425 dataStoreCoordinator.enqueueJob("FIB-" + rd.toString() + "-" + vrfEntry.getDestPrefix(),
1426 new Callable<List<ListenableFuture<Void>>>() {
1428 public List<ListenableFuture<Void>> call() throws Exception {
1429 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1431 if (localDpnIdList.size() <= 0) {
1432 for (VpnToDpnList curDpn : vpnToDpnList) {
1433 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1434 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1435 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1438 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1442 for (BigInteger localDpnId : localDpnIdList) {
1443 for (VpnToDpnList curDpn : vpnToDpnList) {
1444 if (!curDpn.getDpnId().equals(localDpnId)) {
1445 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1446 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1447 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1450 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1456 List<ListenableFuture<Void>> futures = new ArrayList<>();
1457 futures.add(tx.submit());
1463 //The flow/group entry has been deleted from config DS; need to clean up associated operational
1464 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
1465 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
1467 // Remove all fib entries configured due to interVpnLink, when nexthop is the opposite endPoint
1468 // of the interVpnLink.
1469 Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(this.dataBroker, rd);
1470 if ( optVpnUuid.isPresent() ) {
1471 String vpnUuid = optVpnUuid.get();
1472 List<String> routeNexthoplist = vrfEntry.getNextHopAddressList();
1473 if(routeNexthoplist.isEmpty()) {
1474 LOG.trace("NextHopList is empty for VrfEntry {}", vrfEntry);
1477 String routeNexthop = routeNexthoplist.get(0);
1478 Optional<InterVpnLinkDataComposite> optInterVpnLink = InterVpnLinkCache.getInterVpnLinkByVpnId(vpnUuid);
1479 if ( optInterVpnLink.isPresent() ) {
1480 InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
1481 if ( interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid))
1483 // This is route that points to the other endpoint of an InterVpnLink
1484 // In that case, we should look for the FIB table pointing to LPortDispatcher table and remove it.
1485 removeInterVPNLinkRouteFlows(interVpnLink.getInterVpnLinkName(),
1486 interVpnLink.isFirstEndpointVpnName(rd),
1495 Please note that the following deleteFibEntries will be invoked only for BGP Imported Routes.
1496 The invocation of the following method is via delete() callback from the MDSAL Batching Infrastructure
1497 provided by ResourceBatchingManager
1499 private void deleteFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1500 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1502 final String rd = vrfTableKey.getRouteDistinguisher();
1503 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1504 if (vpnInstance == null) {
1505 LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1508 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1509 if (vpnToDpnList != null) {
1510 for (VpnToDpnList curDpn : vpnToDpnList) {
1511 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1512 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, writeTx);
1518 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
1519 final long vpnId, final VrfTablesKey vrfTableKey,
1520 final VrfEntry vrfEntry, WriteTransaction tx) {
1522 Boolean wrTxPresent = true;
1524 wrTxPresent = false;
1525 tx = dataBroker.newWriteOnlyTransaction();
1528 LOG.debug("deleting remote route: prefix={}, vpnId={} localDpnId {} remoteDpnId {}", vrfEntry.getDestPrefix(), vpnId, localDpnId, remoteDpnId);
1529 String rd = vrfTableKey.getRouteDistinguisher();
1531 if(localDpnId != null) {
1532 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
1533 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1537 // below two reads are kept as is, until best way is found to identify dpnID
1538 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
1539 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1541 if (localNextHopInfo == null && extraRoute != null) {
1542 // Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
1543 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1544 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp);
1545 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1548 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1555 private boolean checkDpnDeleteFibEntry(VpnNexthop localNextHopInfo, BigInteger remoteDpnId, long vpnId,
1556 VrfEntry vrfEntry, String rd, WriteTransaction tx){
1557 boolean isRemoteRoute = true;
1558 if (localNextHopInfo != null) {
1559 isRemoteRoute = !remoteDpnId.equals(localNextHopInfo.getDpnId());
1561 if (isRemoteRoute) {
1562 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1565 LOG.debug("Did not delete FIB entry: rd={}, vrfEntry={}, as it is local to dpnId={}", rd, vrfEntry.getDestPrefix(), remoteDpnId);
1570 private void deleteFibEntry(BigInteger remoteDpnId, long vpnId, VrfEntry vrfEntry, String rd, WriteTransaction tx){
1571 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1572 LOG.debug("Successfully delete FIB entry: vrfEntry={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
1576 (byte[] rawIpAddress) {
1577 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
1578 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
1581 private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
1582 List<InstructionInfo> instructions, int addOrRemove, WriteTransaction tx) {
1583 Boolean wrTxPresent = true;
1585 wrTxPresent = false;
1586 tx = dataBroker.newWriteOnlyTransaction();
1589 LOG.trace("makeConnectedRoute: vrfEntry {}", vrfEntry);
1590 String values[] = vrfEntry.getDestPrefix().split("/");
1591 String ipAddress = values[0];
1592 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
1593 if (addOrRemove == NwConstants.ADD_FLOW) {
1594 LOG.debug("Adding route to DPN {} for rd {} prefix {} ", dpId, rd, vrfEntry.getDestPrefix());
1596 LOG.debug("Removing route from DPN {} for rd {} prefix {}", dpId, rd, vrfEntry.getDestPrefix());
1598 InetAddress destPrefix;
1600 destPrefix = InetAddress.getByName(ipAddress);
1601 } catch (UnknownHostException e) {
1602 LOG.error("Failed to get destPrefix for prefix {} ", vrfEntry.getDestPrefix(), e);
1606 List<MatchInfo> matches = new ArrayList<>();
1608 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
1609 MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
1611 if (destPrefix instanceof Inet4Address) {
1612 matches.add(new MatchInfo(MatchFieldType.eth_type,
1613 new long[] { NwConstants.ETHTYPE_IPV4 }));
1614 if(prefixLength != 0) {
1615 matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
1616 destPrefix.getHostAddress(), Integer.toString(prefixLength)}));
1619 matches.add(new MatchInfo(MatchFieldType.eth_type,
1620 new long[] { NwConstants.ETHTYPE_IPV6 }));
1621 if(prefixLength != 0) {
1622 matches.add(new MatchInfo(MatchFieldType.ipv6_destination, new String[] {
1623 destPrefix.getHostAddress() + "/" + Integer.toString(prefixLength)}));
1627 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
1628 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, priority, destPrefix);
1629 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
1630 COOKIE_VM_FIB_TABLE, matches, instructions);
1632 Flow flow = flowEntity.getFlowBuilder().build();
1633 String flowId = flowEntity.getFlowId();
1634 FlowKey flowKey = new FlowKey( new FlowId(flowId));
1635 Node nodeDpn = buildDpnNode(dpId);
1637 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1638 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1639 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1641 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1642 SubTransaction subTransaction = new SubTransactionImpl();
1643 if (addOrRemove == NwConstants.ADD_FLOW) {
1644 subTransaction.setInstanceIdentifier(flowInstanceId);
1645 subTransaction.setInstance(flow);
1646 subTransaction.setAction(SubTransaction.CREATE);
1648 subTransaction.setInstanceIdentifier(flowInstanceId);
1649 subTransaction.setAction(SubTransaction.DELETE);
1651 transactionObjects.add(subTransaction);
1654 if (addOrRemove == NwConstants.ADD_FLOW) {
1655 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true);
1657 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1665 //TODO: How to handle the below code, its a copy paste from MDSALManager.java
1666 private Node buildDpnNode(BigInteger dpnId) {
1667 NodeId nodeId = new NodeId("openflow:" + dpnId);
1668 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
1673 private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions, int priority,
1674 int addOrRemove, WriteTransaction tx) {
1675 Boolean wrTxPresent = true;
1677 wrTxPresent = false;
1678 tx = dataBroker.newWriteOnlyTransaction();
1681 List<MatchInfo> matches = new ArrayList<MatchInfo>();
1682 matches.add(new MatchInfo(MatchFieldType.eth_type,
1683 new long[] { NwConstants.ETHTYPE_MPLS_UC }));
1684 matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
1686 // Install the flow entry in L3_LFIB_TABLE
1687 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, priority);
1689 FlowEntity flowEntity;
1690 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef, priority, flowRef, 0, 0,
1691 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
1692 Flow flow = flowEntity.getFlowBuilder().build();
1693 String flowId = flowEntity.getFlowId();
1694 FlowKey flowKey = new FlowKey( new FlowId(flowId));
1695 Node nodeDpn = buildDpnNode(dpId);
1696 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1697 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1698 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1700 if (addOrRemove == NwConstants.ADD_FLOW) {
1701 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true);
1703 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1709 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} : key {} {} successfully",
1710 dpId, label, instructions, flowKey, (NwConstants.ADD_FLOW == addOrRemove) ? "ADDED" : "REMOVED");
1713 private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress,
1714 final String ipPrefixAddress) {
1715 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
1717 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress, ipPrefixAddress);
1718 } catch (NullPointerException e) {
1723 public void populateFibOnNewDpn(final BigInteger dpnId, final long vpnId, final String rd,
1724 final FutureCallback<List<Void>> callback) {
1725 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
1726 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1727 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1728 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1729 if (!vrfTable.isPresent()) {
1730 LOG.warn("VRF Table not yet available for RD {}", rd);
1731 if (callback != null) {
1732 List<ListenableFuture<Void>> futures = new ArrayList<>();
1733 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1734 Futures.addCallback(listenableFuture, callback);
1738 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1739 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1740 new Callable<List<ListenableFuture<Void>>>() {
1742 public List<ListenableFuture<Void>> call() throws Exception {
1743 List<ListenableFuture<Void>> futures = new ArrayList<>();
1744 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1745 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1746 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1747 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1748 if (subnetRoute != null) {
1749 long elanTag = subnetRoute.getElantag();
1750 installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
1753 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
1754 if (routerInt != null) {
1755 LOG.trace( "Router augmented vrfentry found rd:{}, uuid:{}, ip:{}, mac:{}",
1756 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
1757 installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(), routerInt.getIpAddress(),
1758 new MacAddress(routerInt.getMacAddress()), NwConstants.ADD_FLOW);
1761 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) { //Handle local flow creation for imports
1762 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1763 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
1764 && vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1765 if (lri.getDpnId().equals(dpnId)) {
1766 createLocalFibEntry(vpnId, rd, vrfEntry);
1771 // Passing null as we don't know the dpn
1772 // to which prefix is attached at this point
1773 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1775 //TODO: if we have 100K entries in FIB, can it fit in one Tranasaction (?)
1776 futures.add(tx.submit());
1778 if (callback != null) {
1779 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1780 Futures.addCallback(listenableFuture, callback);
1788 public void populateExternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1789 final String localNextHopIp, final String remoteNextHopIp) {
1790 LOG.trace("populateExternalRoutesOnDpn : dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} ",
1791 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1792 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1793 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1794 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1795 if (vrfTable.isPresent()) {
1796 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1797 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1798 new Callable<List<ListenableFuture<Void>>>() {
1800 public List<ListenableFuture<Void>> call() throws Exception {
1801 List<ListenableFuture<Void>> futures = new ArrayList<>();
1802 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1803 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
1804 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1805 if(!vrfEntry.getNextHopAddressList().isEmpty()) {
1806 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1807 if (remoteNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1808 LOG.trace(" creating remote FIB entry for prefix {} rd {}", vrfEntry.getDestPrefix(), rd);
1809 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeCfgTxn);
1814 futures.add(writeCfgTxn.submit());
1822 public void populateInternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1823 final String localNextHopIp, final String remoteNextHopIp) {
1824 LOG.trace("populateInternalRoutesOnDpn : dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} ",
1825 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1826 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1827 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1828 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1829 if (vrfTable.isPresent()) {
1830 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1831 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1832 new Callable<List<ListenableFuture<Void>>>() {
1834 public List<ListenableFuture<Void>> call() throws Exception {
1835 List<ListenableFuture<Void>> futures = new ArrayList<>();
1836 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1837 WriteTransaction writeCfgTxn = dataBroker.newWriteOnlyTransaction();
1838 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1839 // Handle Internal Routes only (i.e., STATIC for now)
1840 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.STATIC) {
1841 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1842 /* Ignore SubnetRoute entry */
1843 if (subnetRoute == null) {
1844 if(!vrfEntry.getNextHopAddressList().isEmpty()) {
1845 if (remoteNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1846 LOG.trace(" creating remote FIB entry for prefix {} rd {} on Dpn {}", vrfEntry.getDestPrefix(), rd, dpnId);
1847 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeCfgTxn);
1853 futures.add(writeCfgTxn.submit());
1861 public void manageRemoteRouteOnDPN(final boolean action,
1862 final BigInteger localDpnId,
1865 final String destPrefix,
1866 final String destTepIp) {
1867 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1869 if (vpnInstance == null) {
1870 LOG.error("VpnInstance for rd {} not present for prefix {}", rd, destPrefix);
1873 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1874 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + localDpnId.toString(),
1875 new Callable<List<ListenableFuture<Void>>>() {
1877 public List<ListenableFuture<Void>> call() throws Exception {
1878 List<ListenableFuture<Void>> futures = new ArrayList<>();
1879 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1880 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1881 VrfTablesKey vrfTablesKey = new VrfTablesKey(rd);
1882 VrfEntry vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1883 if (vrfEntry == null)
1885 LOG.trace("manageRemoteRouteOnDPN :: action {}, DpnId {}, vpnId {}, rd {}, destPfx {}",
1886 action, localDpnId, vpnId, rd, destPrefix);
1887 List<String> nhList = new ArrayList<String>();
1888 List<String> nextHopAddressList = vrfEntry.getNextHopAddressList();
1889 VrfEntry modVrfEntry;
1890 if (nextHopAddressList == null || (nextHopAddressList.isEmpty())) {
1891 nhList = Arrays.asList(destTepIp);
1892 modVrfEntry = new VrfEntryBuilder(vrfEntry).setNextHopAddressList(nhList).build();
1894 modVrfEntry = vrfEntry;
1897 if (action == true) {
1898 LOG.trace("manageRemoteRouteOnDPN updated(add) vrfEntry :: {}", modVrfEntry);
1899 createRemoteFibEntry(localDpnId, vpnId, vrfTablesKey, modVrfEntry, writeTransaction);
1901 LOG.trace("manageRemoteRouteOnDPN updated(remove) vrfEntry :: {}", modVrfEntry);
1902 deleteRemoteRoute(null, localDpnId, vpnId, vrfTablesKey, modVrfEntry, writeTransaction);
1904 futures.add(writeTransaction.submit());
1911 public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd,
1912 final FutureCallback<List<Void>> callback) {
1913 LOG.trace("cleanUpDpnForVpn: Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
1914 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1915 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1916 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1917 if (vrfTable.isPresent()) {
1918 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1919 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1920 new Callable<List<ListenableFuture<Void>>>() {
1922 public List<ListenableFuture<Void>> call() throws Exception {
1923 List<ListenableFuture<Void>> futures = new ArrayList<>();
1924 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1925 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1926 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1927 /* Handle subnet routes here */
1928 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1929 if (subnetRoute != null) {
1930 LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(),
1932 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1933 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1934 LOG.trace("cleanUpDpnForVpn: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd,
1935 vrfEntry.getDestPrefix());
1938 // ping responder for router interfaces
1939 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
1940 if (routerInt != null) {
1941 LOG.trace("Router augmented vrfentry found for rd:{}, uuid:{}, ip:{}, mac:{}",
1942 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
1943 installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(), routerInt.getIpAddress(),
1944 new MacAddress(routerInt.getMacAddress()), NwConstants.DEL_FLOW);
1947 // Passing null as we don't know the dpn
1948 // to which prefix is attached at this point
1949 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1951 futures.add(tx.submit());
1952 if (callback != null) {
1953 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1954 Futures.addCallback(listenableFuture, callback);
1963 public void cleanUpExternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1964 final String localNextHopIp, final String remoteNextHopIp) {
1965 LOG.trace( "cleanUpExternalRoutesOnDpn : cleanup remote routes on dpn {} for vpn {}, rd {}, " +
1966 " localNexthopIp {} , remoteNexhtHopIp {}",
1967 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1968 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1969 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1970 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1971 if (vrfTable.isPresent()) {
1972 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1973 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1974 new Callable<List<ListenableFuture<Void>>>() {
1976 public List<ListenableFuture<Void>> call() throws Exception {
1977 List<ListenableFuture<Void>> futures = new ArrayList<>();
1978 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1979 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1980 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1981 if(!vrfEntry.getNextHopAddressList().isEmpty()) {
1982 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1983 if (remoteNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1984 LOG.trace(" deleting remote FIB entry {}", vrfEntry);
1985 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeTransaction);
1990 futures.add(writeTransaction.submit());
1998 public void cleanUpInternalRoutesOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1999 final String localNextHopIp, final String remoteNextHopIp) {
2000 LOG.trace( "cleanUpInternalRoutesOnDpn : cleanup remote routes on dpn {} for vpn {}, rd {}, " +
2001 " localNexthopIp {} , remoteNexhtHopIp {}",
2002 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
2003 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
2004 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
2005 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2006 if (vrfTable.isPresent()) {
2007 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
2008 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
2009 new Callable<List<ListenableFuture<Void>>>() {
2011 public List<ListenableFuture<Void>> call() throws Exception {
2012 List<ListenableFuture<Void>> futures = new ArrayList<>();
2013 synchronized (vpnInstance.getVpnInstanceName().intern()) {
2014 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
2015 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
2016 // Handle Internal Routes only (i.e, STATIC for now)
2017 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.STATIC) {
2018 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
2019 /* Ignore SubnetRoute entry */
2020 if (subnetRoute == null) {
2021 if (!vrfEntry.getNextHopAddressList().isEmpty()) {
2022 if (remoteNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
2023 LOG.trace(" deleting remote FIB entry {}", vrfEntry);
2024 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeTransaction);
2030 futures.add(writeTransaction.submit());
2038 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
2039 InstanceIdentifierBuilder<VrfTables> idBuilder =
2040 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
2041 InstanceIdentifier<VrfTables> id = idBuilder.build();
2045 private String getFlowRef(BigInteger dpnId, short tableId, long label, int priority) {
2046 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
2047 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(label).append(NwConstants.FLOWID_SEPARATOR)
2048 .append(priority).toString();
2051 private String getFlowRef(BigInteger dpnId, short tableId, String rd, int priority, InetAddress destPrefix) {
2052 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
2053 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
2054 .append(rd).append(NwConstants.FLOWID_SEPARATOR)
2055 .append(priority).append(NwConstants.FLOWID_SEPARATOR)
2056 .append(destPrefix.getHostAddress()).toString();
2059 private String getInterVpnFibFlowRef(String interVpnLinkName, String prefix, String nextHop ) {
2060 return new StringBuilder(64).append(FLOWID_PREFIX)
2061 .append(interVpnLinkName).append(NwConstants.FLOWID_SEPARATOR)
2062 .append(prefix).append(NwConstants.FLOWID_SEPARATOR)
2063 .append(nextHop).toString();
2066 protected List<AdjacencyResult> resolveAdjacency(final BigInteger remoteDpnId, final long vpnId,
2067 final VrfEntry vrfEntry, String rd) {
2068 List<AdjacencyResult> adjacencyList = new ArrayList<>();
2069 List<String> prefixIpList = new ArrayList<>();
2070 LOG.trace("resolveAdjacency called with remotedDpnId {}, vpnId{}, VrfEntry {}",
2071 remoteDpnId, vpnId, vrfEntry);
2073 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
2074 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
2075 if (extra_route == null) {
2076 prefixIpList = Arrays.asList(vrfEntry.getDestPrefix());
2078 prefixIpList = new ArrayList<>();
2079 for (String extraRouteIp : extra_route.getNexthopIpList()) {
2080 prefixIpList.add(extraRouteIp + "/32");
2084 prefixIpList = Arrays.asList(vrfEntry.getDestPrefix());
2087 for (String prefixIp : prefixIpList) {
2088 for (String nextHopIp : vrfEntry.getNextHopAddressList()) {
2089 LOG.debug("NextHop IP for destination {} is {}", prefixIp, nextHopIp);
2090 AdjacencyResult adjacencyResult = nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId,
2091 prefixIp, nextHopIp);
2092 if (adjacencyResult != null && !adjacencyList.contains(adjacencyResult)) {
2093 adjacencyList.add(adjacencyResult);
2097 } catch (NullPointerException e) {
2100 return adjacencyList;
2103 protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
2104 InstanceIdentifier<VpnInstanceOpDataEntry> id =
2105 InstanceIdentifier.create(VpnInstanceOpData.class)
2106 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
2107 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData =
2108 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
2109 return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null;
2112 private String getTableMissFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
2113 return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
2114 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
2115 .append(FLOWID_PREFIX).toString();
2119 * Install flow entry in protocol table to forward mpls
2120 * coming through gre tunnel to LFIB table.
2122 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
2123 final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
2124 // Instruction to goto L3 InterfaceTable
2125 List<InstructionInfo> instructions = new ArrayList<>();
2126 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
2127 List<MatchInfo> matches = new ArrayList<MatchInfo>();
2128 matches.add(new MatchInfo(MatchFieldType.eth_type,
2129 new long[] { NwConstants.ETHTYPE_MPLS_UC }));
2130 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2131 getTableMissFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2132 NwConstants.L3_LFIB_TABLE),
2133 DEFAULT_FIB_FLOW_PRIORITY,
2134 "Protocol Table For LFIB",
2136 COOKIE_PROTOCOL_TABLE,
2137 matches, instructions);
2139 if (addOrRemove == NwConstants.ADD_FLOW) {
2140 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
2141 mdsalManager.installFlow(flowEntityToLfib);
2143 mdsalManager.removeFlow(flowEntityToLfib);
2147 public List<String> printFibEntries() {
2148 List<String> result = new ArrayList<>();
2149 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s", "RD", "Prefix", "NextHop", "Label", "Origin"));
2150 result.add("-------------------------------------------------------------------");
2151 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
2152 Optional<FibEntries> fibEntries = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2153 if (fibEntries.isPresent()) {
2154 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
2155 for (VrfTables vrfTable : vrfTables) {
2156 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
2157 for (String nextHop : vrfEntry.getNextHopAddressList()) {
2158 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s",
2159 vrfTable.getRouteDistinguisher(),
2160 vrfEntry.getDestPrefix(), nextHop, vrfEntry.getLabel(), vrfEntry.getOrigin()));
2162 if (vrfEntry.getNextHopAddressList().isEmpty()) {
2163 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s",
2164 vrfTable.getRouteDistinguisher(),
2165 vrfEntry.getDestPrefix(), "local", vrfEntry.getLabel(), vrfEntry.getOrigin()));
2174 private VrfEntry getVrfEntry(DataBroker broker, String rd, String ipPrefix) {
2175 InstanceIdentifier<VrfEntry> vrfEntryId =
2176 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).
2177 child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2178 Optional<VrfEntry> vrfEntry = read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
2179 if (vrfEntry.isPresent()) {
2180 return vrfEntry.get();
2185 private InstanceIdentifier<VrfEntry> getVrfEntryId(String rd, String ipPrefix) {
2186 InstanceIdentifier<VrfEntry> vrfEntryId =
2187 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).
2188 child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2192 protected Boolean isIpv4Address(String ipAddress) {
2194 InetAddress address = InetAddress.getByName(ipAddress);
2195 if (address instanceof Inet4Address) {
2198 } catch (UnknownHostException e) {
2199 LOG.warn("Invalid ip address {}", ipAddress, e);
2205 protected Boolean installRouterFibEntries(final VrfEntry vrfEntry, final Collection<VpnToDpnList> vpnToDpnList,
2206 long vpnId, int addOrRemove) {
2207 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
2208 if (routerInt != null && vpnToDpnList != null) {
2209 String routerId = routerInt.getUuid();
2210 String macAddress = routerInt.getMacAddress();
2211 String ipValue = routerInt.getIpAddress();
2212 LOG.trace("createFibEntries - Router augmented vrfentry found for for router uuid:{}, ip:{}, mac:{}",
2213 routerId, ipValue, macAddress);
2214 for (VpnToDpnList vpnDpn : vpnToDpnList) {
2215 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
2216 installRouterFibEntry(vrfEntry, vpnDpn.getDpnId(), vpnId, routerId, ipValue,
2217 new MacAddress(macAddress), addOrRemove);
2225 public void installRouterFibEntry(final VrfEntry vrfEntry, BigInteger dpnId, long vpnId, String routerUuid,
2226 String routerInternalIp, MacAddress routerMac, int addOrRemove) {
2227 String[] subSplit = routerInternalIp.split("/");
2228 if (!isIpv4Address(subSplit[0])) {
2229 // Ping responder using OpenFlow rules is only supported for IPv4, hence skipping.
2233 String addRemoveStr = (addOrRemove == NwConstants.ADD_FLOW) ? "ADD_FLOW" : "DELETE_FLOW";
2234 LOG.trace("{}: bulding Echo Flow entity for dpid:{}, router_ip:{}, vpnId:{}, subSplit:{} ", addRemoveStr,
2235 dpnId, routerInternalIp, vpnId, subSplit[0]);
2237 List<MatchInfo> matches = new ArrayList<>();
2239 matches.add(new MatchInfo(MatchFieldType.ip_proto, new long[] { IPProtocols.ICMP.intValue() }));
2240 matches.add(new MatchInfo(MatchFieldType.metadata,
2241 new BigInteger[] { MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
2242 matches.add(new MatchInfo(MatchFieldType.icmp_v4, new long[] { (short) 8, (short) 0 }));
2243 matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_IPV4 }));
2244 matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] { subSplit[0], "32" }));
2246 List<ActionInfo> actionsInfos = new ArrayList<>();
2248 // Set Eth Src and Eth Dst
2249 actionsInfos.add(new ActionInfo(ActionType.move_src_dst_eth, new String[] {}));
2250 actionsInfos.add(new ActionInfo(ActionType.set_field_eth_src, new String[] { routerMac.getValue() }));
2252 // Move Ip Src to Ip Dst
2253 actionsInfos.add(new ActionInfo(ActionType.move_src_dst_ip, new String[] {}));
2254 actionsInfos.add(new ActionInfo(ActionType.set_source_ip, new String[] { subSplit[0], "32" }));
2256 // Set the ICMP type to 0 (echo reply)
2257 actionsInfos.add(new ActionInfo(ActionType.set_icmp_type, new String[] { "0" }));
2259 actionsInfos.add(new ActionInfo(ActionType.nx_load_in_port, new BigInteger[]{ BigInteger.ZERO }));
2261 actionsInfos.add(new ActionInfo(ActionType.nx_resubmit,
2262 new String[] { Short.toString(NwConstants.L3_FIB_TABLE) }));
2264 List<InstructionInfo> instructions = new ArrayList<>();
2266 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
2268 int priority = FibConstants.DEFAULT_FIB_FLOW_PRIORITY + FibConstants.DEFAULT_PREFIX_LENGTH;
2269 String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, vrfEntry.getLabel(), priority);
2271 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef,
2272 0, 0, NwConstants.COOKIE_VM_FIB_TABLE, matches, instructions);
2274 if (addOrRemove == NwConstants.ADD_FLOW) {
2275 mdsalManager.installFlow(flowEntity);
2277 mdsalManager.removeFlow(flowEntity);
2281 public void removeInterVPNLinkRouteFlows(final String interVpnLinkName,
2282 final boolean isVpnFirstEndPoint,
2283 final VrfEntry vrfEntry)
2285 Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null
2286 && vrfEntry.getNextHopAddressList().size() == 1);
2287 Optional<InterVpnLinkState> interVpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLinkName);
2289 if ( !interVpnLinkState.isPresent()) {
2290 LOG.warn("Could not find State for InterVpnLink {}", interVpnLinkName);
2294 List<BigInteger> targetDpns =
2295 isVpnFirstEndPoint ? interVpnLinkState.get().getFirstEndpointState().getDpId()
2296 : interVpnLinkState.get().getSecondEndpointState().getDpId();
2298 String nextHop = vrfEntry.getNextHopAddressList().get(0);
2302 String flowRef = getInterVpnFibFlowRef(interVpnLinkName, vrfEntry.getDestPrefix(), nextHop);
2303 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
2304 Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef)).setTableId(NwConstants.L3_FIB_TABLE)
2305 .setFlowName(flowRef).build();
2307 LOG.trace("Removing flow in FIB table for interVpnLink {} key {}",
2308 interVpnLinkName, flowRef);
2310 for ( BigInteger dpId : targetDpns ) {
2311 LOG.debug("Removing flow: VrfEntry=[prefix={} label={} nexthop={}] dpn {} for InterVpnLink {} in FIB",
2312 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), nextHop,
2313 dpId, interVpnLinkName);
2315 mdsalManager.removeFlow(dpId, flow);
2320 LOG.trace("Removing flow in FIB table for interVpnLink {}", interVpnLinkName);
2322 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
2323 for ( BigInteger dpId : targetDpns ) {
2324 LOG.debug("Removing flow: VrfEntry=[prefix={} label={} nexthop={}] dpn {} for InterVpnLink {} in LFIB",
2325 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), nextHop,
2326 dpId, interVpnLinkName);
2327 makeLFibTableEntry(dpId, vrfEntry.getLabel(), null /* no instructions */,
2328 LFIB_INTERVPN_PRIORITY, NwConstants.DEL_FLOW, tx);