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());
226 leakRouteIfNeeded(identifier, vrfEntry, NwConstants.DEL_FLOW);
230 protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
231 Preconditions.checkNotNull(update, "VrfEntry should not be null or empty.");
232 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
233 LOG.debug("UPDATE: Updating Fib Entries to rd {} prefix {} nexthop {} label {}",
234 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
235 if (RouteOrigin.value(update.getOrigin()) != RouteOrigin.BGP) {
236 createFibEntries(identifier, update);
238 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + update.getDestPrefix());
239 actResource.setAction(ActionableResource.UPDATE);
240 actResource.setInstanceIdentifier(identifier);
241 actResource.setInstance(update);
242 actResource.setOldInstance(original);
243 vrfEntryBufferQ.add(actResource);
245 LOG.debug("UPDATE: Updated Fib Entries to rd {} prefix {} nexthop {} label {}",
246 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
250 public void create(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object vrfEntry) {
251 if (vrfEntry instanceof VrfEntry) {
252 createFibEntries(tx, identifier, (VrfEntry)vrfEntry);
257 public void delete(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object vrfEntry) {
258 if (vrfEntry instanceof VrfEntry) {
259 deleteFibEntries(tx, identifier, (VrfEntry) vrfEntry);
264 public void update(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object original,
266 if ((original instanceof VrfEntry) && (update instanceof VrfEntry)) {
267 createFibEntries(tx, identifier, (VrfEntry)update);
272 public int getBatchSize() {
277 public int getBatchInterval() {
278 return batchInterval;
282 public LogicalDatastoreType getDatastoreType() {
283 return LogicalDatastoreType.CONFIGURATION;
286 private void createFibEntries(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
287 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
289 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
290 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
291 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
293 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
294 final Long vpnId = vpnInstance.getVpnId();
295 final String rd = vrfTableKey.getRouteDistinguisher();
296 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
297 if (subnetRoute != null) {
298 final long elanTag = subnetRoute.getElantag();
299 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
300 rd, vrfEntry.getDestPrefix(), elanTag);
301 if (vpnToDpnList != null) {
302 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
303 dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(),
304 new Callable<List<ListenableFuture<Void>>>() {
306 public List<ListenableFuture<Void>> call() throws Exception {
307 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
308 for (final VpnToDpnList curDpn : vpnToDpnList) {
309 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
310 installSubnetRouteInFib(curDpn.getDpnId(), elanTag, rd, vpnId.longValue(), vrfEntry, tx);
313 List<ListenableFuture<Void>> futures = new ArrayList<>();
314 futures.add(tx.submit());
322 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.INTERVPN) {
323 // When it is a leaked route, the LFIB and FIB goes a bit different.
324 installInterVpnRouteInLFib(rd, vrfEntry);
328 final List<BigInteger> localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry);
330 if (vpnToDpnList != null) {
331 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
332 dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(),
333 new Callable<List<ListenableFuture<Void>>>() {
335 public List<ListenableFuture<Void>> call() throws Exception {
336 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
337 for (VpnToDpnList vpnDpn : vpnToDpnList) {
338 if ( !localDpnIdList.contains(vpnDpn.getDpnId())) {
339 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
340 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
344 List<ListenableFuture<Void>> futures = new ArrayList<>();
345 futures.add(tx.submit());
351 Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(dataBroker, rd);
352 if ( optVpnUuid.isPresent() ) {
353 Optional<InterVpnLink> interVpnLink = FibUtil.getInterVpnLinkByVpnUuid(dataBroker, optVpnUuid.get());
354 if ( interVpnLink.isPresent() ) {
355 String vpnUuid = optVpnUuid.get();
356 String routeNexthop = vrfEntry.getNextHopAddressList().get(0);
357 if ( isNexthopTheOtherVpnLinkEndpoint(routeNexthop, vpnUuid, interVpnLink.get()) ) {
358 // This is an static route that points to the other endpoint of an InterVpnLink
359 // In that case, we should add another entry in FIB table pointing to LPortDispatcher table.
360 installRouteInInterVpnLink(interVpnLink.get(), vpnUuid, vrfEntry, vpnId);
368 Please note that the following createFibEntries will be invoked only for BGP Imported Routes.
369 The invocation of the following method is via create() callback from the MDSAL Batching Infrastructure
370 provided by ResourceBatchingManager
372 private void createFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
373 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
375 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
376 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
377 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
379 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
380 final String rd = vrfTableKey.getRouteDistinguisher();
381 if (vpnToDpnList != null) {
382 for (VpnToDpnList vpnDpn : vpnToDpnList) {
383 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
384 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, writeTx);
391 * Returns true if the specified nexthop is the other endpoint in an
392 * InterVpnLink, regarding one of the VPN's point of view.
394 private boolean isNexthopTheOtherVpnLinkEndpoint(String nexthop, String thisVpnUuid, InterVpnLink interVpnLink) {
397 && ( (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(thisVpnUuid)
398 && interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(nexthop))
399 || (interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(thisVpnUuid )
400 && interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(nexthop)) );
404 // FIXME: Refactoring needed here.
405 // This kind of logic must be taken to an 'upper' layer like BgpManager or VpnManager
406 private void leakRouteIfNeeded(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry,
408 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
409 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
411 String rd = vrfTableKey.getRouteDistinguisher();
412 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
413 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
414 if (vpnInstance == null) {
415 LOG.error("Vpn Instance not available for external route with prefix {} label {} nexthop {}. Returning...", vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList());
419 Preconditions.checkNotNull(vpnInstance,
420 "Vpn Instance not available with rd " + vrfTableKey.getRouteDistinguisher());
422 String vpnUuid = vpnInstance.getVpnInstanceName();
423 Preconditions.checkArgument(vpnUuid != null && !vpnUuid.isEmpty(),
424 "Could not find suitable VPN UUID for Route-Distinguisher=" + rd);
426 // if the new vrfEntry has been learned by Quagga BGP, its necessary to check if it's
427 // there an interVpnLink for the involved vpn in order to make learn the new route to
428 // the other part of the inter-vpn-link.
430 // For leaking, we need the InterVpnLink to be active. For removal, we just need a InterVpnLink.
431 Optional<InterVpnLink> interVpnLink =
432 (addOrRemove == NwConstants.ADD_FLOW) ? FibUtil.getActiveInterVpnLinkFromRd(dataBroker, rd)
433 : FibUtil.getInterVpnLinkByRd(dataBroker, rd);
434 if ( !interVpnLink.isPresent() ) {
435 LOG.debug("Could not find an InterVpnLink for Route-Distinguisher={}", rd);
439 // Ok, at this point everything is ready for the leaking/removal... but should it be performed?
440 // For removal, we remove all leaked routes, but we only leak a route if the corresponding flag is enabled.
441 boolean proceed = (addOrRemove == NwConstants.DEL_FLOW )
442 || ( RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP
443 && interVpnLink.get().isBgpRoutesLeaking() );
446 String theOtherVpnId = ( interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid) )
447 ? interVpnLink.get().getSecondEndpoint().getVpnUuid().getValue()
450 String dstVpnRd = FibUtil.getVpnRd(dataBroker, theOtherVpnId);
451 String endpointIp = vrfEntry.getNextHopAddressList().get(0);
453 InstanceIdentifier<VrfEntry> vrfEntryIidInOtherVpn =
454 InstanceIdentifier.builder(FibEntries.class)
455 .child(VrfTables.class, new VrfTablesKey(dstVpnRd))
456 .child(VrfEntry.class, new VrfEntryKey(vrfEntry.getDestPrefix()))
458 if ( addOrRemove == NwConstants.ADD_FLOW ) {
459 LOG.debug("Leaking route (destination={}, nexthop={}) from Vrf={} to Vrf={}",
460 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), rd, dstVpnRd);
461 String key = rd + FibConstants.SEPARATOR + vrfEntry.getDestPrefix();
462 long label = FibUtil.getUniqueId(idManager, FibConstants.VPN_IDPOOL_NAME, key);
463 VrfEntry newVrfEntry = new VrfEntryBuilder(vrfEntry).setNextHopAddressList(Arrays.asList(endpointIp))
465 .setOrigin(RouteOrigin.INTERVPN.getValue())
467 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn, newVrfEntry);
469 LOG.debug("Removing leaked vrfEntry={}", vrfEntryIidInOtherVpn.toString());
470 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn);
475 private Prefixes updateVpnReferencesInLri(LabelRouteInfo lri, String vpnInstanceName, boolean isPresentInList) {
476 LOG.debug("updating LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
477 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
478 prefixBuilder.setDpnId(lri.getDpnId());
479 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
480 prefixBuilder.setIpAddress(lri.getPrefix());
481 // Increment the refCount here
482 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
483 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long)lri.getLabel())).build();
484 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri);
485 if (!isPresentInList) {
486 LOG.debug("vpnName {} is not present in LRI with label {}..", vpnInstanceName, lri.getLabel());
487 List<String> vpnInstanceNames = lri.getVpnInstanceList();
488 vpnInstanceNames.add(vpnInstanceName);
489 builder.setVpnInstanceList(vpnInstanceNames);
490 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(), FibUtil.DEFAULT_CALLBACK);
492 LOG.debug("vpnName {} is present in LRI with label {}..", vpnInstanceName, lri.getLabel());
494 return prefixBuilder.build();
497 private void installSubnetRouteInFib(final BigInteger dpnId, final long elanTag, final String rd,
498 final long vpnId, final VrfEntry vrfEntry, WriteTransaction tx){
499 Boolean wrTxPresent = true;
502 tx = dataBroker.newWriteOnlyTransaction();
504 synchronized (vrfEntry.getLabel().toString().intern()) {
505 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
506 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
507 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
509 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
510 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
511 if (vpnInstanceOpDataEntryOptional.isPresent()) {
512 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
513 if (!lri.getVpnInstanceList().contains(vpnInstanceName)) {
514 updateVpnReferencesInLri(lri, vpnInstanceName, false);
518 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
519 vrfEntry.getLabel(), lri.getVpnInterfaceName(), lri.getDpnId());
522 final List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
523 BigInteger subnetRouteMeta = ((BigInteger.valueOf(elanTag)).shiftLeft(32)).or((BigInteger.valueOf(vpnId).shiftLeft(1)));
524 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE }));
525 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
526 makeConnectedRoute(dpnId,vpnId,vrfEntry,rd,instructions,NwConstants.ADD_FLOW, tx);
528 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
529 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
530 // reinitialize instructions list for LFIB Table
531 final List<InstructionInfo> LFIBinstructions = new ArrayList<InstructionInfo>();
533 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
534 LFIBinstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
535 LFIBinstructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE }));
536 LFIBinstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
538 makeLFibTableEntry(dpnId,vrfEntry.getLabel(), LFIBinstructions, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
545 private void installInterVpnRouteInLFib(final String rd, final VrfEntry vrfEntry) {
546 // INTERVPN routes are routes in a Vpn1 that have been leaked to Vpn2. In DC-GW, this Vpn2 route is pointing
547 // to a list of DPNs where Vpn2's VpnLink was instantiated. In these DPNs LFIB must be programmed so that the
548 // packet is commuted from Vpn2 to Vpn1.
549 Optional<String> vpnNameOpc = FibUtil.getVpnNameFromRd(dataBroker, rd);
550 if ( !vpnNameOpc.isPresent() ) {
551 LOG.warn("Could not find VpnInstanceName for Route-Distinguisher {}", rd);
555 String vpnName = vpnNameOpc.get();
556 List<InterVpnLink> interVpnLinks = FibUtil.getAllInterVpnLinks(dataBroker);
557 boolean interVpnLinkFound = false;
558 for ( InterVpnLink interVpnLink : interVpnLinks ) {
559 boolean vpnIs1stEndpoint = interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName);
560 boolean vpnIs2ndEndpoint = !vpnIs1stEndpoint
561 && interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnName);
562 if ( vpnIs1stEndpoint || vpnIs2ndEndpoint ) {
563 interVpnLinkFound = true;
565 Optional<InterVpnLinkState> vpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName());
566 if ( !vpnLinkState.isPresent()
567 || !vpnLinkState.get().getState().equals(InterVpnLinkState.State.Active) ) {
568 LOG.warn("InterVpnLink {}, linking VPN {} and {}, is not in Active state",
569 interVpnLink.getName(), interVpnLink.getFirstEndpoint().getVpnUuid().getValue(),
570 interVpnLink.getSecondEndpoint().getVpnUuid().getValue() );
574 List<BigInteger> targetDpns =
575 ( vpnIs1stEndpoint ) ? vpnLinkState.get().getFirstEndpointState().getDpId()
576 : vpnLinkState.get().getSecondEndpointState().getDpId();
578 ( vpnIs1stEndpoint ) ? vpnLinkState.get().getSecondEndpointState().getLportTag()
579 : vpnLinkState.get().getFirstEndpointState().getLportTag();
581 for ( BigInteger dpId : targetDpns ) {
582 List<ActionInfo> actionsInfos = Arrays.asList(new ActionInfo(ActionType.pop_mpls, new String[]{}));
584 BigInteger[] metadata = new BigInteger[] {
585 MetaDataUtil.getMetaDataForLPortDispatcher(lportTag.intValue(), ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
586 MetaDataUtil.getMetaDataMaskForLPortDispatcher()
588 List<InstructionInfo> instructions =
589 Arrays.asList(new InstructionInfo(InstructionType.apply_actions, actionsInfos),
590 new InstructionInfo(InstructionType.write_metadata, metadata),
591 new InstructionInfo(InstructionType.goto_table,
592 new long[] { NwConstants.L3_INTERFACE_TABLE }));
594 makeLFibTableEntry(dpId, vrfEntry.getLabel(), instructions, LFIB_INTERVPN_PRIORITY,
595 NwConstants.ADD_FLOW, null);
602 if ( !interVpnLinkFound ) {
603 LOG.warn("VrfEntry=[prefix={} label={} nexthop={}] for VPN {} has origin INTERVPN but no InterVpnLink could be found",
604 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), rd);
610 private void installRouteInInterVpnLink(final InterVpnLink interVpnLink, final String vpnUuid,
611 final VrfEntry vrfEntry, long vpnTag) {
612 Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
613 Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null
614 && vrfEntry.getNextHopAddressList().size() == 1);
615 String destination = vrfEntry.getDestPrefix();
616 String nextHop = vrfEntry.getNextHopAddressList().get(0);
618 // After having received a static route, we should check if the vpn is part of an inter-vpn-link.
619 // In that case, we should populate the FIB table of the VPN pointing to LPortDisptacher table
620 // using as metadata the LPortTag associated to that vpn in the inter-vpn-link.
621 Optional<InterVpnLinkState> interVpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName());
622 if ( !interVpnLinkState.isPresent() ) {
623 LOG.warn("Could not find State for InterVpnLink {}", interVpnLink.getName());
626 if ( ! interVpnLinkState.get().getState().equals(InterVpnLinkState.State.Active) ) {
627 LOG.warn("Route to {} with nexthop={} cannot be installed because the interVpnLink {} is not active",
628 destination, nextHop, interVpnLink.getName());
634 boolean vpnIsFirstEndpoint = isVpnFirstEndPoint(interVpnLink, vpnUuid);
635 List<BigInteger> targetDpns =
636 vpnIsFirstEndpoint ? interVpnLinkState.get().getFirstEndpointState().getDpId()
637 : interVpnLinkState.get().getSecondEndpointState().getDpId();
639 Long otherEndpointlportTag =
640 vpnIsFirstEndpoint ? interVpnLinkState.get().getSecondEndpointState().getLportTag()
641 : interVpnLinkState.get().getFirstEndpointState().getLportTag();
643 BigInteger[] metadata = new BigInteger[] {
644 MetaDataUtil.getMetaDataForLPortDispatcher(otherEndpointlportTag.intValue(),
645 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
646 MetaDataUtil.getMetaDataMaskForLPortDispatcher()
649 List<Instruction> instructions =
650 Arrays.asList(new InstructionInfo(InstructionType.write_metadata, metadata).buildInstruction(0),
651 new InstructionInfo(InstructionType.goto_table,
652 new long[] { NwConstants.L3_INTERFACE_TABLE }).buildInstruction(1));
654 String values[] = destination.split("/");
655 String destPrefixIpAddress = values[0];
656 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
658 List<MatchInfo> matches = new ArrayList<>();
659 matches.add(new MatchInfo(MatchFieldType.metadata,
660 new BigInteger[] { MetaDataUtil.getVpnIdMetadata(vpnTag),
661 MetaDataUtil.METADATA_MASK_VRFID }));
662 matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_IPV4 }));
664 if (prefixLength != 0) {
665 matches.add(new MatchInfo(MatchFieldType.ipv4_destination,
666 new String[] { destPrefixIpAddress, Integer.toString(prefixLength) }));
669 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
670 String flowRef = getInterVpnFibFlowRef(interVpnLink.getName(), destination, nextHop);
671 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
672 COOKIE_VM_FIB_TABLE, matches, instructions);
674 for ( BigInteger dpId : targetDpns ) {
675 mdsalManager.installFlow(dpId, flowEntity);
679 private void removeRouteFromInterVpnLink(final InterVpnLink interVpnLink, final String vpnUuid,
680 final VrfEntry vrfEntry) {
682 Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
683 Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null
684 && vrfEntry.getNextHopAddressList().size() == 1);
686 Optional<InterVpnLinkState> interVpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName());
687 if ( !interVpnLinkState.isPresent() ) {
688 LOG.warn("Could not find State for InterVpnLink {}", interVpnLink.getName());
693 boolean vpnIsFirstEndpoint = isVpnFirstEndPoint(interVpnLink, vpnUuid);
694 List<BigInteger> targetDpns =
695 vpnIsFirstEndpoint ? interVpnLinkState.get().getFirstEndpointState().getDpId()
696 : interVpnLinkState.get().getSecondEndpointState().getDpId();
698 String nextHop = vrfEntry.getNextHopAddressList().get(0);
699 String flowRef = getInterVpnFibFlowRef(interVpnLink.getName(), vrfEntry.getDestPrefix(), nextHop);
700 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
701 Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef)).setTableId(NwConstants.L3_FIB_TABLE)
702 .setFlowName(flowRef).build();
704 for ( BigInteger dpId : targetDpns ) {
705 mdsalManager.removeFlow(dpId, flow);
710 private boolean isVpnFirstEndPoint(InterVpnLink interVpnLink, String vpnName) {
711 return interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName);
714 private <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
715 InstanceIdentifier<T> path) {
717 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
719 Optional<T> result = Optional.absent();
721 result = tx.read(datastoreType, path).get();
722 } catch (Exception e) {
723 throw new RuntimeException(e);
729 private void makeSubnetRouteTableMissFlow(BigInteger dpnId, int addOrRemove) {
730 final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
731 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
732 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
733 actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{}));
734 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
735 List<MatchInfo> matches = new ArrayList<MatchInfo>();
736 String flowRef = getTableMissFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, NwConstants.TABLE_MISS_FLOW);
737 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef,
738 NwConstants.TABLE_MISS_PRIORITY, "Subnet Route Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
740 if (addOrRemove == NwConstants.ADD_FLOW) {
741 mdsalManager.installFlow(flowEntity);
743 mdsalManager.removeFlow(flowEntity);
747 private List<BigInteger> createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
748 List<BigInteger> returnLocalDpnId = new ArrayList<BigInteger>();
749 Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
750 String localNextHopIP = vrfEntry.getDestPrefix();
752 if (localNextHopInfo == null) {
753 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
754 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
755 if (extraRoute != null) {
756 for (String nextHopIp : extraRoute.getNexthopIpList()) {
757 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
758 if (nextHopIp != null) {
759 localNextHopInfo = getPrefixToInterface(vpnId, nextHopIp + "/32");
760 localNextHopIP = nextHopIp + "/32";
761 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, vpnId);
762 returnLocalDpnId.add(dpnId);
766 if (localNextHopInfo == null) {
767 /* imported routes case */
768 synchronized (vrfEntry.getLabel().toString().intern()) {
769 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
770 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
771 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
772 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
773 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
774 if (vpnInstanceOpDataEntryOptional.isPresent()) {
775 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
776 if (lri.getVpnInstanceList().contains(vpnInstanceName)) {
777 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, true);
778 localNextHopIP = lri.getPrefix();
780 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, false);
781 localNextHopIP = lri.getPrefix();
784 if (localNextHopInfo != null) {
785 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
786 vrfEntry.getLabel(), localNextHopInfo.getVpnInterfaceName(), lri.getDpnId());
787 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, lri.getParentVpnid());
788 returnLocalDpnId.add(dpnId);
795 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, vpnId);
796 returnLocalDpnId.add(dpnId);
799 return returnLocalDpnId;
802 private BigInteger checkCreateLocalFibEntry(Prefixes localNextHopInfo, String localNextHopIP, final Long vpnId, final String rd,
803 final VrfEntry vrfEntry, Long parentVpnId){
804 if (localNextHopInfo != null) {
805 final BigInteger dpnId = localNextHopInfo.getDpnId();
806 if (!isVpnPresentInDpn(rd, dpnId)) {
807 return BigInteger.ZERO;
810 final long groupId = nextHopManager.createLocalNextHop(parentVpnId, dpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
812 List<ActionInfo> actionsInfos =
813 Arrays.asList(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
814 final List<InstructionInfo> instructions =
815 Arrays.asList(new InstructionInfo(InstructionType.write_actions, actionsInfos));
816 actionsInfos = Arrays.asList(new ActionInfo(ActionType.pop_mpls, new String[]{}),
817 new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }) );
818 final List<InstructionInfo> lfibinstructions = Arrays.asList(new InstructionInfo(InstructionType.write_actions, actionsInfos));
819 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
820 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
821 dpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
823 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);
825 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
826 dataStoreCoordinator.enqueueJob("FIB"+vpnId.toString()+dpnId.toString()+vrfEntry.getDestPrefix(),
827 new Callable<List<ListenableFuture<Void>>>() {
829 public List<ListenableFuture<Void>> call() throws Exception {
830 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
831 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
832 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
833 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), lfibinstructions , DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
834 makeTunnelTableEntry(dpnId, vrfEntry.getLabel(), groupId, tx);
836 List<ListenableFuture<Void>> futures = new ArrayList<>();
837 futures.add(tx.submit());
843 return BigInteger.ZERO;
846 private boolean isVpnPresentInDpn(String rd, BigInteger dpnId) {
847 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
848 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
849 if (dpnInVpn.isPresent()) {
855 private LabelRouteInfo getLabelRouteInfo(Long label) {
856 InstanceIdentifier<LabelRouteInfo>lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
857 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long)label)).build();
858 Optional<LabelRouteInfo> opResult = read(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid);
859 if (opResult.isPresent()) {
860 return opResult.get();
865 private boolean deleteLabelRouteInfo(LabelRouteInfo lri, String vpnInstanceName) {
866 LOG.debug("deleting LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
867 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
868 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long) lri.getLabel())).build();
872 List<String> vpnInstancesList = lri.getVpnInstanceList();
873 if (vpnInstancesList.contains(vpnInstanceName)) {
874 LOG.debug("vpninstance {} name is present", vpnInstanceName);
875 vpnInstancesList.remove(vpnInstanceName);
877 if (vpnInstancesList.size() == 0) {
878 LOG.debug("deleting LRI instance object for label {}", lri.getLabel());
879 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId);
882 LOG.debug("updating LRI instance object for label {}", lri.getLabel());
883 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri).setVpnInstanceList(vpnInstancesList);
884 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(), FibUtil.DEFAULT_CALLBACK);
889 private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/,
890 WriteTransaction tx) {
891 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
892 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
895 createTerminatingServiceActions(dpId, (int)label, actionsInfos, tx);
897 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully",
898 dpId, label, groupId);
901 public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos,
902 WriteTransaction tx) {
903 List<MatchInfo> mkMatches = new ArrayList<>();
905 LOG.debug("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
908 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
909 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
911 List<InstructionInfo> mkInstructions = new ArrayList<>();
912 mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
914 FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
915 getTableMissFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
916 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
918 FlowKey flowKey = new FlowKey( new FlowId(terminatingServiceTableFlowEntity.getFlowId()) );
920 FlowBuilder flowbld = terminatingServiceTableFlowEntity.getFlowBuilder();
922 Node nodeDpn = buildDpnNode(terminatingServiceTableFlowEntity.getDpnId());
923 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
924 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
925 .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId())).child(Flow.class,flowKey).build();
926 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flowbld.build(),true );
929 private void removeTunnelTableEntry(BigInteger dpId, long label, WriteTransaction tx) {
930 FlowEntity flowEntity;
931 LOG.debug("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
932 List<MatchInfo> mkMatches = new ArrayList<>();
934 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
935 flowEntity = MDSALUtil.buildFlowEntity(dpId,
936 NwConstants.INTERNAL_TUNNEL_TABLE,
937 getTableMissFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
938 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
939 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
940 Node nodeDpn = buildDpnNode(flowEntity.getDpnId());
941 FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getFlowId()));
942 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
943 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
944 .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build();
946 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
947 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully", dpId, label);
951 * Delete local FIB entry
957 public List<BigInteger> deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
958 List<BigInteger> returnLocalDpnId = new ArrayList<>();
959 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
960 String localNextHopIP = vrfEntry.getDestPrefix();
962 if (localNextHopInfo == null) {
963 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
964 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
965 if (extra_route != null) {
966 for (String nextHopIp : extra_route.getNexthopIpList()) {
967 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
968 if (nextHopIp != null) {
969 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp + "/32");
970 localNextHopIP = nextHopIp + "/32";
971 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
972 vpnId, rd, vrfEntry, true /*isExtraRoute*/);
973 if (!dpnId.equals(BigInteger.ZERO)) {
974 returnLocalDpnId.add(dpnId);
980 if (localNextHopInfo == null) {
981 /* Imported VRF entry */
982 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
983 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
984 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
985 VpnNexthopBuilder vpnNexthopBuilder = new VpnNexthopBuilder();
986 vpnNexthopBuilder.setDpnId(lri.getDpnId());
987 BigInteger dpnId = checkDeleteLocalFibEntry(vpnNexthopBuilder.build(), localNextHopIP,
988 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
989 if (!dpnId.equals(BigInteger.ZERO)) {
990 returnLocalDpnId.add(dpnId);
997 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
998 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
999 if (!dpnId.equals(BigInteger.ZERO)) {
1000 returnLocalDpnId.add(dpnId);
1004 return returnLocalDpnId;
1007 private BigInteger checkDeleteLocalFibEntry(VpnNexthop localNextHopInfo, final String localNextHopIP,
1008 final Long vpnId, final String rd,
1009 final VrfEntry vrfEntry, final boolean isExtraRoute) {
1010 if (localNextHopInfo != null) {
1011 final BigInteger dpnId = localNextHopInfo.getDpnId();;
1012 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1013 dataStoreCoordinator.enqueueJob("FIB"+vpnId.toString()+dpnId.toString()+vrfEntry.getDestPrefix(),
1014 new Callable<List<ListenableFuture<Void>>>() {
1016 public List<ListenableFuture<Void>> call() throws Exception {
1017 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1018 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null /* instructions */,
1019 NwConstants.DEL_FLOW, tx);
1020 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1021 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null /* instructions */,
1022 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1023 removeTunnelTableEntry(dpnId, vrfEntry.getLabel(), tx);
1025 List<ListenableFuture<Void>> futures = new ArrayList<>();
1026 futures.add(tx.submit());
1030 //TODO: verify below adjacency call need to be optimized (?)
1031 deleteLocalAdjacency(dpnId, vpnId, localNextHopIP);
1034 return BigInteger.ZERO;
1038 private InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) {
1039 return InstanceIdentifier.builder(PrefixToInterface.class)
1040 .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
1043 private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
1044 Optional<Prefixes> localNextHopInfoData =
1045 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
1046 return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
1049 private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
1050 return InstanceIdentifier.builder(VpnToExtraroute.class)
1051 .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class,
1052 new ExtrarouteKey(ipPrefix)).build();
1055 private Extraroute getVpnToExtraroute(String rd, String ipPrefix) {
1056 Optional<Extraroute> extraRouteInfo =
1057 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix));
1058 return extraRouteInfo.isPresent() ? extraRouteInfo.get() : null;
1062 private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
1064 Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
1065 new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
1066 RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
1067 if(!rpcResult.isSuccessful()) {
1068 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
1070 return rpcResult.getResult().getTunnelType();
1073 } catch (InterruptedException | ExecutionException e) {
1074 LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e);
1080 private void createRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, final VrfTablesKey vrfTableKey,
1081 final VrfEntry vrfEntry, WriteTransaction tx) {
1082 Boolean wrTxPresent = true;
1084 wrTxPresent = false;
1085 tx = dataBroker.newWriteOnlyTransaction();
1087 String rd = vrfTableKey.getRouteDistinguisher();
1088 LOG.debug( "createremotefibentry: adding route {} for rd {} with transaction {}",
1089 vrfEntry.getDestPrefix(), rd, tx);
1090 /********************************************/
1091 List<String> tunnelInterfaceList = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
1093 if (tunnelInterfaceList.isEmpty()) {
1094 LOG.error("Could not get interface for nexthop: {} in vpn {}",
1095 vrfEntry.getNextHopAddressList(), rd);
1096 LOG.warn("Failed to add Route: {} in vpn: {}",
1097 vrfEntry.getDestPrefix(), rd);
1101 for (String tunnelInterface : tunnelInterfaceList) {
1102 List<InstructionInfo> instructions = new ArrayList<>();
1103 List<ActionInfo> actionInfos = new ArrayList<>();
1104 Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
1105 if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
1106 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
1107 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[]{null}));
1108 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[]{Long.toString(vrfEntry.getLabel())}));
1110 int label = vrfEntry.getLabel().intValue();
1111 BigInteger tunnelId;
1112 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
1113 if (tunnel_type.equals(TunnelTypeVxlan.class)) {
1114 tunnelId = BigInteger.valueOf(label);
1116 tunnelId = BigInteger.valueOf(label);
1119 LOG.debug("adding set tunnel id action for label {}", label);
1120 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{tunnelId}));
1122 List<ActionInfo> egressActions = nextHopManager.getEgressActionsForInterface(tunnelInterface);
1123 if(egressActions.isEmpty()){
1124 LOG.error("Failed to retrieve egress action for prefix {} nextHop {} interface {}. Aborting remote FIB entry creation.", vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), tunnelInterface);
1127 actionInfos.addAll(egressActions);
1128 instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
1129 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
1134 LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
1137 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
1138 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
1139 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1140 if (dpnInVpn.isPresent()) {
1141 List<VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
1142 VpnInterfaces currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
1144 if (vpnInterfaces.remove(currVpnInterface)) {
1145 if (vpnInterfaces.isEmpty()) {
1146 LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
1147 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1148 cleanUpDpnForVpn(dpnId, vpnId, rd, null);
1150 LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
1151 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id.child(
1152 VpnInterfaces.class,
1153 new VpnInterfacesKey(intfName)));
1159 private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
1160 /* Get interface info from prefix to interface mapping;
1161 Use the interface info to get the corresponding vpn interface op DS entry,
1162 remove the adjacency corresponding to this fib entry.
1163 If adjacency removed is the last adjacency, clean up the following:
1164 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
1165 - prefix to interface entry
1166 - vpn interface op DS
1168 LOG.debug("Cleanup of prefix {} in VPN {}", vrfEntry.getDestPrefix(), vpnId);
1169 Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
1170 Extraroute extraRoute = null;
1171 if (prefixInfo == null) {
1172 extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1173 if(extraRoute != null) {
1174 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1175 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
1177 if (nextHopIp != null) {
1178 prefixInfo = getPrefixToInterface(vpnId, nextHopIp + "/32");
1179 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1183 if (prefixInfo == null) {
1184 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1185 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
1186 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1187 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
1188 prefixBuilder.setDpnId(lri.getDpnId());
1189 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
1190 prefixBuilder.setIpAddress(lri.getPrefix());
1191 prefixInfo = prefixBuilder.build();
1192 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
1193 vrfEntry.getLabel(), prefixInfo.getVpnInterfaceName(), lri.getDpnId());
1194 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1198 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1202 private void checkCleanUpOpDataForFib(final Prefixes prefixInfo, final Long vpnId, final String rd,
1203 final VrfEntry vrfEntry, final Extraroute extraRoute) {
1205 if (prefixInfo == null) {
1206 LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for prefix {}", vrfEntry.getDestPrefix());
1207 return; //Don't have any info for this prefix (shouldn't happen); need to return
1210 String ifName = prefixInfo.getVpnInterfaceName();
1211 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1212 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + ifName,
1213 new CleanupVpnInterfaceWorker(prefixInfo, vpnId, rd, vrfEntry, extraRoute));
1216 private class CleanupVpnInterfaceWorker implements Callable<List<ListenableFuture<Void>>> {
1217 Prefixes prefixInfo;
1221 Extraroute extraRoute;
1223 public CleanupVpnInterfaceWorker(final Prefixes prefixInfo, final Long vpnId, final String rd,
1224 final VrfEntry vrfEntry, final Extraroute extraRoute) {
1225 this.prefixInfo = prefixInfo;
1228 this.vrfEntry= vrfEntry;
1229 this.extraRoute = extraRoute;
1233 public List<ListenableFuture<Void>> call() throws Exception {
1234 // If another renderer(for eg : CSS) needs to be supported, check can be performed here
1235 // to call the respective helpers.
1236 String ifName = prefixInfo.getVpnInterfaceName();
1237 Optional<VpnInterface> optvpnInterface = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1238 FibUtil.getVpnInterfaceIdentifier(ifName));
1239 if (optvpnInterface.isPresent()) {
1240 long associatedVpnId = FibUtil.getVpnId(dataBroker, optvpnInterface.get().getVpnInstanceName());
1241 if (vpnId != associatedVpnId) {
1242 LOG.warn("Prefixes {} are associated with different vpn instance with id : {} rather than {}",
1243 vrfEntry.getDestPrefix(), associatedVpnId, vpnId);
1244 LOG.trace("Releasing prefix label - rd {}, prefix {}", rd, vrfEntry.getDestPrefix());
1245 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1246 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1247 LOG.warn("Not proceeding with Cleanup op data for prefix {}", vrfEntry.getDestPrefix());
1250 LOG.debug("Processing cleanup of prefix {} associated with vpn {}",
1251 vrfEntry.getDestPrefix(), associatedVpnId);
1254 if (extraRoute != null) {
1255 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1256 FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
1258 Optional<Adjacencies> optAdjacencies = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1259 FibUtil.getAdjListPath(ifName));
1261 if (optAdjacencies.isPresent()) {
1262 numAdj = optAdjacencies.get().getAdjacency().size();
1264 //remove adjacency corr to prefix
1266 LOG.info("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix());
1267 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1268 FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
1270 if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
1271 //clean up the vpn interface from DpnToVpn list
1272 LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
1273 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1274 FibUtil.getVpnInterfaceIdentifier(ifName));
1277 synchronized (vrfEntry.getLabel().toString().intern()) {
1278 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1279 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
1280 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1281 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
1282 String vpnInstanceName = "";
1283 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1284 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1286 boolean lriRemoved = deleteLabelRouteInfo(lri, vpnInstanceName);
1288 String parentRd = lri.getParentVpnRd();
1289 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1290 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1293 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1294 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1301 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1302 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1303 final String rd = vrfTableKey.getRouteDistinguisher();
1304 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1305 if (vpnInstance == null) {
1306 LOG.error("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1309 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1311 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1312 if (subnetRoute != null) {
1313 elanTag = subnetRoute.getElantag();
1314 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
1315 rd, vrfEntry.getDestPrefix(), elanTag);
1316 if (vpnToDpnList != null) {
1317 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1318 dataStoreCoordinator.enqueueJob("FIB" + rd.toString() + vrfEntry.getDestPrefix(),
1319 new Callable<List<ListenableFuture<Void>>>() {
1321 public List<ListenableFuture<Void>> call() throws Exception {
1322 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1324 for (final VpnToDpnList curDpn : vpnToDpnList) {
1326 makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry,
1327 vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW, tx);
1328 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1329 makeLFibTableEntry(curDpn.getDpnId(), vrfEntry.getLabel(), null,
1330 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1333 List<ListenableFuture<Void>> futures = new ArrayList<>();
1334 futures.add(tx.submit());
1339 synchronized (vrfEntry.getLabel().toString().intern()) {
1340 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1341 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) && vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1342 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
1343 String vpnInstanceName = "";
1344 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1345 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1347 boolean lriRemoved = this.deleteLabelRouteInfo(lri, vpnInstanceName);
1349 String parentRd = lri.getParentVpnRd();
1350 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1351 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1352 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {} as labelRouteInfo cleared", vrfEntry.getLabel(), rd,
1353 vrfEntry.getDestPrefix());
1356 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1357 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1358 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd,
1359 vrfEntry.getDestPrefix());
1365 final List<BigInteger> localDpnIdList = deleteLocalFibEntry(vpnInstance.getVpnId(),
1366 vrfTableKey.getRouteDistinguisher(), vrfEntry);
1367 if (vpnToDpnList != null) {
1368 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1369 dataStoreCoordinator.enqueueJob("FIB" + rd.toString() + vrfEntry.getDestPrefix(),
1370 new Callable<List<ListenableFuture<Void>>>() {
1372 public List<ListenableFuture<Void>> call() throws Exception {
1373 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1375 if (localDpnIdList.size() <= 0) {
1376 for (VpnToDpnList curDpn : vpnToDpnList) {
1377 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1378 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1379 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1382 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1386 for (BigInteger localDpnId : localDpnIdList) {
1387 for (VpnToDpnList curDpn : vpnToDpnList) {
1388 if (!curDpn.getDpnId().equals(localDpnId)) {
1389 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1390 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1391 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1394 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1400 List<ListenableFuture<Void>> futures = new ArrayList<>();
1401 futures.add(tx.submit());
1407 //The flow/group entry has been deleted from config DS; need to clean up associated operational
1408 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
1409 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
1411 // Remove all fib entries configured due to interVpnLink, when nexthop is the opposite endPoint
1412 // of the interVpnLink.
1413 Optional<String> vpnUuid = FibUtil.getVpnNameFromRd(dataBroker, rd);
1414 if ( vpnUuid.isPresent() ) {
1415 Optional<InterVpnLink> interVpnLink = FibUtil.getInterVpnLinkByVpnUuid(dataBroker, vpnUuid.get());
1416 String routeNexthop = vrfEntry.getNextHopAddressList().get(0);
1418 if ( interVpnLink.isPresent()
1419 && ( (interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid.get())
1420 && interVpnLink.get().getSecondEndpoint().getIpAddress().getValue().equals(routeNexthop))
1421 || (interVpnLink.get().getSecondEndpoint().getVpnUuid().getValue().equals(vpnUuid.get() )
1422 && interVpnLink.get().getFirstEndpoint().getIpAddress().getValue().equals(routeNexthop)) ) ) {
1423 // This is route that points to the other endpoint of an InterVpnLink
1424 // In that case, we should look for the FIB table pointing to LPortDispatcher table and remove it.
1425 removeRouteFromInterVpnLink(interVpnLink.get(), rd, vrfEntry);
1432 Please note that the following deleteFibEntries will be invoked only for BGP Imported Routes.
1433 The invocation of the following method is via delete() callback from the MDSAL Batching Infrastructure
1434 provided by ResourceBatchingManager
1436 private void deleteFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1437 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1439 final String rd = vrfTableKey.getRouteDistinguisher();
1440 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1441 if (vpnInstance == null) {
1442 LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1445 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1446 if (vpnToDpnList != null) {
1447 for (VpnToDpnList curDpn : vpnToDpnList) {
1448 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1449 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, writeTx);
1455 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
1456 final long vpnId, final VrfTablesKey vrfTableKey,
1457 final VrfEntry vrfEntry, WriteTransaction tx) {
1459 Boolean wrTxPresent = true;
1461 wrTxPresent = false;
1462 tx = dataBroker.newWriteOnlyTransaction();
1465 LOG.debug("deleting route: prefix={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
1466 String rd = vrfTableKey.getRouteDistinguisher();
1468 if(localDpnId != null) {
1469 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
1470 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1474 // below two reads are kept as is, until best way is found to identify dpnID
1475 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
1476 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1478 if (localNextHopInfo == null && extraRoute != null) {
1479 // Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
1480 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1481 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp);
1482 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1485 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1492 private boolean checkDpnDeleteFibEntry(VpnNexthop localNextHopInfo, BigInteger remoteDpnId, long vpnId,
1493 VrfEntry vrfEntry, String rd, WriteTransaction tx){
1494 boolean isRemoteRoute = true;
1495 if (localNextHopInfo != null) {
1496 isRemoteRoute = (!remoteDpnId.equals(localNextHopInfo.getDpnId()));
1498 if (isRemoteRoute) {
1499 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1502 LOG.debug("Did not delete FIB entry: rd={}, vrfEntry={}, as it is local to dpnId={}", rd, vrfEntry.getDestPrefix(), remoteDpnId);
1507 private void deleteFibEntry(BigInteger remoteDpnId, long vpnId, VrfEntry vrfEntry, String rd, WriteTransaction tx){
1508 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1509 LOG.debug("Successfully delete FIB entry: vrfEntry={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
1513 (byte[] rawIpAddress) {
1514 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
1515 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
1518 private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
1519 List<InstructionInfo> instructions, int addOrRemove, WriteTransaction tx) {
1520 Boolean wrTxPresent = true;
1522 wrTxPresent = false;
1523 tx = dataBroker.newWriteOnlyTransaction();
1526 LOG.trace("makeConnectedRoute: vrfEntry {}", vrfEntry);
1527 String values[] = vrfEntry.getDestPrefix().split("/");
1528 String ipAddress = values[0];
1529 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
1530 if (addOrRemove == NwConstants.ADD_FLOW) {
1531 LOG.debug("Adding route to DPN {} for rd {} prefix {} ", dpId, rd, vrfEntry.getDestPrefix());
1533 LOG.debug("Removing route from DPN {} for rd {} prefix {}", dpId, rd, vrfEntry.getDestPrefix());
1535 InetAddress destPrefix;
1537 destPrefix = InetAddress.getByName(ipAddress);
1538 } catch (UnknownHostException e) {
1539 LOG.error("Failed to get destPrefix for prefix {} ", vrfEntry.getDestPrefix(), e);
1543 List<MatchInfo> matches = new ArrayList<>();
1545 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
1546 MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
1548 matches.add(new MatchInfo(MatchFieldType.eth_type,
1549 new long[] { NwConstants.ETHTYPE_IPV4 }));
1551 if(prefixLength != 0) {
1552 matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
1553 destPrefix.getHostAddress(), Integer.toString(prefixLength)}));
1555 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
1556 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, priority, destPrefix);
1557 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
1558 COOKIE_VM_FIB_TABLE, matches, instructions);
1560 Flow flow = flowEntity.getFlowBuilder().build();
1561 String flowId = flowEntity.getFlowId();
1562 FlowKey flowKey = new FlowKey( new FlowId(flowId));
1563 Node nodeDpn = buildDpnNode(dpId);
1565 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1566 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1567 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1568 if (addOrRemove == NwConstants.ADD_FLOW) {
1569 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true);
1571 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1579 //TODO: How to handle the below code, its a copy paste from MDSALManager.java
1580 private Node buildDpnNode(BigInteger dpnId) {
1581 NodeId nodeId = new NodeId("openflow:" + dpnId);
1582 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
1587 private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions, int priority,
1588 int addOrRemove, WriteTransaction tx) {
1589 Boolean wrTxPresent = true;
1591 wrTxPresent = false;
1592 tx = dataBroker.newWriteOnlyTransaction();
1595 List<MatchInfo> matches = new ArrayList<MatchInfo>();
1596 matches.add(new MatchInfo(MatchFieldType.eth_type,
1597 new long[] { NwConstants.ETHTYPE_MPLS_UC }));
1598 matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
1600 // Install the flow entry in L3_LFIB_TABLE
1601 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, priority);
1603 FlowEntity flowEntity;
1604 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef, priority, flowRef, 0, 0,
1605 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
1606 Flow flow = flowEntity.getFlowBuilder().build();
1607 String flowId = flowEntity.getFlowId();
1608 FlowKey flowKey = new FlowKey( new FlowId(flowId));
1609 Node nodeDpn = buildDpnNode(dpId);
1610 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1611 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1612 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1614 if (addOrRemove == NwConstants.ADD_FLOW) {
1615 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true);
1617 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1622 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} modified successfully {}",
1623 dpId, label, instructions );
1626 private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
1627 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
1629 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
1630 } catch (NullPointerException e) {
1635 public void populateFibOnNewDpn(final BigInteger dpnId, final long vpnId, final String rd,
1636 final FutureCallback<List<Void>> callback) {
1637 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
1638 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1639 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1640 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1641 if (vrfTable.isPresent()) {
1642 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1643 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1644 new Callable<List<ListenableFuture<Void>>>() {
1646 public List<ListenableFuture<Void>> call() throws Exception {
1647 List<ListenableFuture<Void>> futures = new ArrayList<>();
1648 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1649 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1650 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1652 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1653 if (subnetRoute != null) {
1654 long elanTag = subnetRoute.getElantag();
1655 installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
1658 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
1659 //Handle local flow creation for imports
1660 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1661 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()
1662 ) && vrfEntry.getNextHopAddressList()
1663 .contains(lri.getNextHopIpList().get(0))) {
1664 if (lri.getDpnId().equals(dpnId)) {
1665 createLocalFibEntry(vpnId, rd, vrfEntry);
1670 // Passing null as we don't know the dpn
1671 // to which prefix is attached at this point
1672 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1674 //TODO: if we have 100K entries in FIB, can it fit in one Tranasaction (?)
1675 futures.add(tx.submit());
1676 if (callback != null) {
1677 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1678 Futures.addCallback(listenableFuture, callback);
1687 public void populateFibOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1688 final String localNextHopIp, final String remoteNextHopIp) {
1689 LOG.trace("dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} : populateFibOnDpn",
1690 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1691 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1692 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1693 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1694 if (vrfTable.isPresent()) {
1695 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1696 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1697 new Callable<List<ListenableFuture<Void>>>() {
1699 public List<ListenableFuture<Void>> call() throws Exception {
1700 List<ListenableFuture<Void>> futures = new ArrayList<>();
1701 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1702 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1703 LOG.trace("populate FIB starts on Dpn " + dpnId
1704 + "rd " + rd.toString()
1705 + "localNextHopIp " + localNextHopIp
1706 + "remoteNextHopIp" + remoteNextHopIp
1707 + "vpnId " + vpnId );
1708 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1709 LOG.trace("old vrfEntry before populate:: {}", vrfEntry);
1711 if (vrfEntry.getOrigin().equals(RouteOrigin.BGP.getValue())) {
1712 if (remoteNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1713 LOG.trace(" creating remote FIB entry for vfEntry {}", vrfEntry);
1714 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeTransaction);
1716 } else if (vrfEntry.getOrigin().equals(RouteOrigin.STATIC.getValue())) {
1717 BigInteger dpnIdForPrefix = null;
1718 String destPfx = vrfEntry.getDestPrefix();
1719 if (vrfEntry.getAugmentation(SubnetRoute.class) == null) {
1720 Optional<Extraroute> extraRouteInfo =
1721 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1722 getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
1723 if (extraRouteInfo.isPresent()) {
1726 dpnIdForPrefix = nextHopManager.getDpnForPrefix(vpnId, destPfx);
1728 // Subnet Route handling
1729 Optional<Prefixes> localNextHopInfoData =
1730 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1731 FibUtil.getPrefixToInterfaceIdentifier(vpnId, destPfx));
1732 if (localNextHopInfoData.isPresent()) {
1733 Prefixes prefixes = localNextHopInfoData.get();
1734 dpnIdForPrefix = prefixes.getDpnId();
1737 if (dpnIdForPrefix == null) {
1738 LOG.trace("Populate::the dpnIdForPrefix is null for prefix {}.",
1739 vrfEntry.getDestPrefix());
1742 int sameDpnId = dpnIdForPrefix.compareTo(dpnId);
1743 if (sameDpnId != 0) {
1744 LOG.trace("Populate::Different srcDpnId {} and dpnIdForPrefix {} for prefix {}",
1745 dpnId, dpnIdForPrefix, vrfEntry.getDestPrefix());
1748 InstanceIdentifier<VrfEntry> vrfEntryId = getVrfEntryId(rd, vrfEntry.getDestPrefix());
1749 List<String> newNextHopAddrList = vrfEntry.getNextHopAddressList();
1750 newNextHopAddrList.add(localNextHopIp);
1751 VrfEntry newVrfEntry =
1752 new VrfEntryBuilder(vrfEntry).setNextHopAddressList(newNextHopAddrList).build();
1753 // Just update the VrfEntry
1754 FibUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
1755 vrfEntryId, newVrfEntry);
1756 // writeTransaction.put(LogicalDatastoreType.CONFIGURATION,
1757 // vrfEntryId, newVrfEntry);
1758 vrfEntry = getVrfEntry(dataBroker, rd, destPfx);
1759 LOG.trace("updated vrfEntry after populate:: {}", vrfEntry);
1762 futures.add(writeTransaction.submit());
1763 LOG.trace("populate FIB ends on Dpn " + dpnId
1764 + "rd " + rd.toString()
1765 + "localNextHopIp " + localNextHopIp
1766 + "remoteNextHopIp" + remoteNextHopIp
1767 + "vpnId " + vpnId);
1775 public void handleRemoteRoute(final boolean action, final BigInteger localDpnId, final BigInteger remoteDpnId,
1776 final long vpnId, final String rd, final String destPrefix ,
1777 final String localNextHopIP, final String remoteNextHopIp) {
1779 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1780 dataStoreCoordinator.enqueueJob( "FIB" + rd.toString()
1781 + "local dpid" + localDpnId
1782 + "remote dpid" + remoteDpnId
1784 + "localNHIp" + localNextHopIP
1785 + "remoteNHIp" + remoteNextHopIp,
1786 new Callable<List<ListenableFuture<Void>>>() {
1788 public List<ListenableFuture<Void>> call() throws Exception {
1789 List<ListenableFuture<Void>> futures = new ArrayList<>();
1790 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1791 VrfTablesKey vrfTablesKey = new VrfTablesKey(rd);
1792 VrfEntry vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1793 if (vrfEntry == null)
1795 LOG.trace("handleRemoteRoute :: action {}, localDpnId {}, " +
1796 "remoteDpnId {} , vpnId {}, rd {}, destPfx {}",
1797 action, localDpnId, remoteDpnId, vpnId, rd, destPrefix);
1798 if (action == true) {
1799 vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1800 LOG.trace("handleRemoteRoute updated(add) vrfEntry :: {}", vrfEntry);
1801 createRemoteFibEntry(remoteDpnId, vpnId, vrfTablesKey, vrfEntry, writeTransaction);
1803 vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1804 LOG.trace("handleRemoteRoute updated(remove) vrfEntry :: {}", vrfEntry);
1805 deleteRemoteRoute(null, remoteDpnId, vpnId, vrfTablesKey, vrfEntry, writeTransaction);
1807 futures.add(writeTransaction.submit());
1813 public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd,
1814 final FutureCallback<List<Void>> callback) {
1815 LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
1816 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1817 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1818 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1819 if (vrfTable.isPresent()) {
1820 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1821 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1822 new Callable<List<ListenableFuture<Void>>>() {
1824 public List<ListenableFuture<Void>> call() throws Exception {
1825 List<ListenableFuture<Void>> futures = new ArrayList<>();
1826 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1827 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1828 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1829 /* Handle subnet routes here */
1830 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1831 if (subnetRoute != null) {
1832 LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(),
1834 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1835 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1836 LOG.trace("cleanUpDpnForVpn: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd,
1837 vrfEntry.getDestPrefix());
1840 // Passing null as we don't know the dpn
1841 // to which prefix is attached at this point
1842 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1844 futures.add(tx.submit());
1845 if (callback != null) {
1846 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1847 Futures.addCallback(listenableFuture, callback);
1857 public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd,
1858 final String localNextHopIp, final String remoteNextHopIp,
1859 final FutureCallback<List<Void>> callback) {
1860 LOG.trace( " cleanup remote routes on dpn {} for vpn {}, rd {}, " +
1861 " localNexthopIp {} , remoteNexhtHopIp {} : cleanUpDpnForVpn",
1862 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1863 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1864 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1865 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1866 if (vrfTable.isPresent()) {
1867 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1868 dataStoreCoordinator.enqueueJob(" FIB-" + vpnId + "-" + dpnId.toString(),
1869 new Callable<List<ListenableFuture<Void>>>() {
1871 public List<ListenableFuture<Void>> call() throws Exception {
1872 List<ListenableFuture<Void>> futures = new ArrayList<>();
1873 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1874 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1875 LOG.trace("cleanup FIB starts on Dpn " + dpnId
1876 + "rd " + rd.toString()
1877 + "localNextHopIp " + localNextHopIp
1878 + "remoteNextHopIp" + remoteNextHopIp
1879 + "vpnId " + vpnId);
1881 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1882 LOG.trace("old vrfEntry before cleanup:: {}", vrfEntry);
1883 if (remoteNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1884 LOG.trace(" deleting remote FIB entry {}", vrfEntry);
1885 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeTransaction);
1888 if (localNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1889 LOG.trace("changing the nexthopip for local VM routes {} on dpn {}",
1890 vrfEntry.getDestPrefix(), dpnId);
1891 String destPfx = vrfEntry.getDestPrefix();
1892 InstanceIdentifier<VrfEntry> vrfEntryId = getVrfEntryId(rd, destPfx);
1893 List<java.lang.String> newList = vrfEntry.getNextHopAddressList();
1894 newList.remove(localNextHopIp);
1895 VrfEntry newVrfEntry =
1896 new VrfEntryBuilder(vrfEntry).setNextHopAddressList(newList).build();
1897 FibUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
1898 vrfEntryId, newVrfEntry);
1899 vrfEntry = getVrfEntry(dataBroker, rd, destPfx);
1900 LOG.trace("updated vrfEntry after cleanup:: {}", vrfEntry);
1903 futures.add(writeTransaction.submit());
1904 if (callback != null) {
1905 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1906 Futures.addCallback(listenableFuture, callback);
1908 LOG.trace("cleanup FIB ends on Dpn " + dpnId
1909 + "rd " + rd.toString()
1910 + "localNextHopIp " + localNextHopIp
1911 + "remoteNextHopIp" + remoteNextHopIp
1912 + "vpnId " + vpnId);
1921 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
1922 InstanceIdentifierBuilder<VrfTables> idBuilder =
1923 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1924 InstanceIdentifier<VrfTables> id = idBuilder.build();
1928 private String getFlowRef(BigInteger dpnId, short tableId, long label, int priority) {
1929 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
1930 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(label).append(NwConstants.FLOWID_SEPARATOR)
1931 .append(priority).toString();
1934 private String getFlowRef(BigInteger dpnId, short tableId, String rd, int priority, InetAddress destPrefix) {
1935 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
1936 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
1937 .append(rd).append(NwConstants.FLOWID_SEPARATOR)
1938 .append(priority).append(NwConstants.FLOWID_SEPARATOR)
1939 .append(destPrefix.getHostAddress()).toString();
1942 private String getInterVpnFibFlowRef(String interVpnLinkName, String prefix, String nextHop ) {
1943 return new StringBuilder(64).append(FLOWID_PREFIX)
1944 .append(interVpnLinkName).append(NwConstants.FLOWID_SEPARATOR)
1945 .append(prefix).append(NwConstants.FLOWID_SEPARATOR)
1946 .append(nextHop).toString();
1949 protected List<String> resolveAdjacency(final BigInteger remoteDpnId, final long vpnId,
1950 final VrfEntry vrfEntry, String rd) {
1951 List<String> adjacencyList = new ArrayList<>();
1952 List<String> prefixIpList = new ArrayList<>();
1953 LOG.trace("resolveAdjacency called with remotedpid {}, vpnId{}, VrfEntry {}",
1954 remoteDpnId, vpnId, vrfEntry);
1956 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
1957 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1958 if (extra_route == null) {
1959 prefixIpList = Arrays.asList(vrfEntry.getDestPrefix());
1961 prefixIpList = new ArrayList<>();
1962 for (String extraRouteIp : extra_route.getNexthopIpList()) {
1963 prefixIpList.add(extraRouteIp + "/32");
1967 prefixIpList = Arrays.asList(vrfEntry.getDestPrefix());
1970 for (String prefixIp : prefixIpList) {
1971 for (String nextHopIp : vrfEntry.getNextHopAddressList()) {
1972 LOG.debug("NextHop IP for destination {} is {}", prefixIp, nextHopIp);
1973 String adjacency = nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId,
1974 prefixIp, nextHopIp);
1975 if (adjacency != null && !adjacency.isEmpty() && !adjacencyList.contains(adjacency)) {
1976 adjacencyList.add(adjacency);
1980 } catch (NullPointerException e) {
1983 return adjacencyList;
1986 protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
1987 InstanceIdentifier<VpnInstanceOpDataEntry> id =
1988 InstanceIdentifier.create(VpnInstanceOpData.class)
1989 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
1990 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData =
1991 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1992 return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null;
1995 public void processNodeAdd(BigInteger dpnId) {
1996 LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
1997 makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
1998 makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
1999 makeSubnetRouteTableMissFlow(dpnId, NwConstants.ADD_FLOW);
2002 private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
2003 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
2004 // Instruction to goto L3 InterfaceTable
2005 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
2006 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE }));
2007 List<MatchInfo> matches = new ArrayList<MatchInfo>();
2008 FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE,
2009 getTableMissFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW),
2010 NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
2012 FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE,
2013 getTableMissFlowRef(dpnId, NwConstants.L3_FIB_TABLE,
2014 NwConstants.TABLE_MISS_FLOW),
2015 NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow",
2016 0, 0, COOKIE_VM_FIB_TABLE,
2017 matches, instructions);
2019 if (addOrRemove == NwConstants.ADD_FLOW) {
2020 LOG.debug("Invoking MDSAL to install Table Miss Entries");
2021 mdsalManager.installFlow(flowEntityLfib);
2022 mdsalManager.installFlow(flowEntityFib);
2024 mdsalManager.removeFlow(flowEntityLfib);
2025 mdsalManager.removeFlow(flowEntityFib);
2030 private String getTableMissFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
2031 return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
2032 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
2033 .append(FLOWID_PREFIX).toString();
2037 * Install flow entry in protocol table to forward mpls
2038 * coming through gre tunnel to LFIB table.
2040 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
2041 final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
2042 // Instruction to goto L3 InterfaceTable
2043 List<InstructionInfo> instructions = new ArrayList<>();
2044 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
2045 List<MatchInfo> matches = new ArrayList<MatchInfo>();
2046 matches.add(new MatchInfo(MatchFieldType.eth_type,
2047 new long[] { NwConstants.ETHTYPE_MPLS_UC }));
2048 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2049 getTableMissFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2050 NwConstants.L3_LFIB_TABLE),
2051 DEFAULT_FIB_FLOW_PRIORITY,
2052 "Protocol Table For LFIB",
2054 COOKIE_PROTOCOL_TABLE,
2055 matches, instructions);
2057 if (addOrRemove == NwConstants.ADD_FLOW) {
2058 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
2059 mdsalManager.installFlow(flowEntityToLfib);
2061 mdsalManager.removeFlow(flowEntityToLfib);
2065 public List<String> printFibEntries() {
2066 List<String> result = new ArrayList<String>();
2067 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s", "RD", "Prefix", "NextHop", "Label", "Origin"));
2068 result.add("-------------------------------------------------------------------");
2069 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
2070 Optional<FibEntries> fibEntries = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2071 if (fibEntries.isPresent()) {
2072 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
2073 for (VrfTables vrfTable : vrfTables) {
2074 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
2075 for (String nextHop : vrfEntry.getNextHopAddressList()) {
2076 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s",
2077 vrfTable.getRouteDistinguisher(),
2078 vrfEntry.getDestPrefix(), nextHop, vrfEntry.getLabel(), vrfEntry.getOrigin()));
2080 if (vrfEntry.getNextHopAddressList().isEmpty()) {
2081 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s",
2082 vrfTable.getRouteDistinguisher(),
2083 vrfEntry.getDestPrefix(), "local", vrfEntry.getLabel(), vrfEntry.getOrigin()));
2091 private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) {
2092 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
2093 List<MatchInfo> matches = new ArrayList<MatchInfo>();
2094 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
2095 // Instruction to goto L3 InterfaceTable
2097 List <ActionInfo> actionsInfos = new ArrayList <ActionInfo> ();
2098 actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{
2099 Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)}));
2100 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
2101 //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE }));
2103 FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE,
2104 getTableMissFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW),
2105 NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS,
2106 matches, instructions);
2107 if (addOrRemove == NwConstants.ADD_FLOW) {
2108 LOG.debug("Invoking MDSAL to install L3 interface Table Miss Entries");
2109 mdsalManager.installFlow(flowEntityL3Intf);
2111 mdsalManager.removeFlow(flowEntityL3Intf);
2115 private VrfEntry getVrfEntry(DataBroker broker, String rd, String ipPrefix) {
2116 InstanceIdentifier<VrfEntry> vrfEntryId =
2117 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).
2118 child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2119 Optional<VrfEntry> vrfEntry = read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
2120 if (vrfEntry.isPresent()) {
2121 return (vrfEntry.get());
2126 private InstanceIdentifier<VrfEntry> getVrfEntryId(String rd, String ipPrefix) {
2127 InstanceIdentifier<VrfEntry> vrfEntryId =
2128 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).
2129 child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();