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.CheckedFuture;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.math.BigInteger;
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.DataChangeListener;
30 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
31 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
32 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
33 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
34 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
35 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
36 import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
37 import org.opendaylight.genius.mdsalutil.ActionInfo;
38 import org.opendaylight.genius.mdsalutil.ActionType;
39 import org.opendaylight.genius.mdsalutil.FlowEntity;
40 import org.opendaylight.genius.mdsalutil.InstructionInfo;
41 import org.opendaylight.genius.mdsalutil.InstructionType;
42 import org.opendaylight.genius.mdsalutil.MDSALUtil;
43 import org.opendaylight.genius.mdsalutil.MatchFieldType;
44 import org.opendaylight.genius.mdsalutil.MatchInfo;
45 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
46 import org.opendaylight.genius.mdsalutil.NwConstants;
47 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
48 import org.opendaylight.genius.utils.ServiceIndex;
49 import org.opendaylight.genius.utils.batching.ActionableResource;
50 import org.opendaylight.genius.utils.batching.ActionableResourceImpl;
51 import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
52 import org.opendaylight.genius.utils.batching.ResourceHandler;
53 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
54 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
55 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetTunnelTypeInputBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetTunnelTypeOutput;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthopBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroute;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIds;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIdsKey;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesBuilder;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
101 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;
102 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;
103 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;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.VpnKey;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
111 import org.opendaylight.yangtools.concepts.ListenerRegistration;
112 import org.opendaylight.yangtools.yang.binding.DataObject;
113 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
114 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
115 import org.opendaylight.yangtools.yang.common.RpcResult;
116 import org.slf4j.Logger;
117 import org.slf4j.LoggerFactory;
119 public class VrfEntryListener extends AbstractDataChangeListener<VrfEntry> implements AutoCloseable, ResourceHandler {
120 private static final Logger LOG = LoggerFactory.getLogger(VrfEntryListener.class);
121 private static final String FLOWID_PREFIX = "L3.";
122 private ListenerRegistration<DataChangeListener> listenerRegistration;
123 private final DataBroker dataBroker;
124 private final IMdsalApiManager mdsalManager;
125 private IVpnManager vpnmanager;
126 private NexthopManager nextHopManager;
127 private ItmRpcService itmManager;
128 private OdlInterfaceRpcService interfaceManager;
129 private IdManagerService idManager;
130 private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16);
131 private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
132 private static final int LFIB_INTERVPN_PRIORITY = 1;
133 private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16);
134 private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0);
135 public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
136 private static final int PERIODICITY = 500;
137 private static Integer batchSize;
138 private static Integer batchInterval;
139 private static final int BATCH_SIZE = 1000;
140 private static BlockingQueue<ActionableResource> vrfEntryBufferQ = new LinkedBlockingQueue<>();
141 private ResourceBatchingManager resourceBatchingManager;
143 public VrfEntryListener(final DataBroker dataBroker, final IMdsalApiManager mdsalApiManager,
144 final NexthopManager nexthopManager, final OdlInterfaceRpcService interfaceManager,
145 final IdManagerService idManager) {
146 super(VrfEntry.class);
147 this.dataBroker = dataBroker;
148 this.mdsalManager = mdsalApiManager;
149 this.nextHopManager = nexthopManager;
150 this.interfaceManager = interfaceManager;
151 this.idManager = idManager;
152 batchSize = Integer.getInteger("batch.size");
153 if (batchSize == null) {
154 batchSize = BATCH_SIZE;
156 batchInterval = Integer.getInteger("batch.wait.time");
157 if (batchInterval == null) {
158 batchInterval = PERIODICITY;
160 resourceBatchingManager = ResourceBatchingManager.getInstance();
161 resourceBatchingManager.registerBatchableResource("FIB-VRFENTRY",vrfEntryBufferQ, this);
164 public void start() {
165 LOG.info("{} start", getClass().getSimpleName());
166 listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
167 getWildCardPath(), this, DataChangeScope.SUBTREE);
170 private InstanceIdentifier<VrfEntry> getWildCardPath() {
171 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
175 public void close() throws Exception {
176 if (listenerRegistration != null) {
177 listenerRegistration.close();
178 listenerRegistration = null;
180 LOG.info("{} close", getClass().getSimpleName());
184 public DataBroker getResourceBroker() {
189 protected void add(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
190 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
191 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
192 LOG.debug("ADD: Adding Fib Entry rd {} prefix {} nexthop {} label {}",
193 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
194 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
195 createFibEntries(identifier, vrfEntry);
197 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + vrfEntry.getDestPrefix());
198 actResource.setAction(ActionableResource.CREATE);
199 actResource.setInstanceIdentifier(identifier);
200 actResource.setInstance(vrfEntry);
201 vrfEntryBufferQ.add(actResource);
202 leakRouteIfNeeded(identifier, vrfEntry, NwConstants.ADD_FLOW);
204 LOG.debug("ADD: Added Fib Entry rd {} prefix {} nexthop {} label {}",
205 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
209 protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
210 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
211 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
212 LOG.debug("REMOVE: Removing Fib Entry rd {} prefix {} nexthop {} label {}",
213 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
214 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
215 deleteFibEntries(identifier, vrfEntry);
217 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + vrfEntry.getDestPrefix());
218 actResource.setAction(ActionableResource.DELETE);
219 actResource.setInstanceIdentifier(identifier);
220 actResource.setInstance(vrfEntry);
221 vrfEntryBufferQ.add(actResource);
222 leakRouteIfNeeded(identifier, vrfEntry, NwConstants.DEL_FLOW);
224 LOG.debug("REMOVE: Removed Fib Entry rd {} prefix {} nexthop {} label {}",
225 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
229 protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
230 Preconditions.checkNotNull(update, "VrfEntry should not be null or empty.");
231 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
232 LOG.debug("UPDATE: Updating Fib Entries to rd {} prefix {} nexthop {} label {}",
233 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
234 if (RouteOrigin.value(update.getOrigin()) != RouteOrigin.BGP) {
235 createFibEntries(identifier, update);
237 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + update.getDestPrefix());
238 actResource.setAction(ActionableResource.UPDATE);
239 actResource.setInstanceIdentifier(identifier);
240 actResource.setInstance(update);
241 actResource.setOldInstance(original);
242 vrfEntryBufferQ.add(actResource);
244 LOG.debug("UPDATE: Updated Fib Entries to rd {} prefix {} nexthop {} label {}",
245 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
249 public void create(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object vrfEntry) {
250 if (vrfEntry instanceof VrfEntry) {
251 createFibEntries(tx, identifier, (VrfEntry)vrfEntry);
256 public void delete(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object vrfEntry) {
257 if (vrfEntry instanceof VrfEntry) {
258 deleteFibEntries(tx, identifier, (VrfEntry) vrfEntry);
263 public void update(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object original,
265 if ((original instanceof VrfEntry) && (update instanceof VrfEntry)) {
266 createFibEntries(tx, identifier, (VrfEntry)update);
271 public int getBatchSize() {
276 public int getBatchInterval() {
277 return batchInterval;
281 public LogicalDatastoreType getDatastoreType() {
282 return LogicalDatastoreType.CONFIGURATION;
285 private void createFibEntries(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
286 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
288 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
289 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
290 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
292 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
293 final Long vpnId = vpnInstance.getVpnId();
294 final String rd = vrfTableKey.getRouteDistinguisher();
295 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
296 if (subnetRoute != null) {
297 final long elanTag = subnetRoute.getElantag();
298 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
299 rd, vrfEntry.getDestPrefix(), elanTag);
300 if (vpnToDpnList != null) {
301 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
302 dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(),
303 new Callable<List<ListenableFuture<Void>>>() {
305 public List<ListenableFuture<Void>> call() throws Exception {
306 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
307 for (final VpnToDpnList curDpn : vpnToDpnList) {
308 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
309 installSubnetRouteInFib(curDpn.getDpnId(), elanTag, rd, vpnId.longValue(), vrfEntry, tx);
312 List<ListenableFuture<Void>> futures = new ArrayList<>();
313 futures.add(tx.submit());
321 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.INTERVPN) {
322 // When it is a leaked route, the LFIB and FIB goes a bit different.
323 installInterVpnRouteInLFib(rd, vrfEntry);
327 final List<BigInteger> localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry);
329 if (vpnToDpnList != null) {
330 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
331 dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(),
332 new Callable<List<ListenableFuture<Void>>>() {
334 public List<ListenableFuture<Void>> call() throws Exception {
335 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
336 for (VpnToDpnList vpnDpn : vpnToDpnList) {
337 if ( !localDpnIdList.contains(vpnDpn.getDpnId())) {
338 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
339 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
343 List<ListenableFuture<Void>> futures = new ArrayList<>();
344 futures.add(tx.submit());
350 Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(dataBroker, rd);
351 if ( optVpnUuid.isPresent() ) {
352 Optional<InterVpnLink> interVpnLink = FibUtil.getInterVpnLinkByVpnUuid(dataBroker, optVpnUuid.get());
353 if ( interVpnLink.isPresent() ) {
354 String vpnUuid = optVpnUuid.get();
355 String routeNexthop = vrfEntry.getNextHopAddressList().get(0);
356 if ( isNexthopTheOtherVpnLinkEndpoint(routeNexthop, vpnUuid, interVpnLink.get()) ) {
357 // This is an static route that points to the other endpoint of an InterVpnLink
358 // In that case, we should add another entry in FIB table pointing to LPortDispatcher table.
359 installRouteInInterVpnLink(interVpnLink.get(), vpnUuid, vrfEntry, vpnId);
367 Please note that the following createFibEntries will be invoked only for BGP Imported Routes.
368 The invocation of the following method is via create() callback from the MDSAL Batching Infrastructure
369 provided by ResourceBatchingManager
371 private void createFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
372 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
374 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
375 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
376 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
378 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
379 final String rd = vrfTableKey.getRouteDistinguisher();
380 if (vpnToDpnList != null) {
381 for (VpnToDpnList vpnDpn : vpnToDpnList) {
382 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
383 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, writeTx);
390 * Returns true if the specified nexthop is the other endpoint in an
391 * InterVpnLink, regarding one of the VPN's point of view.
393 private boolean isNexthopTheOtherVpnLinkEndpoint(String nexthop, String thisVpnUuid, InterVpnLink interVpnLink) {
396 && ( (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(thisVpnUuid)
397 && interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(nexthop))
398 || (interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(thisVpnUuid )
399 && interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(nexthop)) );
403 // FIXME: Refactoring needed here.
404 // This kind of logic must be taken to an 'upper' layer like BgpManager or VpnManager
405 private void leakRouteIfNeeded(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry,
407 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
408 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
410 String rd = vrfTableKey.getRouteDistinguisher();
411 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
412 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
413 if (vpnInstance == null) {
414 LOG.error("Vpn Instance not available for external route with prefix {} label {} nexthop {}. Returning...", vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList());
418 Preconditions.checkNotNull(vpnInstance,
419 "Vpn Instance not available with rd " + vrfTableKey.getRouteDistinguisher());
421 String vpnUuid = vpnInstance.getVpnInstanceName();
422 Preconditions.checkArgument(vpnUuid != null && !vpnUuid.isEmpty(),
423 "Could not find suitable VPN UUID for Route-Distinguisher=" + rd);
425 // if the new vrfEntry has been learned by Quagga BGP, its necessary to check if it's
426 // there an interVpnLink for the involved vpn in order to make learn the new route to
427 // the other part of the inter-vpn-link.
429 // For leaking, we need the InterVpnLink to be active. For removal, we just need a InterVpnLink.
430 Optional<InterVpnLink> interVpnLink =
431 (addOrRemove == NwConstants.ADD_FLOW) ? FibUtil.getActiveInterVpnLinkFromRd(dataBroker, rd)
432 : FibUtil.getInterVpnLinkByRd(dataBroker, rd);
433 if ( !interVpnLink.isPresent() ) {
434 LOG.debug("Could not find an InterVpnLink for Route-Distinguisher={}", rd);
438 // Ok, at this point everything is ready for the leaking/removal... but should it be performed?
439 // For removal, we remove all leaked routes, but we only leak a route if the corresponding flag is enabled.
440 boolean proceed = (addOrRemove == NwConstants.DEL_FLOW )
441 || ( RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP
442 && interVpnLink.get().isBgpRoutesLeaking() );
445 String theOtherVpnId = ( interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid) )
446 ? interVpnLink.get().getSecondEndpoint().getVpnUuid().getValue()
449 String dstVpnRd = FibUtil.getVpnRd(dataBroker, theOtherVpnId);
450 String endpointIp = vrfEntry.getNextHopAddressList().get(0);
452 InstanceIdentifier<VrfEntry> vrfEntryIidInOtherVpn =
453 InstanceIdentifier.builder(FibEntries.class)
454 .child(VrfTables.class, new VrfTablesKey(dstVpnRd))
455 .child(VrfEntry.class, new VrfEntryKey(vrfEntry.getDestPrefix()))
457 if ( addOrRemove == NwConstants.ADD_FLOW ) {
458 LOG.debug("Leaking route (destination={}, nexthop={}) from Vrf={} to Vrf={}",
459 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), rd, dstVpnRd);
460 String key = rd + FibConstants.SEPARATOR + vrfEntry.getDestPrefix();
461 long label = FibUtil.getUniqueId(idManager, FibConstants.VPN_IDPOOL_NAME, key);
462 VrfEntry newVrfEntry = new VrfEntryBuilder(vrfEntry).setNextHopAddressList(Arrays.asList(endpointIp))
464 .setOrigin(RouteOrigin.INTERVPN.getValue())
466 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn, newVrfEntry);
468 LOG.debug("Removing leaked vrfEntry={}", vrfEntryIidInOtherVpn.toString());
469 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn);
474 private Prefixes updateVpnReferencesInLri(LabelRouteInfo lri, String vpnInstanceName, boolean isPresentInList) {
475 LOG.debug("updating LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
476 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
477 prefixBuilder.setDpnId(lri.getDpnId());
478 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
479 prefixBuilder.setIpAddress(lri.getPrefix());
480 // Increment the refCount here
481 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
482 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long)lri.getLabel())).build();
483 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri);
484 if (!isPresentInList) {
485 LOG.debug("vpnName {} is not present in LRI with label {}..", vpnInstanceName, lri.getLabel());
486 List<String> vpnInstanceNames = lri.getVpnInstanceList();
487 vpnInstanceNames.add(vpnInstanceName);
488 builder.setVpnInstanceList(vpnInstanceNames);
489 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(), FibUtil.DEFAULT_CALLBACK);
491 LOG.debug("vpnName {} is present in LRI with label {}..", vpnInstanceName, lri.getLabel());
493 return prefixBuilder.build();
496 private void installSubnetRouteInFib(final BigInteger dpnId, final long elanTag, final String rd,
497 final long vpnId, final VrfEntry vrfEntry, WriteTransaction tx){
498 Boolean wrTxPresent = true;
501 tx = dataBroker.newWriteOnlyTransaction();
503 synchronized (vrfEntry.getLabel().toString().intern()) {
504 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
505 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
506 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
508 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
509 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
510 if (vpnInstanceOpDataEntryOptional.isPresent()) {
511 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
512 if (!lri.getVpnInstanceList().contains(vpnInstanceName)) {
513 updateVpnReferencesInLri(lri, vpnInstanceName, false);
517 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
518 vrfEntry.getLabel(), lri.getVpnInterfaceName(), lri.getDpnId());
521 final List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
522 BigInteger subnetRouteMeta = ((BigInteger.valueOf(elanTag)).shiftLeft(32)).or((BigInteger.valueOf(vpnId).shiftLeft(1)));
523 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE }));
524 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
525 makeConnectedRoute(dpnId,vpnId,vrfEntry,rd,instructions,NwConstants.ADD_FLOW, tx);
527 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
528 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
529 // reinitialize instructions list for LFIB Table
530 final List<InstructionInfo> LFIBinstructions = new ArrayList<InstructionInfo>();
532 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
533 LFIBinstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
534 LFIBinstructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE }));
535 LFIBinstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
537 makeLFibTableEntry(dpnId,vrfEntry.getLabel(), LFIBinstructions, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
544 private void installInterVpnRouteInLFib(final String rd, final VrfEntry vrfEntry) {
545 // INTERVPN routes are routes in a Vpn1 that have been leaked to Vpn2. In DC-GW, this Vpn2 route is pointing
546 // to a list of DPNs where Vpn2's VpnLink was instantiated. In these DPNs LFIB must be programmed so that the
547 // packet is commuted from Vpn2 to Vpn1.
548 Optional<String> vpnNameOpc = FibUtil.getVpnNameFromRd(dataBroker, rd);
549 if ( !vpnNameOpc.isPresent() ) {
550 LOG.warn("Could not find VpnInstanceName for Route-Distinguisher {}", rd);
554 String vpnName = vpnNameOpc.get();
555 List<InterVpnLink> interVpnLinks = FibUtil.getAllInterVpnLinks(dataBroker);
556 boolean interVpnLinkFound = false;
557 for ( InterVpnLink interVpnLink : interVpnLinks ) {
558 boolean vpnIs1stEndpoint = interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName);
559 boolean vpnIs2ndEndpoint = !vpnIs1stEndpoint
560 && interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnName);
561 if ( vpnIs1stEndpoint || vpnIs2ndEndpoint ) {
562 interVpnLinkFound = true;
564 Optional<InterVpnLinkState> vpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName());
565 if ( !vpnLinkState.isPresent()
566 || !vpnLinkState.get().getState().equals(InterVpnLinkState.State.Active) ) {
567 LOG.warn("InterVpnLink {}, linking VPN {} and {}, is not in Active state",
568 interVpnLink.getName(), interVpnLink.getFirstEndpoint().getVpnUuid().getValue(),
569 interVpnLink.getSecondEndpoint().getVpnUuid().getValue() );
573 List<BigInteger> targetDpns =
574 ( vpnIs1stEndpoint ) ? vpnLinkState.get().getFirstEndpointState().getDpId()
575 : vpnLinkState.get().getSecondEndpointState().getDpId();
577 ( vpnIs1stEndpoint ) ? vpnLinkState.get().getSecondEndpointState().getLportTag()
578 : vpnLinkState.get().getFirstEndpointState().getLportTag();
580 for ( BigInteger dpId : targetDpns ) {
581 List<ActionInfo> actionsInfos = Arrays.asList(new ActionInfo(ActionType.pop_mpls, new String[]{}));
583 BigInteger[] metadata = new BigInteger[] {
584 MetaDataUtil.getMetaDataForLPortDispatcher(lportTag.intValue(), ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
585 MetaDataUtil.getMetaDataMaskForLPortDispatcher()
587 List<InstructionInfo> instructions =
588 Arrays.asList(new InstructionInfo(InstructionType.apply_actions, actionsInfos),
589 new InstructionInfo(InstructionType.write_metadata, metadata),
590 new InstructionInfo(InstructionType.goto_table,
591 new long[] { NwConstants.L3_INTERFACE_TABLE }));
593 makeLFibTableEntry(dpId, vrfEntry.getLabel(), instructions, LFIB_INTERVPN_PRIORITY,
594 NwConstants.ADD_FLOW, null);
601 if ( !interVpnLinkFound ) {
602 LOG.warn("VrfEntry=[prefix={} label={} nexthop={}] for VPN {} has origin INTERVPN but no InterVpnLink could be found",
603 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), rd);
609 private void installRouteInInterVpnLink(final InterVpnLink interVpnLink, final String vpnUuid,
610 final VrfEntry vrfEntry, long vpnTag) {
611 Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
612 Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null
613 && vrfEntry.getNextHopAddressList().size() == 1);
614 String destination = vrfEntry.getDestPrefix();
615 String nextHop = vrfEntry.getNextHopAddressList().get(0);
617 // After having received a static route, we should check if the vpn is part of an inter-vpn-link.
618 // In that case, we should populate the FIB table of the VPN pointing to LPortDisptacher table
619 // using as metadata the LPortTag associated to that vpn in the inter-vpn-link.
620 Optional<InterVpnLinkState> interVpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName());
621 if ( !interVpnLinkState.isPresent() ) {
622 LOG.warn("Could not find State for InterVpnLink {}", interVpnLink.getName());
625 if ( ! interVpnLinkState.get().getState().equals(InterVpnLinkState.State.Active) ) {
626 LOG.warn("Route to {} with nexthop={} cannot be installed because the interVpnLink {} is not active",
627 destination, nextHop, interVpnLink.getName());
633 boolean vpnIsFirstEndpoint = isVpnFirstEndPoint(interVpnLink, vpnUuid);
634 List<BigInteger> targetDpns =
635 vpnIsFirstEndpoint ? interVpnLinkState.get().getFirstEndpointState().getDpId()
636 : interVpnLinkState.get().getSecondEndpointState().getDpId();
638 Long otherEndpointlportTag =
639 vpnIsFirstEndpoint ? interVpnLinkState.get().getSecondEndpointState().getLportTag()
640 : interVpnLinkState.get().getFirstEndpointState().getLportTag();
642 BigInteger[] metadata = new BigInteger[] {
643 MetaDataUtil.getMetaDataForLPortDispatcher(otherEndpointlportTag.intValue(),
644 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
645 MetaDataUtil.getMetaDataMaskForLPortDispatcher()
648 List<Instruction> instructions =
649 Arrays.asList(new InstructionInfo(InstructionType.write_metadata, metadata).buildInstruction(0),
650 new InstructionInfo(InstructionType.goto_table,
651 new long[] { NwConstants.L3_INTERFACE_TABLE }).buildInstruction(1));
653 String values[] = destination.split("/");
654 String destPrefixIpAddress = values[0];
655 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
657 List<MatchInfo> matches = new ArrayList<>();
658 matches.add(new MatchInfo(MatchFieldType.metadata,
659 new BigInteger[] { MetaDataUtil.getVpnIdMetadata(vpnTag),
660 MetaDataUtil.METADATA_MASK_VRFID }));
661 matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_IPV4 }));
663 if (prefixLength != 0) {
664 matches.add(new MatchInfo(MatchFieldType.ipv4_destination,
665 new String[] { destPrefixIpAddress, Integer.toString(prefixLength) }));
668 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
669 String flowRef = getInterVpnFibFlowRef(interVpnLink.getName(), destination, nextHop);
670 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
671 COOKIE_VM_FIB_TABLE, matches, instructions);
673 for ( BigInteger dpId : targetDpns ) {
674 mdsalManager.installFlow(dpId, flowEntity);
678 private void removeRouteFromInterVpnLink(final InterVpnLink interVpnLink, final String vpnUuid,
679 final VrfEntry vrfEntry) {
681 Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
682 Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null
683 && vrfEntry.getNextHopAddressList().size() == 1);
685 Optional<InterVpnLinkState> interVpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName());
686 if ( !interVpnLinkState.isPresent() ) {
687 LOG.warn("Could not find State for InterVpnLink {}", interVpnLink.getName());
692 boolean vpnIsFirstEndpoint = isVpnFirstEndPoint(interVpnLink, vpnUuid);
693 List<BigInteger> targetDpns =
694 vpnIsFirstEndpoint ? interVpnLinkState.get().getFirstEndpointState().getDpId()
695 : interVpnLinkState.get().getSecondEndpointState().getDpId();
697 String nextHop = vrfEntry.getNextHopAddressList().get(0);
698 String flowRef = getInterVpnFibFlowRef(interVpnLink.getName(), vrfEntry.getDestPrefix(), nextHop);
699 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
700 Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef)).setTableId(NwConstants.L3_FIB_TABLE)
701 .setFlowName(flowRef).build();
703 for ( BigInteger dpId : targetDpns ) {
704 mdsalManager.removeFlow(dpId, flow);
709 private boolean isVpnFirstEndPoint(InterVpnLink interVpnLink, String vpnName) {
710 return interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName);
713 private <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
714 InstanceIdentifier<T> path) {
716 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
718 Optional<T> result = Optional.absent();
720 result = tx.read(datastoreType, path).get();
721 } catch (Exception e) {
722 throw new RuntimeException(e);
728 private void makeSubnetRouteTableMissFlow(BigInteger dpnId, int addOrRemove) {
729 final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
730 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
731 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
732 actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{}));
733 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
734 List<MatchInfo> matches = new ArrayList<MatchInfo>();
735 String flowRef = getTableMissFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, NwConstants.TABLE_MISS_FLOW);
736 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef,
737 NwConstants.TABLE_MISS_PRIORITY, "Subnet Route Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
739 if (addOrRemove == NwConstants.ADD_FLOW) {
740 mdsalManager.installFlow(flowEntity);
742 mdsalManager.removeFlow(flowEntity);
746 private List<BigInteger> createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
747 List<BigInteger> returnLocalDpnId = new ArrayList<BigInteger>();
748 Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
749 String localNextHopIP = vrfEntry.getDestPrefix();
751 if (localNextHopInfo == null) {
752 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
753 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
754 if (extraRoute != null) {
755 for (String nextHopIp : extraRoute.getNexthopIpList()) {
756 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
757 if (nextHopIp != null) {
758 localNextHopInfo = getPrefixToInterface(vpnId, nextHopIp + "/32");
759 localNextHopIP = nextHopIp + "/32";
760 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, vpnId);
761 returnLocalDpnId.add(dpnId);
765 if (localNextHopInfo == null) {
766 /* imported routes case */
767 synchronized (vrfEntry.getLabel().toString().intern()) {
768 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
769 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
770 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
771 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
772 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
773 if (vpnInstanceOpDataEntryOptional.isPresent()) {
774 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
775 if (lri.getVpnInstanceList().contains(vpnInstanceName)) {
776 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, true);
777 localNextHopIP = lri.getPrefix();
779 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, false);
780 localNextHopIP = lri.getPrefix();
783 if (localNextHopInfo != null) {
784 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
785 vrfEntry.getLabel(), localNextHopInfo.getVpnInterfaceName(), lri.getDpnId());
786 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, lri.getParentVpnid());
787 returnLocalDpnId.add(dpnId);
794 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, vpnId);
795 returnLocalDpnId.add(dpnId);
798 return returnLocalDpnId;
801 private BigInteger checkCreateLocalFibEntry(Prefixes localNextHopInfo, String localNextHopIP, final Long vpnId, final String rd,
802 final VrfEntry vrfEntry, Long parentVpnId){
803 if (localNextHopInfo != null) {
804 final BigInteger dpnId = localNextHopInfo.getDpnId();
805 if (!isVpnPresentInDpn(rd, dpnId)) {
806 return BigInteger.ZERO;
809 final long groupId = nextHopManager.createLocalNextHop(parentVpnId, dpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
811 List<ActionInfo> actionsInfos =
812 Arrays.asList(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
813 final List<InstructionInfo> instructions =
814 Arrays.asList(new InstructionInfo(InstructionType.write_actions, actionsInfos));
815 actionsInfos = Arrays.asList(new ActionInfo(ActionType.pop_mpls, new String[]{}),
816 new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }) );
817 final List<InstructionInfo> lfibinstructions = Arrays.asList(new InstructionInfo(InstructionType.write_actions, actionsInfos));
818 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
819 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
820 dpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
822 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);
824 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
825 dataStoreCoordinator.enqueueJob("FIB"+vpnId.toString()+dpnId.toString()+vrfEntry.getDestPrefix(),
826 new Callable<List<ListenableFuture<Void>>>() {
828 public List<ListenableFuture<Void>> call() throws Exception {
829 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
830 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
831 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
832 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), lfibinstructions , DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
833 makeTunnelTableEntry(dpnId, vrfEntry.getLabel(), groupId, tx);
835 List<ListenableFuture<Void>> futures = new ArrayList<>();
836 futures.add(tx.submit());
842 return BigInteger.ZERO;
845 private boolean isVpnPresentInDpn(String rd, BigInteger dpnId) {
846 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
847 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
848 if (dpnInVpn.isPresent()) {
854 private LabelRouteInfo getLabelRouteInfo(Long label) {
855 InstanceIdentifier<LabelRouteInfo>lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
856 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long)label)).build();
857 Optional<LabelRouteInfo> opResult = read(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid);
858 if (opResult.isPresent()) {
859 return opResult.get();
864 private boolean deleteLabelRouteInfo(LabelRouteInfo lri, String vpnInstanceName) {
865 LOG.debug("deleting LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
866 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
867 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long) lri.getLabel())).build();
871 List<String> vpnInstancesList = lri.getVpnInstanceList();
872 if (vpnInstancesList.contains(vpnInstanceName)) {
873 LOG.debug("vpninstance {} name is present", vpnInstanceName);
874 vpnInstancesList.remove(vpnInstanceName);
876 if (vpnInstancesList.size() == 0) {
877 LOG.debug("deleting LRI instance object for label {}", lri.getLabel());
878 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId);
881 LOG.debug("updating LRI instance object for label {}", lri.getLabel());
882 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri).setVpnInstanceList(vpnInstancesList);
883 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(), FibUtil.DEFAULT_CALLBACK);
888 private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/,
889 WriteTransaction tx) {
890 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
891 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
894 createTerminatingServiceActions(dpId, (int)label, actionsInfos, tx);
896 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully",
897 dpId, label, groupId);
900 public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos,
901 WriteTransaction tx) {
902 List<MatchInfo> mkMatches = new ArrayList<>();
904 LOG.debug("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
907 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
908 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
910 List<InstructionInfo> mkInstructions = new ArrayList<>();
911 mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
913 FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
914 getTableMissFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
915 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
917 FlowKey flowKey = new FlowKey( new FlowId(terminatingServiceTableFlowEntity.getFlowId()) );
919 FlowBuilder flowbld = terminatingServiceTableFlowEntity.getFlowBuilder();
921 Node nodeDpn = buildDpnNode(terminatingServiceTableFlowEntity.getDpnId());
922 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
923 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
924 .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId())).child(Flow.class,flowKey).build();
925 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flowbld.build(),true );
928 private void removeTunnelTableEntry(BigInteger dpId, long label, WriteTransaction tx) {
929 FlowEntity flowEntity;
930 LOG.debug("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
931 List<MatchInfo> mkMatches = new ArrayList<>();
933 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
934 flowEntity = MDSALUtil.buildFlowEntity(dpId,
935 NwConstants.INTERNAL_TUNNEL_TABLE,
936 getTableMissFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
937 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
938 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
939 Node nodeDpn = buildDpnNode(flowEntity.getDpnId());
940 FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getFlowId()));
941 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
942 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
943 .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build();
945 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
946 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully", dpId, label);
950 * Delete local FIB entry
956 public List<BigInteger> deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
957 List<BigInteger> returnLocalDpnId = new ArrayList<>();
958 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
959 String localNextHopIP = vrfEntry.getDestPrefix();
961 if (localNextHopInfo == null) {
962 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
963 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
964 if (extra_route != null) {
965 for (String nextHopIp : extra_route.getNexthopIpList()) {
966 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
967 if (nextHopIp != null) {
968 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp + "/32");
969 localNextHopIP = nextHopIp + "/32";
970 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
971 vpnId, rd, vrfEntry, true /*isExtraRoute*/);
972 if (!dpnId.equals(BigInteger.ZERO)) {
973 returnLocalDpnId.add(dpnId);
979 if (localNextHopInfo == null) {
980 /* Imported VRF entry */
981 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
982 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
983 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
984 VpnNexthopBuilder vpnNexthopBuilder = new VpnNexthopBuilder();
985 vpnNexthopBuilder.setDpnId(lri.getDpnId());
986 BigInteger dpnId = checkDeleteLocalFibEntry(vpnNexthopBuilder.build(), localNextHopIP,
987 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
988 if (!dpnId.equals(BigInteger.ZERO)) {
989 returnLocalDpnId.add(dpnId);
996 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
997 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
998 if (!dpnId.equals(BigInteger.ZERO)) {
999 returnLocalDpnId.add(dpnId);
1003 return returnLocalDpnId;
1006 private BigInteger checkDeleteLocalFibEntry(VpnNexthop localNextHopInfo, final String localNextHopIP,
1007 final Long vpnId, final String rd,
1008 final VrfEntry vrfEntry, final boolean isExtraRoute) {
1009 if (localNextHopInfo != null) {
1010 final BigInteger dpnId = localNextHopInfo.getDpnId();;
1011 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1012 dataStoreCoordinator.enqueueJob("FIB"+vpnId.toString()+dpnId.toString()+vrfEntry.getDestPrefix(),
1013 new Callable<List<ListenableFuture<Void>>>() {
1015 public List<ListenableFuture<Void>> call() throws Exception {
1016 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1017 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null /* instructions */,
1018 NwConstants.DEL_FLOW, tx);
1019 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1020 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null /* instructions */,
1021 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1022 removeTunnelTableEntry(dpnId, vrfEntry.getLabel(), tx);
1024 List<ListenableFuture<Void>> futures = new ArrayList<>();
1025 futures.add(tx.submit());
1029 //TODO: verify below adjacency call need to be optimized (?)
1030 deleteLocalAdjacency(dpnId, vpnId, localNextHopIP);
1033 return BigInteger.ZERO;
1037 private InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) {
1038 return InstanceIdentifier.builder(PrefixToInterface.class)
1039 .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
1042 private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
1043 Optional<Prefixes> localNextHopInfoData =
1044 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
1045 return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
1048 private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
1049 return InstanceIdentifier.builder(VpnToExtraroute.class)
1050 .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class,
1051 new ExtrarouteKey(ipPrefix)).build();
1054 private Extraroute getVpnToExtraroute(String rd, String ipPrefix) {
1055 Optional<Extraroute> extraRouteInfo =
1056 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix));
1057 return extraRouteInfo.isPresent() ? extraRouteInfo.get() : null;
1061 private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
1063 Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
1064 new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
1065 RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
1066 if(!rpcResult.isSuccessful()) {
1067 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
1069 return rpcResult.getResult().getTunnelType();
1072 } catch (InterruptedException | ExecutionException e) {
1073 LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e);
1079 private void createRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, final VrfTablesKey vrfTableKey,
1080 final VrfEntry vrfEntry, WriteTransaction tx) {
1081 Boolean wrTxPresent = true;
1083 wrTxPresent = false;
1084 tx = dataBroker.newWriteOnlyTransaction();
1086 String rd = vrfTableKey.getRouteDistinguisher();
1087 LOG.debug( "createremotefibentry: adding route {} for rd {} with transaction {}",
1088 vrfEntry.getDestPrefix(), rd, tx);
1089 /********************************************/
1090 List<String> tunnelInterfaceList = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
1092 if (tunnelInterfaceList.isEmpty()) {
1093 LOG.error("Could not get interface for nexthop: {} in vpn {}",
1094 vrfEntry.getNextHopAddressList(), rd);
1095 LOG.warn("Failed to add Route: {} in vpn: {}",
1096 vrfEntry.getDestPrefix(), rd);
1100 for (String tunnelInterface : tunnelInterfaceList) {
1101 List<InstructionInfo> instructions = new ArrayList<>();
1102 List<ActionInfo> actionInfos = new ArrayList<>();
1103 Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
1104 if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
1105 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
1106 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[]{null}));
1107 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[]{Long.toString(vrfEntry.getLabel())}));
1109 int label = vrfEntry.getLabel().intValue();
1110 BigInteger tunnelId;
1111 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
1112 if (tunnel_type.equals(TunnelTypeVxlan.class)) {
1113 tunnelId = BigInteger.valueOf(label);
1115 tunnelId = BigInteger.valueOf(label);
1118 LOG.debug("adding set tunnel id action for label {}", label);
1119 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{tunnelId}));
1121 List<ActionInfo> egressActions = nextHopManager.getEgressActionsForInterface(tunnelInterface);
1122 if(egressActions.isEmpty()){
1123 LOG.error("Failed to retrieve egress action for prefix {} nextHop {} interface {}. Aborting remote FIB entry creation.", vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), tunnelInterface);
1126 actionInfos.addAll(egressActions);
1127 instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
1128 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
1133 LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
1136 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
1137 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
1138 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1139 if (dpnInVpn.isPresent()) {
1140 List<VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
1141 VpnInterfaces currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
1143 if (vpnInterfaces.remove(currVpnInterface)) {
1144 if (vpnInterfaces.isEmpty()) {
1145 LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
1146 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1147 cleanUpDpnForVpn(dpnId, vpnId, rd, null);
1149 LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
1150 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id.child(
1151 VpnInterfaces.class,
1152 new VpnInterfacesKey(intfName)));
1158 private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
1159 /* Get interface info from prefix to interface mapping;
1160 Use the interface info to get the corresponding vpn interface op DS entry,
1161 remove the adjacency corresponding to this fib entry.
1162 If adjacency removed is the last adjacency, clean up the following:
1163 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
1164 - prefix to interface entry
1165 - vpn interface op DS
1167 LOG.debug("Cleanup of prefix {} in VPN {}", vrfEntry.getDestPrefix(), vpnId);
1168 Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
1169 Extraroute extraRoute = null;
1170 if (prefixInfo == null) {
1171 extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1172 if(extraRoute != null) {
1173 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1174 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
1176 if (nextHopIp != null) {
1177 prefixInfo = getPrefixToInterface(vpnId, nextHopIp + "/32");
1178 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1182 if (prefixInfo == null) {
1183 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1184 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
1185 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1186 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
1187 prefixBuilder.setDpnId(lri.getDpnId());
1188 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
1189 prefixBuilder.setIpAddress(lri.getPrefix());
1190 prefixInfo = prefixBuilder.build();
1191 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
1192 vrfEntry.getLabel(), prefixInfo.getVpnInterfaceName(), lri.getDpnId());
1193 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1197 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1201 private void checkCleanUpOpDataForFib(final Prefixes prefixInfo, final Long vpnId, final String rd,
1202 final VrfEntry vrfEntry, final Extraroute extraRoute) {
1204 if (prefixInfo == null) {
1205 LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for prefix {}", vrfEntry.getDestPrefix());
1206 return; //Don't have any info for this prefix (shouldn't happen); need to return
1209 String ifName = prefixInfo.getVpnInterfaceName();
1210 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1211 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + ifName,
1212 new CleanupVpnInterfaceWorker(prefixInfo, vpnId, rd, vrfEntry, extraRoute));
1215 private class CleanupVpnInterfaceWorker implements Callable<List<ListenableFuture<Void>>> {
1216 Prefixes prefixInfo;
1220 Extraroute extraRoute;
1222 public CleanupVpnInterfaceWorker(final Prefixes prefixInfo, final Long vpnId, final String rd,
1223 final VrfEntry vrfEntry, final Extraroute extraRoute) {
1224 this.prefixInfo = prefixInfo;
1227 this.vrfEntry= vrfEntry;
1228 this.extraRoute = extraRoute;
1232 public List<ListenableFuture<Void>> call() throws Exception {
1233 // If another renderer(for eg : CSS) needs to be supported, check can be performed here
1234 // to call the respective helpers.
1235 String ifName = prefixInfo.getVpnInterfaceName();
1236 Optional<VpnInterface> optvpnInterface = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1237 FibUtil.getVpnInterfaceIdentifier(ifName));
1238 if (optvpnInterface.isPresent()) {
1239 long associatedVpnId = FibUtil.getVpnId(dataBroker, optvpnInterface.get().getVpnInstanceName());
1240 if (vpnId != associatedVpnId) {
1241 LOG.warn("Prefixes {} are associated with different vpn instance with id : {} rather than {}",
1242 vrfEntry.getDestPrefix(), associatedVpnId, vpnId);
1243 LOG.trace("Releasing prefix label - rd {}, prefix {}", rd, vrfEntry.getDestPrefix());
1244 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1245 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1246 LOG.warn("Not proceeding with Cleanup op data for prefix {}", vrfEntry.getDestPrefix());
1249 LOG.debug("Processing cleanup of prefix {} associated with vpn {}",
1250 vrfEntry.getDestPrefix(), associatedVpnId);
1253 if (extraRoute != null) {
1254 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1255 FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
1257 Optional<Adjacencies> optAdjacencies = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1258 FibUtil.getAdjListPath(ifName));
1260 if (optAdjacencies.isPresent()) {
1261 numAdj = optAdjacencies.get().getAdjacency().size();
1263 //remove adjacency corr to prefix
1265 LOG.info("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix());
1266 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1267 FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
1269 if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
1270 //clean up the vpn interface from DpnToVpn list
1271 LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
1272 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1273 FibUtil.getVpnInterfaceIdentifier(ifName));
1276 synchronized (vrfEntry.getLabel().toString().intern()) {
1277 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1278 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
1279 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1280 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
1281 String vpnInstanceName = "";
1282 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1283 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1285 boolean lriRemoved = deleteLabelRouteInfo(lri, vpnInstanceName);
1287 String parentRd = lri.getParentVpnRd();
1288 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1289 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1292 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1293 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1300 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1301 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1302 final String rd = vrfTableKey.getRouteDistinguisher();
1303 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1304 if (vpnInstance == null) {
1305 LOG.error("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1308 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1310 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1311 if (subnetRoute != null) {
1312 elanTag = subnetRoute.getElantag();
1313 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
1314 rd, vrfEntry.getDestPrefix(), elanTag);
1315 if (vpnToDpnList != null) {
1316 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1317 dataStoreCoordinator.enqueueJob("FIB" + rd.toString() + vrfEntry.getDestPrefix(),
1318 new Callable<List<ListenableFuture<Void>>>() {
1320 public List<ListenableFuture<Void>> call() throws Exception {
1321 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1323 for (final VpnToDpnList curDpn : vpnToDpnList) {
1325 makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry,
1326 vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW, tx);
1327 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1328 makeLFibTableEntry(curDpn.getDpnId(), vrfEntry.getLabel(), null,
1329 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1332 List<ListenableFuture<Void>> futures = new ArrayList<>();
1333 futures.add(tx.submit());
1338 synchronized (vrfEntry.getLabel().toString().intern()) {
1339 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1340 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) && vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1341 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
1342 String vpnInstanceName = "";
1343 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1344 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1346 boolean lriRemoved = this.deleteLabelRouteInfo(lri, vpnInstanceName);
1348 String parentRd = lri.getParentVpnRd();
1349 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1350 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1351 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {} as labelRouteInfo cleared", vrfEntry.getLabel(), rd,
1352 vrfEntry.getDestPrefix());
1355 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1356 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1357 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd,
1358 vrfEntry.getDestPrefix());
1364 final List<BigInteger> localDpnIdList = deleteLocalFibEntry(vpnInstance.getVpnId(),
1365 vrfTableKey.getRouteDistinguisher(), vrfEntry);
1366 if (vpnToDpnList != null) {
1367 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1368 dataStoreCoordinator.enqueueJob("FIB" + rd.toString() + vrfEntry.getDestPrefix(),
1369 new Callable<List<ListenableFuture<Void>>>() {
1371 public List<ListenableFuture<Void>> call() throws Exception {
1372 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1374 if (localDpnIdList.size() <= 0) {
1375 for (VpnToDpnList curDpn : vpnToDpnList) {
1376 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1377 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1378 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1381 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1385 for (BigInteger localDpnId : localDpnIdList) {
1386 for (VpnToDpnList curDpn : vpnToDpnList) {
1387 if (!curDpn.getDpnId().equals(localDpnId)) {
1388 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1389 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1390 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1393 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1399 List<ListenableFuture<Void>> futures = new ArrayList<>();
1400 futures.add(tx.submit());
1406 //The flow/group entry has been deleted from config DS; need to clean up associated operational
1407 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
1408 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
1410 // Remove all fib entries configured due to interVpnLink, when nexthop is the opposite endPoint
1411 // of the interVpnLink.
1412 Optional<String> vpnUuid = FibUtil.getVpnNameFromRd(dataBroker, rd);
1413 if ( vpnUuid.isPresent() ) {
1414 Optional<InterVpnLink> interVpnLink = FibUtil.getInterVpnLinkByVpnUuid(dataBroker, vpnUuid.get());
1415 String routeNexthop = vrfEntry.getNextHopAddressList().get(0);
1417 if ( interVpnLink.isPresent()
1418 && ( (interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid.get())
1419 && interVpnLink.get().getSecondEndpoint().getIpAddress().getValue().equals(routeNexthop))
1420 || (interVpnLink.get().getSecondEndpoint().getVpnUuid().getValue().equals(vpnUuid.get() )
1421 && interVpnLink.get().getFirstEndpoint().getIpAddress().getValue().equals(routeNexthop)) ) ) {
1422 // This is route that points to the other endpoint of an InterVpnLink
1423 // In that case, we should look for the FIB table pointing to LPortDispatcher table and remove it.
1424 removeRouteFromInterVpnLink(interVpnLink.get(), rd, vrfEntry);
1431 Please note that the following deleteFibEntries will be invoked only for BGP Imported Routes.
1432 The invocation of the following method is via delete() callback from the MDSAL Batching Infrastructure
1433 provided by ResourceBatchingManager
1435 private void deleteFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1436 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1438 final String rd = vrfTableKey.getRouteDistinguisher();
1439 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1440 if (vpnInstance == null) {
1441 LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1444 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1445 if (vpnToDpnList != null) {
1446 for (VpnToDpnList curDpn : vpnToDpnList) {
1447 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1448 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, writeTx);
1454 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
1455 final long vpnId, final VrfTablesKey vrfTableKey,
1456 final VrfEntry vrfEntry, WriteTransaction tx) {
1458 Boolean wrTxPresent = true;
1460 wrTxPresent = false;
1461 tx = dataBroker.newWriteOnlyTransaction();
1464 LOG.debug("deleting route: prefix={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
1465 String rd = vrfTableKey.getRouteDistinguisher();
1467 if(localDpnId != null) {
1468 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
1469 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1473 // below two reads are kept as is, until best way is found to identify dpnID
1474 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
1475 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1477 if (localNextHopInfo == null && extraRoute != null) {
1478 // Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
1479 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1480 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp);
1481 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1484 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1491 private boolean checkDpnDeleteFibEntry(VpnNexthop localNextHopInfo, BigInteger remoteDpnId, long vpnId,
1492 VrfEntry vrfEntry, String rd, WriteTransaction tx){
1493 boolean isRemoteRoute = true;
1494 if (localNextHopInfo != null) {
1495 isRemoteRoute = (!remoteDpnId.equals(localNextHopInfo.getDpnId()));
1497 if (isRemoteRoute) {
1498 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1501 LOG.debug("Did not delete FIB entry: rd={}, vrfEntry={}, as it is local to dpnId={}", rd, vrfEntry.getDestPrefix(), remoteDpnId);
1506 private void deleteFibEntry(BigInteger remoteDpnId, long vpnId, VrfEntry vrfEntry, String rd, WriteTransaction tx){
1507 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1508 LOG.debug("Successfully delete FIB entry: vrfEntry={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
1512 (byte[] rawIpAddress) {
1513 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
1514 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
1517 private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
1518 List<InstructionInfo> instructions, int addOrRemove, WriteTransaction tx) {
1519 Boolean wrTxPresent = true;
1521 wrTxPresent = false;
1522 tx = dataBroker.newWriteOnlyTransaction();
1525 LOG.trace("makeConnectedRoute: vrfEntry {}", vrfEntry);
1526 String values[] = vrfEntry.getDestPrefix().split("/");
1527 String ipAddress = values[0];
1528 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
1529 if (addOrRemove == NwConstants.ADD_FLOW) {
1530 LOG.debug("Adding route to DPN {} for rd {} prefix {} ", dpId, rd, vrfEntry.getDestPrefix());
1532 LOG.debug("Removing route from DPN {} for rd {} prefix {}", dpId, rd, vrfEntry.getDestPrefix());
1534 InetAddress destPrefix;
1536 destPrefix = InetAddress.getByName(ipAddress);
1537 } catch (UnknownHostException e) {
1538 LOG.error("Failed to get destPrefix for prefix {} ", vrfEntry.getDestPrefix(), e);
1542 List<MatchInfo> matches = new ArrayList<>();
1544 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
1545 MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
1547 matches.add(new MatchInfo(MatchFieldType.eth_type,
1548 new long[] { NwConstants.ETHTYPE_IPV4 }));
1550 if(prefixLength != 0) {
1551 matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
1552 destPrefix.getHostAddress(), Integer.toString(prefixLength)}));
1554 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
1555 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, priority, destPrefix);
1556 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
1557 COOKIE_VM_FIB_TABLE, matches, instructions);
1559 Flow flow = flowEntity.getFlowBuilder().build();
1560 String flowId = flowEntity.getFlowId();
1561 FlowKey flowKey = new FlowKey( new FlowId(flowId));
1562 Node nodeDpn = buildDpnNode(dpId);
1564 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1565 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1566 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1567 if (addOrRemove == NwConstants.ADD_FLOW) {
1568 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true);
1570 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1578 //TODO: How to handle the below code, its a copy paste from MDSALManager.java
1579 private Node buildDpnNode(BigInteger dpnId) {
1580 NodeId nodeId = new NodeId("openflow:" + dpnId);
1581 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
1586 private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions, int priority,
1587 int addOrRemove, WriteTransaction tx) {
1588 Boolean wrTxPresent = true;
1590 wrTxPresent = false;
1591 tx = dataBroker.newWriteOnlyTransaction();
1594 List<MatchInfo> matches = new ArrayList<MatchInfo>();
1595 matches.add(new MatchInfo(MatchFieldType.eth_type,
1596 new long[] { NwConstants.ETHTYPE_MPLS_UC }));
1597 matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
1599 // Install the flow entry in L3_LFIB_TABLE
1600 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, priority);
1602 FlowEntity flowEntity;
1603 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef, priority, flowRef, 0, 0,
1604 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
1605 Flow flow = flowEntity.getFlowBuilder().build();
1606 String flowId = flowEntity.getFlowId();
1607 FlowKey flowKey = new FlowKey( new FlowId(flowId));
1608 Node nodeDpn = buildDpnNode(dpId);
1609 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1610 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1611 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1613 if (addOrRemove == NwConstants.ADD_FLOW) {
1614 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true);
1616 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1621 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} modified successfully {}",
1622 dpId, label, instructions );
1625 private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
1626 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
1628 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
1629 } catch (NullPointerException e) {
1634 public void populateFibOnNewDpn(final BigInteger dpnId, final long vpnId, final String rd,
1635 final FutureCallback<List<Void>> callback) {
1636 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
1637 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1638 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1639 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1640 if (vrfTable.isPresent()) {
1641 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1642 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1643 new Callable<List<ListenableFuture<Void>>>() {
1645 public List<ListenableFuture<Void>> call() throws Exception {
1646 List<ListenableFuture<Void>> futures = new ArrayList<>();
1647 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1648 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1649 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1651 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1652 if (subnetRoute != null) {
1653 long elanTag = subnetRoute.getElantag();
1654 installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
1657 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
1658 //Handle local flow creation for imports
1659 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1660 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()
1661 ) && vrfEntry.getNextHopAddressList()
1662 .contains(lri.getNextHopIpList().get(0))) {
1663 if (lri.getDpnId().equals(dpnId)) {
1664 createLocalFibEntry(vpnId, rd, vrfEntry);
1669 // Passing null as we don't know the dpn
1670 // to which prefix is attached at this point
1671 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1673 //TODO: if we have 100K entries in FIB, can it fit in one Tranasaction (?)
1674 futures.add(tx.submit());
1675 if (callback != null) {
1676 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1677 Futures.addCallback(listenableFuture, callback);
1686 public void populateFibOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1687 final String localNextHopIp, final String remoteNextHopIp) {
1688 LOG.trace("dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} : populateFibOnDpn",
1689 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1690 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1691 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1692 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1693 if (vrfTable.isPresent()) {
1694 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1695 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1696 new Callable<List<ListenableFuture<Void>>>() {
1698 public List<ListenableFuture<Void>> call() throws Exception {
1699 List<ListenableFuture<Void>> futures = new ArrayList<>();
1700 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1701 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1702 LOG.trace("populate FIB starts on Dpn " + dpnId
1703 + "rd " + rd.toString()
1704 + "localNextHopIp " + localNextHopIp
1705 + "remoteNextHopIp" + remoteNextHopIp
1706 + "vpnId " + vpnId );
1707 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1708 LOG.trace("old vrfEntry before populate:: {}", vrfEntry);
1710 if (vrfEntry.getOrigin().equals(RouteOrigin.BGP.getValue())) {
1711 if (remoteNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1712 LOG.trace(" creating remote FIB entry for vfEntry {}", vrfEntry);
1713 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeTransaction);
1715 } else if (vrfEntry.getOrigin().equals(RouteOrigin.STATIC.getValue())) {
1716 BigInteger dpnIdForPrefix = null;
1717 String destPfx = vrfEntry.getDestPrefix();
1718 if (vrfEntry.getAugmentation(SubnetRoute.class) == null) {
1719 Optional<Extraroute> extraRouteInfo =
1720 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1721 getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
1722 if (extraRouteInfo.isPresent()) {
1725 dpnIdForPrefix = nextHopManager.getDpnForPrefix(vpnId, destPfx);
1727 // Subnet Route handling
1728 Optional<Prefixes> localNextHopInfoData =
1729 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1730 FibUtil.getPrefixToInterfaceIdentifier(vpnId, destPfx));
1731 if (localNextHopInfoData.isPresent()) {
1732 Prefixes prefixes = localNextHopInfoData.get();
1733 dpnIdForPrefix = prefixes.getDpnId();
1736 if (dpnIdForPrefix == null) {
1737 LOG.trace("Populate::the dpnIdForPrefix is null for prefix {}.",
1738 vrfEntry.getDestPrefix());
1741 int sameDpnId = dpnIdForPrefix.compareTo(dpnId);
1742 if (sameDpnId != 0) {
1743 LOG.trace("Populate::Different srcDpnId {} and dpnIdForPrefix {} for prefix {}",
1744 dpnId, dpnIdForPrefix, vrfEntry.getDestPrefix());
1747 InstanceIdentifier<VrfEntry> vrfEntryId = getVrfEntryId(rd, vrfEntry.getDestPrefix());
1748 List<String> newNextHopAddrList = vrfEntry.getNextHopAddressList();
1749 newNextHopAddrList.add(localNextHopIp);
1750 VrfEntry newVrfEntry =
1751 new VrfEntryBuilder(vrfEntry).setNextHopAddressList(newNextHopAddrList).build();
1752 // Just update the VrfEntry
1753 FibUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
1754 vrfEntryId, newVrfEntry);
1755 // writeTransaction.put(LogicalDatastoreType.CONFIGURATION,
1756 // vrfEntryId, newVrfEntry);
1757 vrfEntry = getVrfEntry(dataBroker, rd, destPfx);
1758 LOG.trace("updated vrfEntry after populate:: {}", vrfEntry);
1761 futures.add(writeTransaction.submit());
1762 LOG.trace("populate FIB ends on Dpn " + dpnId
1763 + "rd " + rd.toString()
1764 + "localNextHopIp " + localNextHopIp
1765 + "remoteNextHopIp" + remoteNextHopIp
1766 + "vpnId " + vpnId);
1774 public void handleRemoteRoute(final boolean action, final BigInteger localDpnId, final BigInteger remoteDpnId,
1775 final long vpnId, final String rd, final String destPrefix ,
1776 final String localNextHopIP, final String remoteNextHopIp) {
1778 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1779 dataStoreCoordinator.enqueueJob( "FIB" + rd.toString()
1780 + "local dpid" + localDpnId
1781 + "remote dpid" + remoteDpnId
1783 + "localNHIp" + localNextHopIP
1784 + "remoteNHIp" + remoteNextHopIp,
1785 new Callable<List<ListenableFuture<Void>>>() {
1787 public List<ListenableFuture<Void>> call() throws Exception {
1788 List<ListenableFuture<Void>> futures = new ArrayList<>();
1789 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1790 VrfTablesKey vrfTablesKey = new VrfTablesKey(rd);
1791 VrfEntry vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1792 if (vrfEntry == null)
1794 LOG.trace("handleRemoteRoute :: action {}, localDpnId {}, " +
1795 "remoteDpnId {} , vpnId {}, rd {}, destPfx {}",
1796 action, localDpnId, remoteDpnId, vpnId, rd, destPrefix);
1797 if (action == true) {
1798 vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1799 LOG.trace("handleRemoteRoute updated(add) vrfEntry :: {}", vrfEntry);
1800 createRemoteFibEntry(remoteDpnId, vpnId, vrfTablesKey, vrfEntry, writeTransaction);
1802 vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1803 LOG.trace("handleRemoteRoute updated(remove) vrfEntry :: {}", vrfEntry);
1804 deleteRemoteRoute(null, remoteDpnId, vpnId, vrfTablesKey, vrfEntry, writeTransaction);
1806 futures.add(writeTransaction.submit());
1812 public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd,
1813 final FutureCallback<List<Void>> callback) {
1814 LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
1815 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1816 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1817 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1818 if (vrfTable.isPresent()) {
1819 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1820 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1821 new Callable<List<ListenableFuture<Void>>>() {
1823 public List<ListenableFuture<Void>> call() throws Exception {
1824 List<ListenableFuture<Void>> futures = new ArrayList<>();
1825 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1826 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1827 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1828 /* Handle subnet routes here */
1829 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1830 if (subnetRoute != null) {
1831 LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(),
1833 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1834 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1835 LOG.trace("cleanUpDpnForVpn: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd,
1836 vrfEntry.getDestPrefix());
1839 // Passing null as we don't know the dpn
1840 // to which prefix is attached at this point
1841 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1843 futures.add(tx.submit());
1844 if (callback != null) {
1845 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1846 Futures.addCallback(listenableFuture, callback);
1856 public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd,
1857 final String localNextHopIp, final String remoteNextHopIp,
1858 final FutureCallback<List<Void>> callback) {
1859 LOG.trace( " cleanup remote routes on dpn {} for vpn {}, rd {}, " +
1860 " localNexthopIp {} , remoteNexhtHopIp {} : cleanUpDpnForVpn",
1861 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1862 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1863 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1864 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1865 if (vrfTable.isPresent()) {
1866 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1867 dataStoreCoordinator.enqueueJob(" FIB-" + vpnId + "-" + dpnId.toString(),
1868 new Callable<List<ListenableFuture<Void>>>() {
1870 public List<ListenableFuture<Void>> call() throws Exception {
1871 List<ListenableFuture<Void>> futures = new ArrayList<>();
1872 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1873 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1874 LOG.trace("cleanup FIB starts on Dpn " + dpnId
1875 + "rd " + rd.toString()
1876 + "localNextHopIp " + localNextHopIp
1877 + "remoteNextHopIp" + remoteNextHopIp
1878 + "vpnId " + vpnId);
1880 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1881 LOG.trace("old vrfEntry before cleanup:: {}", vrfEntry);
1882 if (remoteNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1883 LOG.trace(" deleting remote FIB entry {}", vrfEntry);
1884 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeTransaction);
1887 if (localNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1888 LOG.trace("changing the nexthopip for local VM routes {} on dpn {}",
1889 vrfEntry.getDestPrefix(), dpnId);
1890 String destPfx = vrfEntry.getDestPrefix();
1891 InstanceIdentifier<VrfEntry> vrfEntryId = getVrfEntryId(rd, destPfx);
1892 List<java.lang.String> newList = vrfEntry.getNextHopAddressList();
1893 newList.remove(localNextHopIp);
1894 VrfEntry newVrfEntry =
1895 new VrfEntryBuilder(vrfEntry).setNextHopAddressList(newList).build();
1896 FibUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
1897 vrfEntryId, newVrfEntry);
1898 vrfEntry = getVrfEntry(dataBroker, rd, destPfx);
1899 LOG.trace("updated vrfEntry after cleanup:: {}", vrfEntry);
1902 futures.add(writeTransaction.submit());
1903 if (callback != null) {
1904 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1905 Futures.addCallback(listenableFuture, callback);
1907 LOG.trace("cleanup FIB ends on Dpn " + dpnId
1908 + "rd " + rd.toString()
1909 + "localNextHopIp " + localNextHopIp
1910 + "remoteNextHopIp" + remoteNextHopIp
1911 + "vpnId " + vpnId);
1920 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
1921 InstanceIdentifierBuilder<VrfTables> idBuilder =
1922 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1923 InstanceIdentifier<VrfTables> id = idBuilder.build();
1927 private String getFlowRef(BigInteger dpnId, short tableId, long label, int priority) {
1928 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
1929 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(label).append(NwConstants.FLOWID_SEPARATOR)
1930 .append(priority).toString();
1933 private String getFlowRef(BigInteger dpnId, short tableId, String rd, int priority, InetAddress destPrefix) {
1934 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
1935 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
1936 .append(rd).append(NwConstants.FLOWID_SEPARATOR)
1937 .append(priority).append(NwConstants.FLOWID_SEPARATOR)
1938 .append(destPrefix.getHostAddress()).toString();
1941 private String getInterVpnFibFlowRef(String interVpnLinkName, String prefix, String nextHop ) {
1942 return new StringBuilder(64).append(FLOWID_PREFIX)
1943 .append(interVpnLinkName).append(NwConstants.FLOWID_SEPARATOR)
1944 .append(prefix).append(NwConstants.FLOWID_SEPARATOR)
1945 .append(nextHop).toString();
1948 protected List<String> resolveAdjacency(final BigInteger remoteDpnId, final long vpnId,
1949 final VrfEntry vrfEntry, String rd) {
1950 List<String> adjacencyList = new ArrayList<>();
1951 List<String> prefixIpList = new ArrayList<>();
1952 LOG.trace("resolveAdjacency called with remotedpid {}, vpnId{}, VrfEntry {}",
1953 remoteDpnId, vpnId, vrfEntry);
1955 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
1956 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1957 if (extra_route == null) {
1958 prefixIpList = Arrays.asList(vrfEntry.getDestPrefix());
1960 prefixIpList = new ArrayList<>();
1961 for (String extraRouteIp : extra_route.getNexthopIpList()) {
1962 prefixIpList.add(extraRouteIp + "/32");
1966 prefixIpList = Arrays.asList(vrfEntry.getDestPrefix());
1969 for (String prefixIp : prefixIpList) {
1970 for (String nextHopIp : vrfEntry.getNextHopAddressList()) {
1971 LOG.debug("NextHop IP for destination {} is {}", prefixIp, nextHopIp);
1972 String adjacency = nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId,
1973 prefixIp, nextHopIp);
1974 if (adjacency != null && !adjacency.isEmpty() && !adjacencyList.contains(adjacency)) {
1975 adjacencyList.add(adjacency);
1979 } catch (NullPointerException e) {
1982 return adjacencyList;
1985 protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
1986 InstanceIdentifier<VpnInstanceOpDataEntry> id =
1987 InstanceIdentifier.create(VpnInstanceOpData.class)
1988 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
1989 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData =
1990 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1991 return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null;
1994 public void processNodeAdd(BigInteger dpnId) {
1995 LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
1996 makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
1997 makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
1998 makeSubnetRouteTableMissFlow(dpnId, NwConstants.ADD_FLOW);
2001 private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
2002 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
2003 // Instruction to goto L3 InterfaceTable
2004 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
2005 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE }));
2006 List<MatchInfo> matches = new ArrayList<MatchInfo>();
2007 FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE,
2008 getTableMissFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW),
2009 NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
2011 FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE,
2012 getTableMissFlowRef(dpnId, NwConstants.L3_FIB_TABLE,
2013 NwConstants.TABLE_MISS_FLOW),
2014 NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow",
2015 0, 0, COOKIE_VM_FIB_TABLE,
2016 matches, instructions);
2018 if (addOrRemove == NwConstants.ADD_FLOW) {
2019 LOG.debug("Invoking MDSAL to install Table Miss Entries");
2020 mdsalManager.installFlow(flowEntityLfib);
2021 mdsalManager.installFlow(flowEntityFib);
2023 mdsalManager.removeFlow(flowEntityLfib);
2024 mdsalManager.removeFlow(flowEntityFib);
2029 private String getTableMissFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
2030 return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
2031 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
2032 .append(FLOWID_PREFIX).toString();
2036 * Install flow entry in protocol table to forward mpls
2037 * coming through gre tunnel to LFIB table.
2039 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
2040 final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
2041 // Instruction to goto L3 InterfaceTable
2042 List<InstructionInfo> instructions = new ArrayList<>();
2043 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
2044 List<MatchInfo> matches = new ArrayList<MatchInfo>();
2045 matches.add(new MatchInfo(MatchFieldType.eth_type,
2046 new long[] { NwConstants.ETHTYPE_MPLS_UC }));
2047 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2048 getTableMissFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2049 NwConstants.L3_LFIB_TABLE),
2050 DEFAULT_FIB_FLOW_PRIORITY,
2051 "Protocol Table For LFIB",
2053 COOKIE_PROTOCOL_TABLE,
2054 matches, instructions);
2056 if (addOrRemove == NwConstants.ADD_FLOW) {
2057 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
2058 mdsalManager.installFlow(flowEntityToLfib);
2060 mdsalManager.removeFlow(flowEntityToLfib);
2064 public List<String> printFibEntries() {
2065 List<String> result = new ArrayList<String>();
2066 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s", "RD", "Prefix", "NextHop", "Label", "Origin"));
2067 result.add("-------------------------------------------------------------------");
2068 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
2069 Optional<FibEntries> fibEntries = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2070 if (fibEntries.isPresent()) {
2071 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
2072 for (VrfTables vrfTable : vrfTables) {
2073 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
2074 for (String nextHop : vrfEntry.getNextHopAddressList()) {
2075 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s",
2076 vrfTable.getRouteDistinguisher(),
2077 vrfEntry.getDestPrefix(), nextHop, vrfEntry.getLabel(), vrfEntry.getOrigin()));
2079 if (vrfEntry.getNextHopAddressList().isEmpty()) {
2080 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s",
2081 vrfTable.getRouteDistinguisher(),
2082 vrfEntry.getDestPrefix(), "local", vrfEntry.getLabel(), vrfEntry.getOrigin()));
2090 private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) {
2091 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
2092 List<MatchInfo> matches = new ArrayList<MatchInfo>();
2093 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
2094 // Instruction to goto L3 InterfaceTable
2096 List <ActionInfo> actionsInfos = new ArrayList <ActionInfo> ();
2097 actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{
2098 Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)}));
2099 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
2100 //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE }));
2102 FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE,
2103 getTableMissFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW),
2104 NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS,
2105 matches, instructions);
2106 if (addOrRemove == NwConstants.ADD_FLOW) {
2107 LOG.debug("Invoking MDSAL to install L3 interface Table Miss Entries");
2108 mdsalManager.installFlow(flowEntityL3Intf);
2110 mdsalManager.removeFlow(flowEntityL3Intf);
2114 private VrfEntry getVrfEntry(DataBroker broker, String rd, String ipPrefix) {
2115 InstanceIdentifier<VrfEntry> vrfEntryId =
2116 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).
2117 child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2118 Optional<VrfEntry> vrfEntry = read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
2119 if (vrfEntry.isPresent()) {
2120 return (vrfEntry.get());
2125 private InstanceIdentifier<VrfEntry> getVrfEntryId(String rd, String ipPrefix) {
2126 InstanceIdentifier<VrfEntry> vrfEntryId =
2127 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).
2128 child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();