2 * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netvirt.fibmanager;
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
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;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
31 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
34 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
35 import org.opendaylight.genius.mdsalutil.ActionInfo;
36 import org.opendaylight.genius.mdsalutil.ActionType;
37 import org.opendaylight.genius.mdsalutil.FlowEntity;
38 import org.opendaylight.genius.mdsalutil.InstructionInfo;
39 import org.opendaylight.genius.mdsalutil.InstructionType;
40 import org.opendaylight.genius.mdsalutil.MDSALUtil;
41 import org.opendaylight.genius.mdsalutil.MatchFieldType;
42 import org.opendaylight.genius.mdsalutil.MatchInfo;
43 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
44 import org.opendaylight.genius.mdsalutil.NwConstants;
45 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
46 import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
47 import org.opendaylight.genius.utils.ServiceIndex;
48 import org.opendaylight.genius.utils.batching.ActionableResource;
49 import org.opendaylight.genius.utils.batching.ActionableResourceImpl;
50 import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
51 import org.opendaylight.genius.utils.batching.ResourceHandler;
52 import org.opendaylight.genius.utils.batching.SubTransaction;
53 import org.opendaylight.genius.utils.batching.SubTransactionImpl;
54 import org.opendaylight.netvirt.elanmanager.api.IElanService;
55 import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
56 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
57 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
58 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
59 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
60 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
61 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetTunnelTypeInputBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetTunnelTypeOutput;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthopBuilder;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroute;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIds;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIdsKey;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesBuilder;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder;
111 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;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.VpnKey;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState.State;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
120 import org.opendaylight.yangtools.yang.binding.DataObject;
121 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
122 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
123 import org.opendaylight.yangtools.yang.common.RpcResult;
124 import org.slf4j.Logger;
125 import org.slf4j.LoggerFactory;
127 public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry, VrfEntryListener> implements AutoCloseable, ResourceHandler {
128 private static final Logger LOG = LoggerFactory.getLogger(VrfEntryListener.class);
129 private static final String FLOWID_PREFIX = "L3.";
130 private final DataBroker dataBroker;
131 private final IMdsalApiManager mdsalManager;
132 private IVpnManager vpnmanager;
133 private final NexthopManager nextHopManager;
134 private ItmRpcService itmManager;
135 private final OdlInterfaceRpcService interfaceManager;
136 private final IdManagerService idManager;
137 private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16);
138 private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
139 private static final int LFIB_INTERVPN_PRIORITY = 1;
140 private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16);
141 private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0);
142 public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
143 List<SubTransaction> transactionObjects;
144 private static final int PERIODICITY = 500;
145 private static Integer batchSize;
146 private static Integer batchInterval;
147 private static final int BATCH_SIZE = 1000;
148 private static BlockingQueue<ActionableResource> vrfEntryBufferQ = new LinkedBlockingQueue<>();
149 private final ResourceBatchingManager resourceBatchingManager;
151 public VrfEntryListener(final DataBroker dataBroker, final IMdsalApiManager mdsalApiManager,
152 final NexthopManager nexthopManager, final OdlInterfaceRpcService interfaceManager,
153 final IdManagerService idManager) {
154 super(VrfEntry.class, VrfEntryListener.class);
155 this.dataBroker = dataBroker;
156 this.mdsalManager = mdsalApiManager;
157 this.nextHopManager = nexthopManager;
158 this.interfaceManager = interfaceManager;
159 this.idManager = idManager;
161 batchSize = Integer.getInteger("batch.size");
162 if (batchSize == null) {
163 batchSize = BATCH_SIZE;
165 batchInterval = Integer.getInteger("batch.wait.time");
166 if (batchInterval == null) {
167 batchInterval = PERIODICITY;
169 resourceBatchingManager = ResourceBatchingManager.getInstance();
170 resourceBatchingManager.registerBatchableResource("FIB-VRFENTRY",vrfEntryBufferQ, this);
171 transactionObjects = new ArrayList<>();
174 public void start() {
175 LOG.info("{} start", getClass().getSimpleName());
176 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
180 protected VrfEntryListener getDataTreeChangeListener() { return VrfEntryListener.this; }
183 protected InstanceIdentifier<VrfEntry> getWildCardPath() {
184 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
188 public DataBroker getResourceBroker() {
193 protected void add(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
194 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
195 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
196 LOG.debug("ADD: Adding Fib Entry rd {} prefix {} nexthop {} label {}",
197 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
198 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
199 createFibEntries(identifier, vrfEntry);
201 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + vrfEntry.getDestPrefix());
202 actResource.setAction(ActionableResource.CREATE);
203 actResource.setInstanceIdentifier(identifier);
204 actResource.setInstance(vrfEntry);
205 vrfEntryBufferQ.add(actResource);
206 leakRouteIfNeeded(identifier, vrfEntry, NwConstants.ADD_FLOW);
208 LOG.debug("ADD: Added Fib Entry rd {} prefix {} nexthop {} label {}",
209 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
213 protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
214 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
215 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
216 LOG.debug("REMOVE: Removing Fib Entry rd {} prefix {} nexthop {} label {}",
217 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
218 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
219 deleteFibEntries(identifier, vrfEntry);
221 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + vrfEntry.getDestPrefix());
222 actResource.setAction(ActionableResource.DELETE);
223 actResource.setInstanceIdentifier(identifier);
224 actResource.setInstance(vrfEntry);
225 vrfEntryBufferQ.add(actResource);
226 leakRouteIfNeeded(identifier, vrfEntry, NwConstants.DEL_FLOW);
228 LOG.debug("REMOVE: Removed Fib Entry rd {} prefix {} nexthop {} label {}",
229 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
233 protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
234 Preconditions.checkNotNull(update, "VrfEntry should not be null or empty.");
235 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
236 LOG.debug("UPDATE: Updating Fib Entries to rd {} prefix {} nexthop {} label {}",
237 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
238 if (RouteOrigin.value(update.getOrigin()) != RouteOrigin.BGP) {
239 createFibEntries(identifier, update);
241 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + update.getDestPrefix());
242 actResource.setAction(ActionableResource.UPDATE);
243 actResource.setInstanceIdentifier(identifier);
244 actResource.setInstance(update);
245 actResource.setOldInstance(original);
246 vrfEntryBufferQ.add(actResource);
248 LOG.debug("UPDATE: Updated Fib Entries to rd {} prefix {} nexthop {} label {}",
249 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
253 public void create(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object vrfEntry, List<SubTransaction> transactionObjects) {
254 this.transactionObjects = transactionObjects;
255 if (vrfEntry instanceof VrfEntry) {
256 createFibEntries(tx, identifier, (VrfEntry)vrfEntry);
261 public void delete(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object vrfEntry, List<SubTransaction> transactionObjects) {
262 this.transactionObjects = transactionObjects;
263 if (vrfEntry instanceof VrfEntry) {
264 deleteFibEntries(tx, identifier, (VrfEntry) vrfEntry);
269 public void update(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object original,
270 Object update, List<SubTransaction> transactionObjects) {
271 this.transactionObjects = transactionObjects;
272 if ((original instanceof VrfEntry) && (update instanceof VrfEntry)) {
273 createFibEntries(tx, identifier, (VrfEntry)update);
278 public int getBatchSize() {
283 public int getBatchInterval() {
284 return batchInterval;
288 public LogicalDatastoreType getDatastoreType() {
289 return LogicalDatastoreType.CONFIGURATION;
292 private void createFibEntries(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
293 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
295 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
296 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
297 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
299 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
300 final Long vpnId = vpnInstance.getVpnId();
301 final String rd = vrfTableKey.getRouteDistinguisher();
302 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
303 if (subnetRoute != null) {
304 final long elanTag = subnetRoute.getElantag();
305 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
306 rd, vrfEntry.getDestPrefix(), elanTag);
307 if (vpnToDpnList != null) {
308 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
309 dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(),
310 new Callable<List<ListenableFuture<Void>>>() {
312 public List<ListenableFuture<Void>> call() throws Exception {
313 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
314 for (final VpnToDpnList curDpn : vpnToDpnList) {
315 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
316 installSubnetRouteInFib(curDpn.getDpnId(), elanTag, rd, vpnId.longValue(), vrfEntry, tx);
319 List<ListenableFuture<Void>> futures = new ArrayList<>();
320 futures.add(tx.submit());
327 // ping responder for router interfaces
328 if (installRouterFibEntries(vrfEntry, vpnToDpnList, vpnId, NwConstants.ADD_FLOW)) {
332 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.INTERVPN) {
333 // When it is a leaked route, the LFIB and FIB goes a bit different.
334 installInterVpnRouteInLFib(rd, vrfEntry);
338 final List<BigInteger> localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry);
340 if (vpnToDpnList != null) {
341 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
342 dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(),
343 new Callable<List<ListenableFuture<Void>>>() {
345 public List<ListenableFuture<Void>> call() throws Exception {
346 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
347 for (VpnToDpnList vpnDpn : vpnToDpnList) {
348 if ( !localDpnIdList.contains(vpnDpn.getDpnId())) {
349 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
350 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
354 List<ListenableFuture<Void>> futures = new ArrayList<>();
355 futures.add(tx.submit());
361 Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(dataBroker, rd);
362 if ( optVpnUuid.isPresent() ) {
363 Optional<InterVpnLinkDataComposite> optInterVpnLink = InterVpnLinkCache.getInterVpnLinkByVpnId(optVpnUuid.get());
364 LOG.debug("InterVpnLink {} found in Cache: {}", optVpnUuid.get(), optInterVpnLink.isPresent());
365 if ( optInterVpnLink.isPresent() ) {
366 InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
367 String vpnUuid = optVpnUuid.get();
368 String routeNexthop = vrfEntry.getNextHopAddressList().get(0);
369 if ( interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid) ) {
370 // This is an static route that points to the other endpoint of an InterVpnLink
371 // In that case, we should add another entry in FIB table pointing to LPortDispatcher table.
372 installRouteInInterVpnLink(interVpnLink, vpnUuid, vrfEntry, vpnId);
373 installInterVpnRouteInLFib(rd, vrfEntry);
381 Please note that the following createFibEntries will be invoked only for BGP Imported Routes.
382 The invocation of the following method is via create() callback from the MDSAL Batching Infrastructure
383 provided by ResourceBatchingManager
385 private void createFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
386 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
388 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
389 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
390 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
392 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
393 final String rd = vrfTableKey.getRouteDistinguisher();
394 if (vpnToDpnList != null) {
395 for (VpnToDpnList vpnDpn : vpnToDpnList) {
396 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
397 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, writeTx);
403 // FIXME: Refactoring needed here.
404 // This kind of logic must be taken to an 'upper' layer like BgpManager or VpnManager
405 private void leakRouteIfNeeded(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry,
407 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
408 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
410 String rd = vrfTableKey.getRouteDistinguisher();
411 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
412 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
413 if (vpnInstance == null) {
414 LOG.error("Vpn Instance not available for external route with prefix {} label {} nexthop {}. Returning...", vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList());
418 Preconditions.checkNotNull(vpnInstance,
419 "Vpn Instance not available with rd " + vrfTableKey.getRouteDistinguisher());
421 String vpnUuid = vpnInstance.getVpnInstanceName();
422 Preconditions.checkArgument(vpnUuid != null && !vpnUuid.isEmpty(),
423 "Could not find suitable VPN UUID for Route-Distinguisher=" + rd);
425 // if the new vrfEntry has been learned by Quagga BGP, its necessary to check if it's
426 // there an interVpnLink for the involved vpn in order to make learn the new route to
427 // the other part of the inter-vpn-link.
429 // For leaking, we need the InterVpnLink to be active. For removal, we just need a InterVpnLink.
430 Optional<InterVpnLink> interVpnLink =
431 (addOrRemove == NwConstants.ADD_FLOW) ? FibUtil.getActiveInterVpnLinkFromRd(dataBroker, rd)
432 : FibUtil.getInterVpnLinkByRd(dataBroker, rd);
433 if ( !interVpnLink.isPresent() ) {
434 LOG.debug("Could not find an InterVpnLink for Route-Distinguisher={}", rd);
438 // Ok, at this point everything is ready for the leaking/removal... but should it be performed?
439 // For removal, we remove all leaked routes, but we only leak a route if the corresponding flag is enabled.
441 (addOrRemove == NwConstants.DEL_FLOW) || ( RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP
442 && interVpnLink.get().isBgpRoutesLeaking() );
445 String theOtherVpnId = interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid)
446 ? interVpnLink.get().getSecondEndpoint().getVpnUuid().getValue()
449 String dstVpnRd = FibUtil.getVpnRd(dataBroker, theOtherVpnId);
450 String endpointIp = vrfEntry.getNextHopAddressList().get(0);
452 InstanceIdentifier<VrfEntry> vrfEntryIidInOtherVpn =
453 InstanceIdentifier.builder(FibEntries.class)
454 .child(VrfTables.class, new VrfTablesKey(dstVpnRd))
455 .child(VrfEntry.class, new VrfEntryKey(vrfEntry.getDestPrefix()))
457 if ( addOrRemove == NwConstants.ADD_FLOW ) {
458 LOG.debug("Leaking route (destination={}, nexthop={}) from Vrf={} to Vrf={}",
459 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), rd, dstVpnRd);
460 String key = rd + FibConstants.SEPARATOR + vrfEntry.getDestPrefix();
461 long label = FibUtil.getUniqueId(idManager, FibConstants.VPN_IDPOOL_NAME, key);
462 VrfEntry newVrfEntry = new VrfEntryBuilder(vrfEntry).setNextHopAddressList(Arrays.asList(endpointIp))
464 .setOrigin(RouteOrigin.INTERVPN.getValue())
466 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn, newVrfEntry);
468 LOG.debug("Removing leaked vrfEntry={}", vrfEntryIidInOtherVpn.toString());
469 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn);
474 private Prefixes updateVpnReferencesInLri(LabelRouteInfo lri, String vpnInstanceName, boolean isPresentInList) {
475 LOG.debug("updating LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
476 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
477 prefixBuilder.setDpnId(lri.getDpnId());
478 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
479 prefixBuilder.setIpAddress(lri.getPrefix());
480 // Increment the refCount here
481 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
482 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long)lri.getLabel())).build();
483 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri);
484 if (!isPresentInList) {
485 LOG.debug("vpnName {} is not present in LRI with label {}..", vpnInstanceName, lri.getLabel());
486 List<String> vpnInstanceNames = lri.getVpnInstanceList();
487 vpnInstanceNames.add(vpnInstanceName);
488 builder.setVpnInstanceList(vpnInstanceNames);
489 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(), FibUtil.DEFAULT_CALLBACK);
491 LOG.debug("vpnName {} is present in LRI with label {}..", vpnInstanceName, lri.getLabel());
493 return prefixBuilder.build();
496 private void installSubnetRouteInFib(final BigInteger dpnId, final long elanTag, final String rd,
497 final long vpnId, final VrfEntry vrfEntry, WriteTransaction tx){
498 Boolean wrTxPresent = true;
501 tx = dataBroker.newWriteOnlyTransaction();
503 synchronized (vrfEntry.getLabel().toString().intern()) {
504 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
505 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
506 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
508 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
509 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
510 if (vpnInstanceOpDataEntryOptional.isPresent()) {
511 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
512 if (!lri.getVpnInstanceList().contains(vpnInstanceName)) {
513 updateVpnReferencesInLri(lri, vpnInstanceName, false);
517 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
518 vrfEntry.getLabel(), lri.getVpnInterfaceName(), lri.getDpnId());
521 final List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
522 BigInteger subnetRouteMeta = ((BigInteger.valueOf(elanTag)).shiftLeft(32)).or((BigInteger.valueOf(vpnId).shiftLeft(1)));
523 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE }));
524 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
525 makeConnectedRoute(dpnId,vpnId,vrfEntry,rd,instructions,NwConstants.ADD_FLOW, tx);
527 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
528 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
529 // reinitialize instructions list for LFIB Table
530 final List<InstructionInfo> LFIBinstructions = new ArrayList<InstructionInfo>();
532 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
533 LFIBinstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
534 LFIBinstructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE }));
535 LFIBinstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
537 makeLFibTableEntry(dpnId,vrfEntry.getLabel(), LFIBinstructions, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
544 public void installInterVpnRouteInLFib(final String rd, final VrfEntry vrfEntry) {
545 // INTERVPN routes are routes in a Vpn1 that have been leaked to Vpn2. In DC-GW, this Vpn2 route is pointing
546 // to a list of DPNs where Vpn2's VpnLink was instantiated. In these DPNs LFIB must be programmed so that the
547 // packet is commuted from Vpn2 to Vpn1.
548 Optional<String> vpnNameOpc = FibUtil.getVpnNameFromRd(dataBroker, rd);
549 if ( !vpnNameOpc.isPresent() ) {
550 LOG.warn("Could not find VpnInstanceName for Route-Distinguisher {}", rd);
554 String vpnName = vpnNameOpc.get();
555 List<InterVpnLink> interVpnLinks = FibUtil.getAllInterVpnLinks(dataBroker);
556 boolean interVpnLinkFound = false;
557 for ( InterVpnLink interVpnLink : interVpnLinks ) {
558 boolean vpnIs1stEndpoint = interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName);
559 boolean vpnIs2ndEndpoint = !vpnIs1stEndpoint
560 && interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnName);
561 if ( vpnIs1stEndpoint || vpnIs2ndEndpoint ) {
562 interVpnLinkFound = true;
564 Optional<InterVpnLinkState> vpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName());
565 if ( !vpnLinkState.isPresent()
566 || !vpnLinkState.get().getState().equals(InterVpnLinkState.State.Active) ) {
567 LOG.warn("InterVpnLink {}, linking VPN {} and {}, is not in Active state",
568 interVpnLink.getName(), interVpnLink.getFirstEndpoint().getVpnUuid().getValue(),
569 interVpnLink.getSecondEndpoint().getVpnUuid().getValue() );
573 List<BigInteger> targetDpns = vpnIs1stEndpoint ? vpnLinkState.get().getFirstEndpointState().getDpId()
574 : vpnLinkState.get().getSecondEndpointState().getDpId();
575 Long lportTag = vpnIs1stEndpoint ? vpnLinkState.get().getSecondEndpointState().getLportTag()
576 : vpnLinkState.get().getFirstEndpointState().getLportTag();
578 LOG.trace("Installing flow in LFIB table for interVpnLink {}", interVpnLink.getName());
580 for ( BigInteger dpId : targetDpns ) {
581 List<ActionInfo> actionsInfos = Arrays.asList(new ActionInfo(ActionType.pop_mpls, new String[]{}));
583 BigInteger[] metadata = new BigInteger[] {
584 MetaDataUtil.getMetaDataForLPortDispatcher(lportTag.intValue(), ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
585 MetaDataUtil.getMetaDataMaskForLPortDispatcher()
587 List<InstructionInfo> instructions =
588 Arrays.asList(new InstructionInfo(InstructionType.apply_actions, actionsInfos),
589 new InstructionInfo(InstructionType.write_metadata, metadata),
590 new InstructionInfo(InstructionType.goto_table,
591 new long[] { NwConstants.L3_INTERFACE_TABLE }));
593 LOG.debug("Installing flow: VrfEntry=[prefix={} label={} nexthop={}] dpn {} for InterVpnLink {} in LFIB",
594 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(),
595 dpId, interVpnLink.getName());
597 makeLFibTableEntry(dpId, vrfEntry.getLabel(), instructions, LFIB_INTERVPN_PRIORITY,
598 NwConstants.ADD_FLOW, null);
605 if ( !interVpnLinkFound ) {
606 LOG.warn("VrfEntry=[prefix={} label={} nexthop={}] for VPN {} has origin INTERVPN but no InterVpnLink could be found",
607 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), rd);
613 private void installRouteInInterVpnLink(final InterVpnLinkDataComposite interVpnLink, final String vpnUuid,
614 final VrfEntry vrfEntry, long vpnTag) {
615 Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
616 Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null
617 && vrfEntry.getNextHopAddressList().size() == 1);
618 String destination = vrfEntry.getDestPrefix();
619 String nextHop = vrfEntry.getNextHopAddressList().get(0);
620 String iVpnLinkName = interVpnLink.getInterVpnLinkName();
622 // After having received a static route, we should check if the vpn is part of an inter-vpn-link.
623 // In that case, we should populate the FIB table of the VPN pointing to LPortDisptacher table
624 // using as metadata the LPortTag associated to that vpn in the inter-vpn-link.
625 if ( interVpnLink.getState().or(State.Error) != State.Active ) {
626 LOG.warn("Route to {} with nexthop={} cannot be installed because the interVpnLink {} is not active",
627 destination, nextHop, iVpnLinkName);
631 Optional<Long> optOtherEndpointLportTag = interVpnLink.getOtherEndpointLportTagByVpnName(vpnUuid);
632 if ( !optOtherEndpointLportTag.isPresent() ) {
633 LOG.warn("Could not find suitable LportTag for the endpoint opposite to vpn {} in interVpnLink {}",
634 vpnUuid, iVpnLinkName);
638 List<BigInteger> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnUuid);
639 if ( targetDpns.isEmpty() ) {
640 LOG.warn("Could not find DPNs for endpoint opposite to vpn {} in interVpnLink {}", vpnUuid, iVpnLinkName);
644 BigInteger[] metadata = new BigInteger[] {
645 MetaDataUtil.getMetaDataForLPortDispatcher(optOtherEndpointLportTag.get().intValue(),
646 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
647 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, new BigInteger[] { MetaDataUtil.getVpnIdMetadata(vpnTag),
660 MetaDataUtil.METADATA_MASK_VRFID }));
661 matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_IPV4 }));
663 if (prefixLength != 0) {
664 matches.add(new MatchInfo(MatchFieldType.ipv4_destination,
665 new String[] { destPrefixIpAddress, Integer.toString(prefixLength) }));
668 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
669 String flowRef = getInterVpnFibFlowRef(iVpnLinkName, destination, nextHop);
670 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
671 COOKIE_VM_FIB_TABLE, matches, instructions);
673 LOG.trace("Installing flow in FIB table for vpn {} interVpnLink {} nextHop {} key {}" ,
674 vpnUuid, interVpnLink.getInterVpnLinkName(), nextHop, flowRef);
676 for ( BigInteger dpId : targetDpns ) {
678 LOG.debug("Installing flow: VrfEntry=[prefix={} label={} nextHop={}] dpn {} for InterVpnLink {} in FIB",
679 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(),
680 dpId, interVpnLink.getInterVpnLinkName());
682 mdsalManager.installFlow(dpId, flowEntity);
687 private <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
688 InstanceIdentifier<T> path) {
690 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
692 Optional<T> result = Optional.absent();
694 result = tx.read(datastoreType, path).get();
695 } catch (Exception e) {
696 throw new RuntimeException(e);
702 private List<BigInteger> createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
703 List<BigInteger> returnLocalDpnId = new ArrayList<>();
704 Prefixes localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
705 String localNextHopIP = vrfEntry.getDestPrefix();
707 if (localNextHopInfo == null) {
708 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
709 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
710 if (extraRoute != null) {
711 for (String nextHopIp : extraRoute.getNexthopIpList()) {
712 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
713 if (nextHopIp != null) {
714 localNextHopInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, nextHopIp + "/32");
715 localNextHopIP = nextHopIp + "/32";
716 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, vpnId);
717 returnLocalDpnId.add(dpnId);
721 if (localNextHopInfo == null) {
722 /* imported routes case */
723 synchronized (vrfEntry.getLabel().toString().intern()) {
724 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
725 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
726 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
727 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
728 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
729 if (vpnInstanceOpDataEntryOptional.isPresent()) {
730 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
731 if (lri.getVpnInstanceList().contains(vpnInstanceName)) {
732 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, true);
733 localNextHopIP = lri.getPrefix();
735 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, false);
736 localNextHopIP = lri.getPrefix();
739 if (localNextHopInfo != null) {
740 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
741 vrfEntry.getLabel(), localNextHopInfo.getVpnInterfaceName(), lri.getDpnId());
742 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, lri.getParentVpnid());
743 returnLocalDpnId.add(dpnId);
750 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, vpnId);
751 returnLocalDpnId.add(dpnId);
754 return returnLocalDpnId;
757 private BigInteger checkCreateLocalFibEntry(Prefixes localNextHopInfo, String localNextHopIP, final Long vpnId, final String rd,
758 final VrfEntry vrfEntry, Long parentVpnId){
759 if (localNextHopInfo != null) {
760 final BigInteger dpnId = localNextHopInfo.getDpnId();
761 if (!isVpnPresentInDpn(rd, dpnId)) {
762 LOG.error("The vpnName with vpnId {} rd {} is not available on dpn {}", vpnId, rd, dpnId.toString());
763 return BigInteger.ZERO;
766 final long groupId = nextHopManager.createLocalNextHop(parentVpnId, dpnId,
767 localNextHopInfo.getVpnInterfaceName(), localNextHopIP, vrfEntry.getDestPrefix());
769 LOG.error("Unable to create Group for local prefix {} on rd {} for vpninterface {} on Node {}",
770 vrfEntry.getDestPrefix(), rd, localNextHopInfo.getVpnInterfaceName(), dpnId.toString());
771 return BigInteger.ZERO;
773 List<ActionInfo> actionsInfos =
774 Arrays.asList(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
775 final List<InstructionInfo> instructions =
776 Arrays.asList(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
777 actionsInfos = Arrays.asList(new ActionInfo(ActionType.pop_mpls, new String[]{}),
778 new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }) );
779 final List<InstructionInfo> lfibinstructions = Arrays.asList(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
780 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
781 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
782 dpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
784 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);
786 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
787 dataStoreCoordinator.enqueueJob("FIB"+vpnId.toString()+dpnId.toString()+vrfEntry.getDestPrefix(),
788 new Callable<List<ListenableFuture<Void>>>() {
790 public List<ListenableFuture<Void>> call() throws Exception {
791 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
792 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
793 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
794 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), lfibinstructions , DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
795 makeTunnelTableEntry(dpnId, vrfEntry.getLabel(), groupId, tx);
797 List<ListenableFuture<Void>> futures = new ArrayList<>();
798 futures.add(tx.submit());
804 return BigInteger.ZERO;
807 private boolean isVpnPresentInDpn(String rd, BigInteger dpnId) {
808 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
809 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
810 if (dpnInVpn.isPresent()) {
816 private LabelRouteInfo getLabelRouteInfo(Long label) {
817 InstanceIdentifier<LabelRouteInfo>lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
818 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long)label)).build();
819 Optional<LabelRouteInfo> opResult = read(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid);
820 if (opResult.isPresent()) {
821 return opResult.get();
826 private boolean deleteLabelRouteInfo(LabelRouteInfo lri, String vpnInstanceName) {
827 LOG.debug("deleting LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
828 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
829 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long) lri.getLabel())).build();
833 List<String> vpnInstancesList = lri.getVpnInstanceList() != null ? lri.getVpnInstanceList() : new ArrayList<String>();
834 if (vpnInstancesList.contains(vpnInstanceName)) {
835 LOG.debug("vpninstance {} name is present", vpnInstanceName);
836 vpnInstancesList.remove(vpnInstanceName);
838 if (vpnInstancesList.size() == 0) {
839 LOG.debug("deleting LRI instance object for label {}", lri.getLabel());
840 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId);
843 LOG.debug("updating LRI instance object for label {}", lri.getLabel());
844 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri).setVpnInstanceList(vpnInstancesList);
845 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(), FibUtil.DEFAULT_CALLBACK);
850 private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/,
851 WriteTransaction tx) {
852 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
853 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
856 createTerminatingServiceActions(dpId, (int)label, actionsInfos, tx);
858 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully",
859 dpId, label, groupId);
862 public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos,
863 WriteTransaction tx) {
864 List<MatchInfo> mkMatches = new ArrayList<>();
866 LOG.debug("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
869 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
870 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
872 List<InstructionInfo> mkInstructions = new ArrayList<>();
873 mkInstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
875 FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
876 getTableMissFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
877 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
879 FlowKey flowKey = new FlowKey( new FlowId(terminatingServiceTableFlowEntity.getFlowId()) );
881 FlowBuilder flowbld = terminatingServiceTableFlowEntity.getFlowBuilder();
883 Node nodeDpn = buildDpnNode(terminatingServiceTableFlowEntity.getDpnId());
884 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
885 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
886 .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId())).child(Flow.class,flowKey).build();
887 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flowbld.build(),true );
890 private void removeTunnelTableEntry(BigInteger dpId, long label, WriteTransaction tx) {
891 FlowEntity flowEntity;
892 LOG.debug("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
893 List<MatchInfo> mkMatches = new ArrayList<>();
895 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
896 flowEntity = MDSALUtil.buildFlowEntity(dpId,
897 NwConstants.INTERNAL_TUNNEL_TABLE,
898 getTableMissFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
899 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
900 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
901 Node nodeDpn = buildDpnNode(flowEntity.getDpnId());
902 FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getFlowId()));
903 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
904 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
905 .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build();
907 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
908 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully", dpId, label);
912 * Delete local FIB entry
918 public List<BigInteger> deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
919 List<BigInteger> returnLocalDpnId = new ArrayList<>();
920 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
921 String localNextHopIP = vrfEntry.getDestPrefix();
923 if (localNextHopInfo == null) {
924 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
925 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
926 if (extra_route != null) {
927 for (String nextHopIp : extra_route.getNexthopIpList()) {
928 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
929 if (nextHopIp != null) {
930 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp + "/32");
931 localNextHopIP = nextHopIp + "/32";
932 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
933 vpnId, rd, vrfEntry, true /*isExtraRoute*/);
934 if (!dpnId.equals(BigInteger.ZERO)) {
935 returnLocalDpnId.add(dpnId);
941 if (localNextHopInfo == null) {
942 /* Imported VRF entry */
943 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
944 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
945 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
946 VpnNexthopBuilder vpnNexthopBuilder = new VpnNexthopBuilder();
947 vpnNexthopBuilder.setDpnId(lri.getDpnId());
948 BigInteger dpnId = checkDeleteLocalFibEntry(vpnNexthopBuilder.build(), localNextHopIP,
949 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
950 if (!dpnId.equals(BigInteger.ZERO)) {
951 returnLocalDpnId.add(dpnId);
958 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
959 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
960 if (!dpnId.equals(BigInteger.ZERO)) {
961 returnLocalDpnId.add(dpnId);
965 return returnLocalDpnId;
968 private BigInteger checkDeleteLocalFibEntry(VpnNexthop localNextHopInfo, final String localNextHopIP,
969 final Long vpnId, final String rd,
970 final VrfEntry vrfEntry, final boolean isExtraRoute) {
971 if (localNextHopInfo != null) {
972 final BigInteger dpnId = localNextHopInfo.getDpnId();;
973 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
974 dataStoreCoordinator.enqueueJob("FIB"+vpnId.toString()+dpnId.toString()+vrfEntry.getDestPrefix(),
975 new Callable<List<ListenableFuture<Void>>>() {
977 public List<ListenableFuture<Void>> call() throws Exception {
978 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
979 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null /* instructions */,
980 NwConstants.DEL_FLOW, tx);
981 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
982 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null /* instructions */,
983 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
984 removeTunnelTableEntry(dpnId, vrfEntry.getLabel(), tx);
986 List<ListenableFuture<Void>> futures = new ArrayList<>();
987 futures.add(tx.submit());
991 //TODO: verify below adjacency call need to be optimized (?)
992 deleteLocalAdjacency(dpnId, vpnId, localNextHopIP, vrfEntry.getDestPrefix());
995 return BigInteger.ZERO;
998 private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
999 return InstanceIdentifier.builder(VpnToExtraroute.class)
1000 .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class,
1001 new ExtrarouteKey(ipPrefix)).build();
1004 private Extraroute getVpnToExtraroute(String rd, String ipPrefix) {
1005 Optional<Extraroute> extraRouteInfo =
1006 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix));
1007 return extraRouteInfo.isPresent() ? extraRouteInfo.get() : null;
1011 private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
1013 Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
1014 new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
1015 RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
1016 if(!rpcResult.isSuccessful()) {
1017 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
1019 return rpcResult.getResult().getTunnelType();
1022 } catch (InterruptedException | ExecutionException e) {
1023 LOG.warn("Exception when getting tunnel interface Id for tunnel type", e);
1029 private void createRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, final VrfTablesKey vrfTableKey,
1030 final VrfEntry vrfEntry, WriteTransaction tx) {
1031 Boolean wrTxPresent = true;
1033 wrTxPresent = false;
1034 tx = dataBroker.newWriteOnlyTransaction();
1036 String rd = vrfTableKey.getRouteDistinguisher();
1037 LOG.debug( "createremotefibentry: adding route {} for rd {} with transaction {}",
1038 vrfEntry.getDestPrefix(), rd, tx);
1039 /********************************************/
1040 List<AdjacencyResult> adjacencyResults = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
1042 if (adjacencyResults.isEmpty()) {
1043 LOG.error("Could not get interface for nexthop: {} in vpn {}",
1044 vrfEntry.getNextHopAddressList(), rd);
1045 LOG.warn("Failed to add Route: {} in vpn: {}",
1046 vrfEntry.getDestPrefix(), rd);
1050 for (AdjacencyResult adjacencyResult : adjacencyResults) {
1051 List<InstructionInfo> instructions = new ArrayList<>();
1052 List<ActionInfo> actionInfos = new ArrayList<>();
1053 String egressInterface = adjacencyResult.getInterfaceName();
1054 if (Tunnel.class.equals(adjacencyResult.getInterfaceType())) {
1055 addTunnelInterfaceActions(egressInterface, vpnId, vrfEntry, actionInfos);
1057 addRewriteDstMacAction(vpnId, vrfEntry, actionInfos);
1059 List<ActionInfo> egressActions = nextHopManager.getEgressActionsForInterface(egressInterface);
1060 if (egressActions.isEmpty()) {
1062 "Failed to retrieve egress action for prefix {} nextHop {} interface {}. Aborting remote FIB entry creation.",
1063 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), egressInterface);
1066 actionInfos.addAll(egressActions);
1067 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionInfos));
1068 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
1073 LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
1076 private void addRewriteDstMacAction(long vpnId, VrfEntry vrfEntry, List<ActionInfo> actionInfos) {
1077 String ipPrefix = vrfEntry.getDestPrefix();
1078 Prefixes prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, ipPrefix);
1079 if (prefixInfo == null) {
1080 LOG.debug("No prefix info found for prefix {}", ipPrefix);
1084 String ifName = prefixInfo.getVpnInterfaceName();
1085 if (ifName == null) {
1086 LOG.warn("Failed to get VPN interface for prefix {}", ipPrefix);
1090 String macAddress = FibUtil.getMacAddressFromPrefix(dataBroker, ifName, ipPrefix);
1091 if (macAddress == null) {
1092 LOG.warn("No MAC address found for VPN interface {} prefix {}", ifName, ipPrefix);
1096 actionInfos.add(new ActionInfo(ActionType.set_field_eth_dest, new String[] { macAddress }, actionInfos.size()));
1099 private void addTunnelInterfaceActions(String tunnelInterface, long vpnId, VrfEntry vrfEntry,
1100 List<ActionInfo> actionInfos) {
1101 Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
1102 if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
1103 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
1104 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
1105 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label,
1106 new String[] { Long.toString(vrfEntry.getLabel()) }));
1108 int label = vrfEntry.getLabel().intValue();
1109 BigInteger tunnelId;
1110 // FIXME vxlan vni bit set is not working properly with OVS.need to
1112 if (tunnel_type.equals(TunnelTypeVxlan.class)) {
1113 tunnelId = BigInteger.valueOf(label);
1115 tunnelId = BigInteger.valueOf(label);
1118 LOG.debug("adding set tunnel id action for label {}", label);
1119 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] { tunnelId }));
1120 addRewriteDstMacAction(vpnId, vrfEntry, actionInfos);
1124 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
1125 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
1126 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1127 if (dpnInVpn.isPresent()) {
1128 List<VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
1129 VpnInterfaces currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
1131 if (vpnInterfaces.remove(currVpnInterface)) {
1132 if (vpnInterfaces.isEmpty()) {
1133 LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
1134 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1135 cleanUpDpnForVpn(dpnId, vpnId, rd, null);
1137 LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
1138 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id.child(
1139 VpnInterfaces.class,
1140 new VpnInterfacesKey(intfName)));
1146 private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
1147 /* Get interface info from prefix to interface mapping;
1148 Use the interface info to get the corresponding vpn interface op DS entry,
1149 remove the adjacency corresponding to this fib entry.
1150 If adjacency removed is the last adjacency, clean up the following:
1151 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
1152 - prefix to interface entry
1153 - vpn interface op DS
1155 LOG.debug("Cleanup of prefix {} in VPN {}", vrfEntry.getDestPrefix(), vpnId);
1156 Prefixes prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, vrfEntry.getDestPrefix());
1157 Extraroute extraRoute = null;
1158 if (prefixInfo == null) {
1159 extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1160 if(extraRoute != null) {
1161 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1162 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
1164 if (nextHopIp != null) {
1165 prefixInfo = FibUtil.getPrefixToInterface(dataBroker, vpnId, nextHopIp + "/32");
1166 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1170 if (prefixInfo == null) {
1171 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1172 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
1173 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1174 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
1175 prefixBuilder.setDpnId(lri.getDpnId());
1176 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
1177 prefixBuilder.setIpAddress(lri.getPrefix());
1178 prefixInfo = prefixBuilder.build();
1179 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
1180 vrfEntry.getLabel(), prefixInfo.getVpnInterfaceName(), lri.getDpnId());
1181 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1185 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1189 private void checkCleanUpOpDataForFib(final Prefixes prefixInfo, final Long vpnId, final String rd,
1190 final VrfEntry vrfEntry, final Extraroute extraRoute) {
1192 if (prefixInfo == null) {
1193 LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for prefix {}", vrfEntry.getDestPrefix());
1194 return; //Don't have any info for this prefix (shouldn't happen); need to return
1197 String ifName = prefixInfo.getVpnInterfaceName();
1198 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1199 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + ifName,
1200 new CleanupVpnInterfaceWorker(prefixInfo, vpnId, rd, vrfEntry, extraRoute));
1203 private class CleanupVpnInterfaceWorker implements Callable<List<ListenableFuture<Void>>> {
1204 Prefixes prefixInfo;
1208 Extraroute extraRoute;
1210 public CleanupVpnInterfaceWorker(final Prefixes prefixInfo, final Long vpnId, final String rd,
1211 final VrfEntry vrfEntry, final Extraroute extraRoute) {
1212 this.prefixInfo = prefixInfo;
1215 this.vrfEntry= vrfEntry;
1216 this.extraRoute = extraRoute;
1220 public List<ListenableFuture<Void>> call() throws Exception {
1221 // If another renderer(for eg : CSS) needs to be supported, check can be performed here
1222 // to call the respective helpers.
1224 //First Cleanup LabelRouteInfo
1225 synchronized (vrfEntry.getLabel().toString().intern()) {
1226 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1227 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
1228 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1229 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
1230 String vpnInstanceName = "";
1231 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1232 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1234 boolean lriRemoved = deleteLabelRouteInfo(lri, vpnInstanceName);
1236 String parentRd = lri.getParentVpnRd();
1237 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1238 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1241 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1242 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1245 String ifName = prefixInfo.getVpnInterfaceName();
1246 Optional<VpnInterface> optvpnInterface = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1247 FibUtil.getVpnInterfaceIdentifier(ifName));
1248 if (optvpnInterface.isPresent()) {
1249 long associatedVpnId = FibUtil.getVpnId(dataBroker, optvpnInterface.get().getVpnInstanceName());
1250 if (vpnId != associatedVpnId) {
1251 LOG.warn("Prefixes {} are associated with different vpn instance with id : {} rather than {}",
1252 vrfEntry.getDestPrefix(), associatedVpnId, vpnId);
1253 LOG.warn("Not proceeding with Cleanup op data for prefix {}", vrfEntry.getDestPrefix());
1256 LOG.debug("Processing cleanup of prefix {} associated with vpn {}",
1257 vrfEntry.getDestPrefix(), associatedVpnId);
1260 if (extraRoute != null) {
1261 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1262 FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
1264 Optional<Adjacencies> optAdjacencies = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1265 FibUtil.getAdjListPath(ifName));
1267 if (optAdjacencies.isPresent()) {
1268 numAdj = optAdjacencies.get().getAdjacency().size();
1270 //remove adjacency corr to prefix
1272 LOG.info("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix());
1273 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1274 FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
1276 if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
1277 //clean up the vpn interface from DpnToVpn list
1278 LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
1279 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1280 FibUtil.getVpnInterfaceIdentifier(ifName));
1286 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1287 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1288 final String rd = vrfTableKey.getRouteDistinguisher();
1289 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1290 if (vpnInstance == null) {
1291 LOG.error("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1294 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1296 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1297 if (subnetRoute != null) {
1298 elanTag = subnetRoute.getElantag();
1299 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
1300 rd, vrfEntry.getDestPrefix(), elanTag);
1301 if (vpnToDpnList != null) {
1302 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1303 dataStoreCoordinator.enqueueJob("FIB" + rd.toString() + vrfEntry.getDestPrefix(),
1304 new Callable<List<ListenableFuture<Void>>>() {
1306 public List<ListenableFuture<Void>> call() throws Exception {
1307 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1309 for (final VpnToDpnList curDpn : vpnToDpnList) {
1311 makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry,
1312 vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW, tx);
1313 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1314 makeLFibTableEntry(curDpn.getDpnId(), vrfEntry.getLabel(), null,
1315 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1318 List<ListenableFuture<Void>> futures = new ArrayList<>();
1319 futures.add(tx.submit());
1324 synchronized (vrfEntry.getLabel().toString().intern()) {
1325 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1326 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) && vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1327 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
1328 String vpnInstanceName = "";
1329 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1330 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1332 boolean lriRemoved = this.deleteLabelRouteInfo(lri, vpnInstanceName);
1334 String parentRd = lri.getParentVpnRd();
1335 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1336 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1337 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {} as labelRouteInfo cleared", vrfEntry.getLabel(), rd,
1338 vrfEntry.getDestPrefix());
1341 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1342 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1343 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd,
1344 vrfEntry.getDestPrefix());
1349 if (installRouterFibEntries(vrfEntry, vpnToDpnList, vpnInstance.getVpnId(), NwConstants.DEL_FLOW)) {
1353 final List<BigInteger> localDpnIdList = deleteLocalFibEntry(vpnInstance.getVpnId(),
1354 vrfTableKey.getRouteDistinguisher(), vrfEntry);
1355 if (vpnToDpnList != null) {
1356 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1357 dataStoreCoordinator.enqueueJob("FIB" + rd.toString() + vrfEntry.getDestPrefix(),
1358 new Callable<List<ListenableFuture<Void>>>() {
1360 public List<ListenableFuture<Void>> call() throws Exception {
1361 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1363 if (localDpnIdList.size() <= 0) {
1364 for (VpnToDpnList curDpn : vpnToDpnList) {
1365 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1366 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1367 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1370 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1374 for (BigInteger localDpnId : localDpnIdList) {
1375 for (VpnToDpnList curDpn : vpnToDpnList) {
1376 if (!curDpn.getDpnId().equals(localDpnId)) {
1377 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1378 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1379 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1382 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1388 List<ListenableFuture<Void>> futures = new ArrayList<>();
1389 futures.add(tx.submit());
1395 //The flow/group entry has been deleted from config DS; need to clean up associated operational
1396 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
1397 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
1399 // Remove all fib entries configured due to interVpnLink, when nexthop is the opposite endPoint
1400 // of the interVpnLink.
1401 Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(this.dataBroker, rd);
1402 if ( optVpnUuid.isPresent() ) {
1403 String vpnUuid = optVpnUuid.get();
1404 List<String> routeNexthoplist = vrfEntry.getNextHopAddressList();
1405 if(routeNexthoplist.isEmpty()) {
1406 LOG.trace("NextHopList is empty for VrfEntry {}", vrfEntry);
1409 String routeNexthop = routeNexthoplist.get(0);
1410 Optional<InterVpnLinkDataComposite> optInterVpnLink = InterVpnLinkCache.getInterVpnLinkByVpnId(vpnUuid);
1411 if ( optInterVpnLink.isPresent() ) {
1412 InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
1413 if ( interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid))
1415 // This is route that points to the other endpoint of an InterVpnLink
1416 // In that case, we should look for the FIB table pointing to LPortDispatcher table and remove it.
1417 removeInterVPNLinkRouteFlows(interVpnLink.getInterVpnLinkName(),
1418 interVpnLink.isFirstEndpointVpnName(rd),
1427 Please note that the following deleteFibEntries will be invoked only for BGP Imported Routes.
1428 The invocation of the following method is via delete() callback from the MDSAL Batching Infrastructure
1429 provided by ResourceBatchingManager
1431 private void deleteFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1432 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1434 final String rd = vrfTableKey.getRouteDistinguisher();
1435 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1436 if (vpnInstance == null) {
1437 LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1440 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1441 if (vpnToDpnList != null) {
1442 for (VpnToDpnList curDpn : vpnToDpnList) {
1443 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1444 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, writeTx);
1450 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
1451 final long vpnId, final VrfTablesKey vrfTableKey,
1452 final VrfEntry vrfEntry, WriteTransaction tx) {
1454 Boolean wrTxPresent = true;
1456 wrTxPresent = false;
1457 tx = dataBroker.newWriteOnlyTransaction();
1460 LOG.debug("deleting route: prefix={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
1461 String rd = vrfTableKey.getRouteDistinguisher();
1463 if(localDpnId != null) {
1464 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
1465 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1469 // below two reads are kept as is, until best way is found to identify dpnID
1470 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
1471 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1473 if (localNextHopInfo == null && extraRoute != null) {
1474 // Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
1475 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1476 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp);
1477 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1480 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1487 private boolean checkDpnDeleteFibEntry(VpnNexthop localNextHopInfo, BigInteger remoteDpnId, long vpnId,
1488 VrfEntry vrfEntry, String rd, WriteTransaction tx){
1489 boolean isRemoteRoute = true;
1490 if (localNextHopInfo != null) {
1491 isRemoteRoute = !remoteDpnId.equals(localNextHopInfo.getDpnId());
1493 if (isRemoteRoute) {
1494 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1497 LOG.debug("Did not delete FIB entry: rd={}, vrfEntry={}, as it is local to dpnId={}", rd, vrfEntry.getDestPrefix(), remoteDpnId);
1502 private void deleteFibEntry(BigInteger remoteDpnId, long vpnId, VrfEntry vrfEntry, String rd, WriteTransaction tx){
1503 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1504 LOG.debug("Successfully delete FIB entry: vrfEntry={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
1508 (byte[] rawIpAddress) {
1509 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
1510 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
1513 private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
1514 List<InstructionInfo> instructions, int addOrRemove, WriteTransaction tx) {
1515 Boolean wrTxPresent = true;
1517 wrTxPresent = false;
1518 tx = dataBroker.newWriteOnlyTransaction();
1521 LOG.trace("makeConnectedRoute: vrfEntry {}", vrfEntry);
1522 String values[] = vrfEntry.getDestPrefix().split("/");
1523 String ipAddress = values[0];
1524 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
1525 if (addOrRemove == NwConstants.ADD_FLOW) {
1526 LOG.debug("Adding route to DPN {} for rd {} prefix {} ", dpId, rd, vrfEntry.getDestPrefix());
1528 LOG.debug("Removing route from DPN {} for rd {} prefix {}", dpId, rd, vrfEntry.getDestPrefix());
1530 InetAddress destPrefix;
1532 destPrefix = InetAddress.getByName(ipAddress);
1533 } catch (UnknownHostException e) {
1534 LOG.error("Failed to get destPrefix for prefix {} ", vrfEntry.getDestPrefix(), e);
1538 List<MatchInfo> matches = new ArrayList<>();
1540 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
1541 MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
1543 matches.add(new MatchInfo(MatchFieldType.eth_type,
1544 new long[] { NwConstants.ETHTYPE_IPV4 }));
1546 if(prefixLength != 0) {
1547 matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
1548 destPrefix.getHostAddress(), Integer.toString(prefixLength)}));
1550 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
1551 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, priority, destPrefix);
1552 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
1553 COOKIE_VM_FIB_TABLE, matches, instructions);
1555 Flow flow = flowEntity.getFlowBuilder().build();
1556 String flowId = flowEntity.getFlowId();
1557 FlowKey flowKey = new FlowKey( new FlowId(flowId));
1558 Node nodeDpn = buildDpnNode(dpId);
1560 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1561 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1562 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1564 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1565 SubTransaction subTransaction = new SubTransactionImpl();
1566 if (addOrRemove == NwConstants.ADD_FLOW) {
1567 subTransaction.setInstanceIdentifier(flowInstanceId);
1568 subTransaction.setInstance(flow);
1569 subTransaction.setAction(SubTransaction.CREATE);
1571 subTransaction.setInstanceIdentifier(flowInstanceId);
1572 subTransaction.setAction(SubTransaction.DELETE);
1574 transactionObjects.add(subTransaction);
1577 if (addOrRemove == NwConstants.ADD_FLOW) {
1578 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true);
1580 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1588 //TODO: How to handle the below code, its a copy paste from MDSALManager.java
1589 private Node buildDpnNode(BigInteger dpnId) {
1590 NodeId nodeId = new NodeId("openflow:" + dpnId);
1591 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
1596 private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions, int priority,
1597 int addOrRemove, WriteTransaction tx) {
1598 Boolean wrTxPresent = true;
1600 wrTxPresent = false;
1601 tx = dataBroker.newWriteOnlyTransaction();
1604 List<MatchInfo> matches = new ArrayList<MatchInfo>();
1605 matches.add(new MatchInfo(MatchFieldType.eth_type,
1606 new long[] { NwConstants.ETHTYPE_MPLS_UC }));
1607 matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
1609 // Install the flow entry in L3_LFIB_TABLE
1610 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, priority);
1612 FlowEntity flowEntity;
1613 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef, priority, flowRef, 0, 0,
1614 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
1615 Flow flow = flowEntity.getFlowBuilder().build();
1616 String flowId = flowEntity.getFlowId();
1617 FlowKey flowKey = new FlowKey( new FlowId(flowId));
1618 Node nodeDpn = buildDpnNode(dpId);
1619 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1620 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1621 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1623 if (addOrRemove == NwConstants.ADD_FLOW) {
1624 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true);
1626 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1632 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} : key {} {} successfully",
1633 dpId, label, instructions, flowKey, (NwConstants.ADD_FLOW == addOrRemove) ? "ADDED" : "REMOVED");
1636 private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress,
1637 final String ipPrefixAddress) {
1638 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
1640 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress, ipPrefixAddress);
1641 } catch (NullPointerException e) {
1646 public void populateFibOnNewDpn(final BigInteger dpnId, final long vpnId, final String rd,
1647 final FutureCallback<List<Void>> callback) {
1648 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
1649 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1650 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1651 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1652 if (!vrfTable.isPresent()) {
1653 LOG.warn("VRF Table not yet available for RD {}", rd);
1654 if (callback != null) {
1655 List<ListenableFuture<Void>> futures = new ArrayList<>();
1656 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1657 Futures.addCallback(listenableFuture, callback);
1661 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1662 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1663 new Callable<List<ListenableFuture<Void>>>() {
1665 public List<ListenableFuture<Void>> call() throws Exception {
1666 List<ListenableFuture<Void>> futures = new ArrayList<>();
1667 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1668 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1669 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1670 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1671 if (subnetRoute != null) {
1672 long elanTag = subnetRoute.getElantag();
1673 installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
1676 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
1677 if (routerInt != null) {
1678 LOG.trace( "Router augmented vrfentry found rd:{}, uuid:{}, ip:{}, mac:{}",
1679 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
1680 installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(), routerInt.getIpAddress(),
1681 new MacAddress(routerInt.getMacAddress()), NwConstants.ADD_FLOW);
1684 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) { //Handle local flow creation for imports
1685 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1686 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
1687 && vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1688 if (lri.getDpnId().equals(dpnId)) {
1689 createLocalFibEntry(vpnId, rd, vrfEntry);
1694 // Passing null as we don't know the dpn
1695 // to which prefix is attached at this point
1696 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1698 //TODO: if we have 100K entries in FIB, can it fit in one Tranasaction (?)
1699 futures.add(tx.submit());
1701 if (callback != null) {
1702 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1703 Futures.addCallback(listenableFuture, callback);
1711 public void populateFibOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1712 final String localNextHopIp, final String remoteNextHopIp) {
1713 LOG.trace("dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} : populateFibOnDpn",
1714 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1715 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1716 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1717 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1718 if (vrfTable.isPresent()) {
1719 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1720 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1721 new Callable<List<ListenableFuture<Void>>>() {
1723 public List<ListenableFuture<Void>> call() throws Exception {
1724 List<ListenableFuture<Void>> futures = new ArrayList<>();
1725 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1726 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1727 LOG.trace("populate FIB starts on Dpn " + dpnId
1728 + "rd " + rd.toString()
1729 + "localNextHopIp " + localNextHopIp
1730 + "remoteNextHopIp" + remoteNextHopIp
1731 + "vpnId " + vpnId );
1732 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1733 LOG.trace("old vrfEntry before populate:: {}", vrfEntry);
1735 if (vrfEntry.getOrigin().equals(RouteOrigin.BGP.getValue())) {
1736 if (remoteNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1737 LOG.trace(" creating remote FIB entry for vfEntry {}", vrfEntry);
1738 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeTransaction);
1740 } else if (vrfEntry.getOrigin().equals(RouteOrigin.STATIC.getValue())) {
1741 BigInteger dpnIdForPrefix = null;
1742 String destPfx = vrfEntry.getDestPrefix();
1743 if (vrfEntry.getAugmentation(SubnetRoute.class) == null) {
1744 Optional<Extraroute> extraRouteInfo =
1745 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1746 getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
1747 if (extraRouteInfo.isPresent()) {
1750 dpnIdForPrefix = nextHopManager.getDpnForPrefix(vpnId, destPfx);
1752 // Subnet Route handling
1753 Optional<Prefixes> localNextHopInfoData =
1754 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1755 FibUtil.getPrefixToInterfaceIdentifier(vpnId, destPfx));
1756 if (localNextHopInfoData.isPresent()) {
1757 Prefixes prefixes = localNextHopInfoData.get();
1758 dpnIdForPrefix = prefixes.getDpnId();
1761 if (dpnIdForPrefix == null) {
1762 LOG.trace("Populate::the dpnIdForPrefix is null for prefix {}.",
1763 vrfEntry.getDestPrefix());
1766 int sameDpnId = dpnIdForPrefix.compareTo(dpnId);
1767 if (sameDpnId != 0) {
1768 LOG.trace("Populate::Different srcDpnId {} and dpnIdForPrefix {} for prefix {}",
1769 dpnId, dpnIdForPrefix, vrfEntry.getDestPrefix());
1772 InstanceIdentifier<VrfEntry> vrfEntryId = getVrfEntryId(rd, vrfEntry.getDestPrefix());
1773 List<String> newNextHopAddrList = vrfEntry.getNextHopAddressList();
1774 newNextHopAddrList.add(localNextHopIp);
1775 VrfEntry newVrfEntry =
1776 new VrfEntryBuilder(vrfEntry).setNextHopAddressList(newNextHopAddrList).build();
1777 // Just update the VrfEntry
1778 FibUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
1779 vrfEntryId, newVrfEntry);
1780 // writeTransaction.put(LogicalDatastoreType.CONFIGURATION,
1781 // vrfEntryId, newVrfEntry);
1782 vrfEntry = getVrfEntry(dataBroker, rd, destPfx);
1783 LOG.trace("updated vrfEntry after populate:: {}", vrfEntry);
1786 futures.add(writeTransaction.submit());
1787 LOG.trace("populate FIB ends on Dpn " + dpnId
1788 + "rd " + rd.toString()
1789 + "localNextHopIp " + localNextHopIp
1790 + "remoteNextHopIp" + remoteNextHopIp
1791 + "vpnId " + vpnId);
1799 public void handleRemoteRoute(final boolean action, final BigInteger localDpnId, final BigInteger remoteDpnId,
1800 final long vpnId, final String rd, final String destPrefix ,
1801 final String localNextHopIP, final String remoteNextHopIp) {
1803 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1804 dataStoreCoordinator.enqueueJob( "FIB" + rd.toString()
1805 + "local dpid" + localDpnId
1806 + "remote dpid" + remoteDpnId
1808 + "localNHIp" + localNextHopIP
1809 + "remoteNHIp" + remoteNextHopIp,
1810 new Callable<List<ListenableFuture<Void>>>() {
1812 public List<ListenableFuture<Void>> call() throws Exception {
1813 List<ListenableFuture<Void>> futures = new ArrayList<>();
1814 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1815 VrfTablesKey vrfTablesKey = new VrfTablesKey(rd);
1816 VrfEntry vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1817 if (vrfEntry == null) {
1820 LOG.trace("handleRemoteRoute :: action {}, localDpnId {}, " +
1821 "remoteDpnId {} , vpnId {}, rd {}, destPfx {}",
1822 action, localDpnId, remoteDpnId, vpnId, rd, destPrefix);
1823 if (action == true) {
1824 vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1825 LOG.trace("handleRemoteRoute updated(add) vrfEntry :: {}", vrfEntry);
1826 createRemoteFibEntry(remoteDpnId, vpnId, vrfTablesKey, vrfEntry, writeTransaction);
1828 vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1829 LOG.trace("handleRemoteRoute updated(remove) vrfEntry :: {}", vrfEntry);
1830 deleteRemoteRoute(null, remoteDpnId, vpnId, vrfTablesKey, vrfEntry, writeTransaction);
1832 futures.add(writeTransaction.submit());
1838 public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd,
1839 final FutureCallback<List<Void>> callback) {
1840 LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
1841 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1842 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1843 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1844 if (vrfTable.isPresent()) {
1845 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1846 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1847 new Callable<List<ListenableFuture<Void>>>() {
1849 public List<ListenableFuture<Void>> call() throws Exception {
1850 List<ListenableFuture<Void>> futures = new ArrayList<>();
1851 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1852 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1853 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1854 /* Handle subnet routes here */
1855 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1856 if (subnetRoute != null) {
1857 LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(),
1859 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1860 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1861 LOG.trace("cleanUpDpnForVpn: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd,
1862 vrfEntry.getDestPrefix());
1865 // ping responder for router interfaces
1866 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
1867 if (routerInt != null) {
1868 LOG.trace("Router augmented vrfentry found for rd:{}, uuid:{}, ip:{}, mac:{}",
1869 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
1870 installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(), routerInt.getIpAddress(),
1871 new MacAddress(routerInt.getMacAddress()), NwConstants.DEL_FLOW);
1874 // Passing null as we don't know the dpn
1875 // to which prefix is attached at this point
1876 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1878 futures.add(tx.submit());
1879 if (callback != null) {
1880 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1881 Futures.addCallback(listenableFuture, callback);
1891 public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd,
1892 final String localNextHopIp, final String remoteNextHopIp,
1893 final FutureCallback<List<Void>> callback) {
1894 LOG.trace( " cleanup remote routes on dpn {} for vpn {}, rd {}, " +
1895 " localNexthopIp {} , remoteNexhtHopIp {} : cleanUpDpnForVpn",
1896 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1897 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1898 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1899 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1900 if (vrfTable.isPresent()) {
1901 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1902 dataStoreCoordinator.enqueueJob(" FIB-" + vpnId + "-" + dpnId.toString(),
1903 new Callable<List<ListenableFuture<Void>>>() {
1905 public List<ListenableFuture<Void>> call() throws Exception {
1906 List<ListenableFuture<Void>> futures = new ArrayList<>();
1907 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1908 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1909 LOG.trace("cleanup FIB starts on Dpn " + dpnId
1910 + "rd " + rd.toString()
1911 + "localNextHopIp " + localNextHopIp
1912 + "remoteNextHopIp" + remoteNextHopIp
1913 + "vpnId " + vpnId);
1915 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1916 LOG.trace("old vrfEntry before cleanup:: {}", vrfEntry);
1917 if (remoteNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1918 LOG.trace(" deleting remote FIB entry {}", vrfEntry);
1919 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeTransaction);
1922 if (localNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1923 LOG.trace("changing the nexthopip for local VM routes {} on dpn {}",
1924 vrfEntry.getDestPrefix(), dpnId);
1925 String destPfx = vrfEntry.getDestPrefix();
1926 InstanceIdentifier<VrfEntry> vrfEntryId = getVrfEntryId(rd, destPfx);
1927 List<java.lang.String> newList = vrfEntry.getNextHopAddressList();
1928 newList.remove(localNextHopIp);
1929 VrfEntry newVrfEntry =
1930 new VrfEntryBuilder(vrfEntry).setNextHopAddressList(newList).build();
1931 FibUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
1932 vrfEntryId, newVrfEntry);
1933 vrfEntry = getVrfEntry(dataBroker, rd, destPfx);
1934 LOG.trace("updated vrfEntry after cleanup:: {}", vrfEntry);
1937 futures.add(writeTransaction.submit());
1938 if (callback != null) {
1939 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1940 Futures.addCallback(listenableFuture, callback);
1942 LOG.trace("cleanup FIB ends on Dpn " + dpnId
1943 + "rd " + rd.toString()
1944 + "localNextHopIp " + localNextHopIp
1945 + "remoteNextHopIp" + remoteNextHopIp
1946 + "vpnId " + vpnId);
1955 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
1956 InstanceIdentifierBuilder<VrfTables> idBuilder =
1957 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1958 InstanceIdentifier<VrfTables> id = idBuilder.build();
1962 private String getFlowRef(BigInteger dpnId, short tableId, long label, int priority) {
1963 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
1964 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(label).append(NwConstants.FLOWID_SEPARATOR)
1965 .append(priority).toString();
1968 private String getFlowRef(BigInteger dpnId, short tableId, String rd, int priority, InetAddress destPrefix) {
1969 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
1970 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
1971 .append(rd).append(NwConstants.FLOWID_SEPARATOR)
1972 .append(priority).append(NwConstants.FLOWID_SEPARATOR)
1973 .append(destPrefix.getHostAddress()).toString();
1976 private String getInterVpnFibFlowRef(String interVpnLinkName, String prefix, String nextHop ) {
1977 return new StringBuilder(64).append(FLOWID_PREFIX)
1978 .append(interVpnLinkName).append(NwConstants.FLOWID_SEPARATOR)
1979 .append(prefix).append(NwConstants.FLOWID_SEPARATOR)
1980 .append(nextHop).toString();
1983 protected List<AdjacencyResult> resolveAdjacency(final BigInteger remoteDpnId, final long vpnId,
1984 final VrfEntry vrfEntry, String rd) {
1985 List<AdjacencyResult> adjacencyList = new ArrayList<>();
1986 List<String> prefixIpList = new ArrayList<>();
1987 LOG.trace("resolveAdjacency called with remotedpid {}, vpnId{}, VrfEntry {}",
1988 remoteDpnId, vpnId, vrfEntry);
1990 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
1991 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1992 if (extra_route == null) {
1993 prefixIpList = Arrays.asList(vrfEntry.getDestPrefix());
1995 prefixIpList = new ArrayList<>();
1996 for (String extraRouteIp : extra_route.getNexthopIpList()) {
1997 prefixIpList.add(extraRouteIp + "/32");
2001 prefixIpList = Arrays.asList(vrfEntry.getDestPrefix());
2004 for (String prefixIp : prefixIpList) {
2005 for (String nextHopIp : vrfEntry.getNextHopAddressList()) {
2006 LOG.debug("NextHop IP for destination {} is {}", prefixIp, nextHopIp);
2007 AdjacencyResult adjacencyResult = nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId,
2008 prefixIp, nextHopIp);
2009 if (adjacencyResult != null && !adjacencyList.contains(adjacencyResult)) {
2010 adjacencyList.add(adjacencyResult);
2014 } catch (NullPointerException e) {
2017 return adjacencyList;
2020 protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
2021 InstanceIdentifier<VpnInstanceOpDataEntry> id =
2022 InstanceIdentifier.create(VpnInstanceOpData.class)
2023 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
2024 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData =
2025 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
2026 return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null;
2029 private String getTableMissFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
2030 return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
2031 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
2032 .append(FLOWID_PREFIX).toString();
2036 * Install flow entry in protocol table to forward mpls
2037 * coming through gre tunnel to LFIB table.
2039 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
2040 final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
2041 // Instruction to goto L3 InterfaceTable
2042 List<InstructionInfo> instructions = new ArrayList<>();
2043 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
2044 List<MatchInfo> matches = new ArrayList<MatchInfo>();
2045 matches.add(new MatchInfo(MatchFieldType.eth_type,
2046 new long[] { NwConstants.ETHTYPE_MPLS_UC }));
2047 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2048 getTableMissFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2049 NwConstants.L3_LFIB_TABLE),
2050 DEFAULT_FIB_FLOW_PRIORITY,
2051 "Protocol Table For LFIB",
2053 COOKIE_PROTOCOL_TABLE,
2054 matches, instructions);
2056 if (addOrRemove == NwConstants.ADD_FLOW) {
2057 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
2058 mdsalManager.installFlow(flowEntityToLfib);
2060 mdsalManager.removeFlow(flowEntityToLfib);
2064 public List<String> printFibEntries() {
2065 List<String> result = new ArrayList<>();
2066 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s", "RD", "Prefix", "NextHop", "Label", "Origin"));
2067 result.add("-------------------------------------------------------------------");
2068 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
2069 Optional<FibEntries> fibEntries = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2070 if (fibEntries.isPresent()) {
2071 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
2072 for (VrfTables vrfTable : vrfTables) {
2073 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
2074 for (String nextHop : vrfEntry.getNextHopAddressList()) {
2075 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s",
2076 vrfTable.getRouteDistinguisher(),
2077 vrfEntry.getDestPrefix(), nextHop, vrfEntry.getLabel(), vrfEntry.getOrigin()));
2079 if (vrfEntry.getNextHopAddressList().isEmpty()) {
2080 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s",
2081 vrfTable.getRouteDistinguisher(),
2082 vrfEntry.getDestPrefix(), "local", vrfEntry.getLabel(), vrfEntry.getOrigin()));
2091 private VrfEntry getVrfEntry(DataBroker broker, String rd, String ipPrefix) {
2092 InstanceIdentifier<VrfEntry> vrfEntryId =
2093 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).
2094 child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2095 Optional<VrfEntry> vrfEntry = read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
2096 if (vrfEntry.isPresent()) {
2097 return vrfEntry.get();
2102 private InstanceIdentifier<VrfEntry> getVrfEntryId(String rd, String ipPrefix) {
2103 InstanceIdentifier<VrfEntry> vrfEntryId =
2104 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).
2105 child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2108 protected Boolean installRouterFibEntries(final VrfEntry vrfEntry, final Collection<VpnToDpnList> vpnToDpnList,
2109 long vpnId, int addOrRemove) {
2110 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
2111 if (routerInt != null && vpnToDpnList != null) {
2112 String routerId = routerInt.getUuid();
2113 String macAddress = routerInt.getMacAddress();
2114 String ipValue = routerInt.getIpAddress();
2115 LOG.trace("createFibEntries - Router augmented vrfentry found for for router uuid:{}, ip:{}, mac:{}",
2116 routerId, ipValue, macAddress);
2117 for (VpnToDpnList vpnDpn : vpnToDpnList) {
2118 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
2119 installRouterFibEntry(vrfEntry, vpnDpn.getDpnId(), vpnId, routerId, ipValue,
2120 new MacAddress(macAddress), addOrRemove);
2128 public void installRouterFibEntry(final VrfEntry vrfEntry, BigInteger dpnId, long vpnId, String routerUuid,
2129 String routerInternalIp, MacAddress routerMac, int addOrRemove) {
2130 String[] subSplit = routerInternalIp.split("/");
2132 String addRemoveStr = (addOrRemove == NwConstants.ADD_FLOW) ? "ADD_FLOW" : "DELETE_FLOW";
2133 LOG.trace("{}: bulding Echo Flow entity for dpid:{}, router_ip:{}, vpnId:{}, subSplit:{} ", addRemoveStr,
2134 dpnId, routerInternalIp, vpnId, subSplit[0]);
2136 List<MatchInfo> matches = new ArrayList<>();
2138 matches.add(new MatchInfo(MatchFieldType.ip_proto, new long[] { IPProtocols.ICMP.intValue() }));
2139 matches.add(new MatchInfo(MatchFieldType.metadata,
2140 new BigInteger[] { MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
2141 matches.add(new MatchInfo(MatchFieldType.icmp_v4, new long[] { (short) 8, (short) 0 }));
2142 matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_IPV4 }));
2143 matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] { subSplit[0], "32" }));
2145 List<ActionInfo> actionsInfos = new ArrayList<>();
2147 // Set Eth Src and Eth Dst
2148 actionsInfos.add(new ActionInfo(ActionType.move_src_dst_eth, new String[] {}));
2149 actionsInfos.add(new ActionInfo(ActionType.set_field_eth_src, new String[] { routerMac.getValue() }));
2151 // Move Ip Src to Ip Dst
2152 actionsInfos.add(new ActionInfo(ActionType.move_src_dst_ip, new String[] {}));
2153 actionsInfos.add(new ActionInfo(ActionType.set_source_ip, new String[] { subSplit[0], "32" }));
2155 // Set the ICMP type to 0 (echo reply)
2156 actionsInfos.add(new ActionInfo(ActionType.set_icmp_type, new String[] { "0" }));
2158 actionsInfos.add(new ActionInfo(ActionType.nx_load_in_port, new BigInteger[]{ BigInteger.ZERO }));
2160 actionsInfos.add(new ActionInfo(ActionType.nx_resubmit,
2161 new String[] { Short.toString(NwConstants.L3_FIB_TABLE) }));
2163 List<InstructionInfo> instructions = new ArrayList<>();
2165 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
2167 int priority = FibConstants.DEFAULT_FIB_FLOW_PRIORITY + FibConstants.DEFAULT_PREFIX_LENGTH;
2168 String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, vrfEntry.getLabel(), priority);
2170 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef,
2171 0, 0, NwConstants.COOKIE_VM_FIB_TABLE, matches, instructions);
2173 if (addOrRemove == NwConstants.ADD_FLOW) {
2174 mdsalManager.installFlow(flowEntity);
2176 mdsalManager.removeFlow(flowEntity);
2180 public void removeInterVPNLinkRouteFlows(final String interVpnLinkName,
2181 final boolean isVpnFirstEndPoint,
2182 final VrfEntry vrfEntry)
2184 Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null
2185 && vrfEntry.getNextHopAddressList().size() == 1);
2186 Optional<InterVpnLinkState> interVpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLinkName);
2188 if ( !interVpnLinkState.isPresent()) {
2189 LOG.warn("Could not find State for InterVpnLink {}", interVpnLinkName);
2193 List<BigInteger> targetDpns =
2194 isVpnFirstEndPoint ? interVpnLinkState.get().getFirstEndpointState().getDpId()
2195 : interVpnLinkState.get().getSecondEndpointState().getDpId();
2197 String nextHop = vrfEntry.getNextHopAddressList().get(0);
2201 String flowRef = getInterVpnFibFlowRef(interVpnLinkName, vrfEntry.getDestPrefix(), nextHop);
2202 FlowKey flowKey = new FlowKey(new FlowId(flowRef));
2203 Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef)).setTableId(NwConstants.L3_FIB_TABLE)
2204 .setFlowName(flowRef).build();
2206 LOG.trace("Removing flow in FIB table for interVpnLink {} key {}",
2207 interVpnLinkName, flowRef);
2209 for ( BigInteger dpId : targetDpns ) {
2210 LOG.debug("Removing flow: VrfEntry=[prefix={} label={} nexthop={}] dpn {} for InterVpnLink {} in FIB",
2211 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), nextHop,
2212 dpId, interVpnLinkName);
2214 mdsalManager.removeFlow(dpId, flow);
2219 LOG.trace("Removing flow in FIB table for interVpnLink {}", interVpnLinkName);
2221 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
2222 for ( BigInteger dpId : targetDpns ) {
2223 LOG.debug("Removing flow: VrfEntry=[prefix={} label={} nexthop={}] dpn {} for InterVpnLink {} in LFIB",
2224 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), nextHop,
2225 dpId, interVpnLinkName);
2226 makeLFibTableEntry(dpId, vrfEntry.getLabel(), null /* no instructions */,
2227 LFIB_INTERVPN_PRIORITY, NwConstants.DEL_FLOW, tx);