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.fibmanager.api.RouteOrigin;
55 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
56 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
57 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
58 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetTunnelTypeInputBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetTunnelTypeOutput;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.LabelRouteMap;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.RouterInterface;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.SubnetRoute;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfo;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthopBuilder;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroute;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIds;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIdsKey;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesBuilder;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
106 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;
107 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;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.VpnKey;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.link.states.InterVpnLinkState.State;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.inter.vpn.links.InterVpnLink;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
117 import org.opendaylight.yangtools.yang.binding.DataObject;
118 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
119 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
120 import org.opendaylight.yangtools.yang.common.RpcResult;
121 import org.slf4j.Logger;
122 import org.slf4j.LoggerFactory;
124 public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry, VrfEntryListener> implements AutoCloseable, ResourceHandler {
125 private static final Logger LOG = LoggerFactory.getLogger(VrfEntryListener.class);
126 private static final String FLOWID_PREFIX = "L3.";
127 private final DataBroker dataBroker;
128 private final IMdsalApiManager mdsalManager;
129 private IVpnManager vpnmanager;
130 private final NexthopManager nextHopManager;
131 private ItmRpcService itmManager;
132 private final OdlInterfaceRpcService interfaceManager;
133 private final IdManagerService idManager;
134 private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16);
135 private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
136 private static final int LFIB_INTERVPN_PRIORITY = 1;
137 private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16);
138 private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0);
139 public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
140 List<SubTransaction> transactionObjects;
141 private static final int PERIODICITY = 500;
142 private static Integer batchSize;
143 private static Integer batchInterval;
144 private static final int BATCH_SIZE = 1000;
145 private static BlockingQueue<ActionableResource> vrfEntryBufferQ = new LinkedBlockingQueue<>();
146 private final ResourceBatchingManager resourceBatchingManager;
148 public VrfEntryListener(final DataBroker dataBroker, final IMdsalApiManager mdsalApiManager,
149 final NexthopManager nexthopManager, final OdlInterfaceRpcService interfaceManager,
150 final IdManagerService idManager) {
151 super(VrfEntry.class, VrfEntryListener.class);
152 this.dataBroker = dataBroker;
153 this.mdsalManager = mdsalApiManager;
154 this.nextHopManager = nexthopManager;
155 this.interfaceManager = interfaceManager;
156 this.idManager = idManager;
157 batchSize = Integer.getInteger("batch.size");
158 if (batchSize == null) {
159 batchSize = BATCH_SIZE;
161 batchInterval = Integer.getInteger("batch.wait.time");
162 if (batchInterval == null) {
163 batchInterval = PERIODICITY;
165 resourceBatchingManager = ResourceBatchingManager.getInstance();
166 resourceBatchingManager.registerBatchableResource("FIB-VRFENTRY",vrfEntryBufferQ, this);
167 transactionObjects = new ArrayList<>();
170 public void start() {
171 LOG.info("{} start", getClass().getSimpleName());
172 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
176 protected VrfEntryListener getDataTreeChangeListener() { return VrfEntryListener.this; }
179 protected InstanceIdentifier<VrfEntry> getWildCardPath() {
180 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
184 public DataBroker getResourceBroker() {
189 protected void add(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
190 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
191 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
192 LOG.debug("ADD: Adding Fib Entry rd {} prefix {} nexthop {} label {}",
193 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
194 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
195 createFibEntries(identifier, vrfEntry);
197 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + vrfEntry.getDestPrefix());
198 actResource.setAction(ActionableResource.CREATE);
199 actResource.setInstanceIdentifier(identifier);
200 actResource.setInstance(vrfEntry);
201 vrfEntryBufferQ.add(actResource);
202 leakRouteIfNeeded(identifier, vrfEntry, NwConstants.ADD_FLOW);
204 LOG.debug("ADD: Added Fib Entry rd {} prefix {} nexthop {} label {}",
205 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
209 protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
210 Preconditions.checkNotNull(vrfEntry, "VrfEntry should not be null or empty.");
211 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
212 LOG.debug("REMOVE: Removing Fib Entry rd {} prefix {} nexthop {} label {}",
213 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
214 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
215 deleteFibEntries(identifier, vrfEntry);
217 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + vrfEntry.getDestPrefix());
218 actResource.setAction(ActionableResource.DELETE);
219 actResource.setInstanceIdentifier(identifier);
220 actResource.setInstance(vrfEntry);
221 vrfEntryBufferQ.add(actResource);
222 leakRouteIfNeeded(identifier, vrfEntry, NwConstants.DEL_FLOW);
224 LOG.debug("REMOVE: Removed Fib Entry rd {} prefix {} nexthop {} label {}",
225 rd, vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), vrfEntry.getLabel());
229 protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
230 Preconditions.checkNotNull(update, "VrfEntry should not be null or empty.");
231 String rd = identifier.firstKeyOf(VrfTables.class).getRouteDistinguisher();
232 LOG.debug("UPDATE: Updating Fib Entries to rd {} prefix {} nexthop {} label {}",
233 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
234 if (RouteOrigin.value(update.getOrigin()) != RouteOrigin.BGP) {
235 createFibEntries(identifier, update);
237 ActionableResource actResource = new ActionableResourceImpl(rd.toString() + update.getDestPrefix());
238 actResource.setAction(ActionableResource.UPDATE);
239 actResource.setInstanceIdentifier(identifier);
240 actResource.setInstance(update);
241 actResource.setOldInstance(original);
242 vrfEntryBufferQ.add(actResource);
244 LOG.debug("UPDATE: Updated Fib Entries to rd {} prefix {} nexthop {} label {}",
245 rd, update.getDestPrefix(), update.getNextHopAddressList(), update.getLabel());
249 public void create(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object vrfEntry, List<SubTransaction> transactionObjects) {
250 this.transactionObjects = transactionObjects;
251 if (vrfEntry instanceof VrfEntry) {
252 createFibEntries(tx, identifier, (VrfEntry)vrfEntry);
257 public void delete(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object vrfEntry, List<SubTransaction> transactionObjects) {
258 this.transactionObjects = transactionObjects;
259 if (vrfEntry instanceof VrfEntry) {
260 deleteFibEntries(tx, identifier, (VrfEntry) vrfEntry);
265 public void update(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier, Object original,
266 Object update, List<SubTransaction> transactionObjects) {
267 this.transactionObjects = transactionObjects;
268 if ((original instanceof VrfEntry) && (update instanceof VrfEntry)) {
269 createFibEntries(tx, identifier, (VrfEntry)update);
274 public int getBatchSize() {
279 public int getBatchInterval() {
280 return batchInterval;
284 public LogicalDatastoreType getDatastoreType() {
285 return LogicalDatastoreType.CONFIGURATION;
288 private void createFibEntries(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
289 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
291 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
292 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
293 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
295 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
296 final Long vpnId = vpnInstance.getVpnId();
297 final String rd = vrfTableKey.getRouteDistinguisher();
298 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
299 if (subnetRoute != null) {
300 final long elanTag = subnetRoute.getElantag();
301 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
302 rd, vrfEntry.getDestPrefix(), elanTag);
303 if (vpnToDpnList != null) {
304 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
305 dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(),
306 new Callable<List<ListenableFuture<Void>>>() {
308 public List<ListenableFuture<Void>> call() throws Exception {
309 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
310 for (final VpnToDpnList curDpn : vpnToDpnList) {
311 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
312 installSubnetRouteInFib(curDpn.getDpnId(), elanTag, rd, vpnId.longValue(), vrfEntry, tx);
315 List<ListenableFuture<Void>> futures = new ArrayList<>();
316 futures.add(tx.submit());
323 // ping responder for router interfaces
324 if (installRouterFibEntries(vrfEntry, vpnToDpnList, vpnId, NwConstants.ADD_FLOW)) {
328 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.INTERVPN) {
329 // When it is a leaked route, the LFIB and FIB goes a bit different.
330 installInterVpnRouteInLFib(rd, vrfEntry);
334 final List<BigInteger> localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry);
336 if (vpnToDpnList != null) {
337 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
338 dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(),
339 new Callable<List<ListenableFuture<Void>>>() {
341 public List<ListenableFuture<Void>> call() throws Exception {
342 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
343 for (VpnToDpnList vpnDpn : vpnToDpnList) {
344 if ( !localDpnIdList.contains(vpnDpn.getDpnId())) {
345 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
346 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
350 List<ListenableFuture<Void>> futures = new ArrayList<>();
351 futures.add(tx.submit());
357 Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(dataBroker, rd);
358 if ( optVpnUuid.isPresent() ) {
359 Optional<InterVpnLinkDataComposite> optInterVpnLink = InterVpnLinkCache.getInterVpnLinkByVpnId(optVpnUuid.get());
360 LOG.debug("InterVpnLink {} found in Cache: {}", optVpnUuid.get(), optInterVpnLink.isPresent());
361 if ( optInterVpnLink.isPresent() ) {
362 InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
363 String vpnUuid = optVpnUuid.get();
364 String routeNexthop = vrfEntry.getNextHopAddressList().get(0);
365 if ( interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid) ) {
366 // This is an static route that points to the other endpoint of an InterVpnLink
367 // In that case, we should add another entry in FIB table pointing to LPortDispatcher table.
368 installRouteInInterVpnLink(interVpnLink, vpnUuid, vrfEntry, vpnId);
369 installInterVpnRouteInLFib(rd, vrfEntry);
377 Please note that the following createFibEntries will be invoked only for BGP Imported Routes.
378 The invocation of the following method is via create() callback from the MDSAL Batching Infrastructure
379 provided by ResourceBatchingManager
381 private void createFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
382 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
384 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
385 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
386 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
388 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
389 final String rd = vrfTableKey.getRouteDistinguisher();
390 if (vpnToDpnList != null) {
391 for (VpnToDpnList vpnDpn : vpnToDpnList) {
392 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
393 createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, writeTx);
399 // FIXME: Refactoring needed here.
400 // This kind of logic must be taken to an 'upper' layer like BgpManager or VpnManager
401 private void leakRouteIfNeeded(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry,
403 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
404 final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
406 String rd = vrfTableKey.getRouteDistinguisher();
407 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
408 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
409 if (vpnInstance == null) {
410 LOG.error("Vpn Instance not available for external route with prefix {} label {} nexthop {}. Returning...", vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList());
414 Preconditions.checkNotNull(vpnInstance,
415 "Vpn Instance not available with rd " + vrfTableKey.getRouteDistinguisher());
417 String vpnUuid = vpnInstance.getVpnInstanceName();
418 Preconditions.checkArgument(vpnUuid != null && !vpnUuid.isEmpty(),
419 "Could not find suitable VPN UUID for Route-Distinguisher=" + rd);
421 // if the new vrfEntry has been learned by Quagga BGP, its necessary to check if it's
422 // there an interVpnLink for the involved vpn in order to make learn the new route to
423 // the other part of the inter-vpn-link.
425 // For leaking, we need the InterVpnLink to be active. For removal, we just need a InterVpnLink.
426 Optional<InterVpnLink> interVpnLink =
427 (addOrRemove == NwConstants.ADD_FLOW) ? FibUtil.getActiveInterVpnLinkFromRd(dataBroker, rd)
428 : FibUtil.getInterVpnLinkByRd(dataBroker, rd);
429 if ( !interVpnLink.isPresent() ) {
430 LOG.debug("Could not find an InterVpnLink for Route-Distinguisher={}", rd);
434 // Ok, at this point everything is ready for the leaking/removal... but should it be performed?
435 // For removal, we remove all leaked routes, but we only leak a route if the corresponding flag is enabled.
437 (addOrRemove == NwConstants.DEL_FLOW) || ( RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP
438 && interVpnLink.get().isBgpRoutesLeaking() );
441 String theOtherVpnId = interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid)
442 ? interVpnLink.get().getSecondEndpoint().getVpnUuid().getValue()
445 String dstVpnRd = FibUtil.getVpnRd(dataBroker, theOtherVpnId);
446 String endpointIp = vrfEntry.getNextHopAddressList().get(0);
448 InstanceIdentifier<VrfEntry> vrfEntryIidInOtherVpn =
449 InstanceIdentifier.builder(FibEntries.class)
450 .child(VrfTables.class, new VrfTablesKey(dstVpnRd))
451 .child(VrfEntry.class, new VrfEntryKey(vrfEntry.getDestPrefix()))
453 if ( addOrRemove == NwConstants.ADD_FLOW ) {
454 LOG.debug("Leaking route (destination={}, nexthop={}) from Vrf={} to Vrf={}",
455 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), rd, dstVpnRd);
456 String key = rd + FibConstants.SEPARATOR + vrfEntry.getDestPrefix();
457 long label = FibUtil.getUniqueId(idManager, FibConstants.VPN_IDPOOL_NAME, key);
458 VrfEntry newVrfEntry = new VrfEntryBuilder(vrfEntry).setNextHopAddressList(Arrays.asList(endpointIp))
460 .setOrigin(RouteOrigin.INTERVPN.getValue())
462 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn, newVrfEntry);
464 LOG.debug("Removing leaked vrfEntry={}", vrfEntryIidInOtherVpn.toString());
465 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn);
470 private Prefixes updateVpnReferencesInLri(LabelRouteInfo lri, String vpnInstanceName, boolean isPresentInList) {
471 LOG.debug("updating LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
472 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
473 prefixBuilder.setDpnId(lri.getDpnId());
474 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
475 prefixBuilder.setIpAddress(lri.getPrefix());
476 // Increment the refCount here
477 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
478 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long)lri.getLabel())).build();
479 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri);
480 if (!isPresentInList) {
481 LOG.debug("vpnName {} is not present in LRI with label {}..", vpnInstanceName, lri.getLabel());
482 List<String> vpnInstanceNames = lri.getVpnInstanceList();
483 vpnInstanceNames.add(vpnInstanceName);
484 builder.setVpnInstanceList(vpnInstanceNames);
485 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(), FibUtil.DEFAULT_CALLBACK);
487 LOG.debug("vpnName {} is present in LRI with label {}..", vpnInstanceName, lri.getLabel());
489 return prefixBuilder.build();
492 private void installSubnetRouteInFib(final BigInteger dpnId, final long elanTag, final String rd,
493 final long vpnId, final VrfEntry vrfEntry, WriteTransaction tx){
494 Boolean wrTxPresent = true;
497 tx = dataBroker.newWriteOnlyTransaction();
499 synchronized (vrfEntry.getLabel().toString().intern()) {
500 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
501 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
502 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
504 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
505 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
506 if (vpnInstanceOpDataEntryOptional.isPresent()) {
507 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
508 if (!lri.getVpnInstanceList().contains(vpnInstanceName)) {
509 updateVpnReferencesInLri(lri, vpnInstanceName, false);
513 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
514 vrfEntry.getLabel(), lri.getVpnInterfaceName(), lri.getDpnId());
517 final List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
518 BigInteger subnetRouteMeta = ((BigInteger.valueOf(elanTag)).shiftLeft(32)).or((BigInteger.valueOf(vpnId).shiftLeft(1)));
519 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE }));
520 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
521 makeConnectedRoute(dpnId,vpnId,vrfEntry,rd,instructions,NwConstants.ADD_FLOW, tx);
523 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
524 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
525 // reinitialize instructions list for LFIB Table
526 final List<InstructionInfo> LFIBinstructions = new ArrayList<InstructionInfo>();
528 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
529 LFIBinstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
530 LFIBinstructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { subnetRouteMeta, MetaDataUtil.METADATA_MASK_SUBNET_ROUTE }));
531 LFIBinstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
533 makeLFibTableEntry(dpnId,vrfEntry.getLabel(), LFIBinstructions, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
540 private void installInterVpnRouteInLFib(final String rd, final VrfEntry vrfEntry) {
541 // INTERVPN routes are routes in a Vpn1 that have been leaked to Vpn2. In DC-GW, this Vpn2 route is pointing
542 // to a list of DPNs where Vpn2's VpnLink was instantiated. In these DPNs LFIB must be programmed so that the
543 // packet is commuted from Vpn2 to Vpn1.
544 Optional<String> vpnNameOpc = FibUtil.getVpnNameFromRd(dataBroker, rd);
545 if ( !vpnNameOpc.isPresent() ) {
546 LOG.warn("Could not find VpnInstanceName for Route-Distinguisher {}", rd);
550 String vpnName = vpnNameOpc.get();
551 List<InterVpnLink> interVpnLinks = FibUtil.getAllInterVpnLinks(dataBroker);
552 boolean interVpnLinkFound = false;
553 for ( InterVpnLink interVpnLink : interVpnLinks ) {
554 boolean vpnIs1stEndpoint = interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(vpnName);
555 boolean vpnIs2ndEndpoint = !vpnIs1stEndpoint
556 && interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(vpnName);
557 if ( vpnIs1stEndpoint || vpnIs2ndEndpoint ) {
558 interVpnLinkFound = true;
560 Optional<InterVpnLinkState> vpnLinkState = FibUtil.getInterVpnLinkState(dataBroker, interVpnLink.getName());
561 if ( !vpnLinkState.isPresent()
562 || !vpnLinkState.get().getState().equals(InterVpnLinkState.State.Active) ) {
563 LOG.warn("InterVpnLink {}, linking VPN {} and {}, is not in Active state",
564 interVpnLink.getName(), interVpnLink.getFirstEndpoint().getVpnUuid().getValue(),
565 interVpnLink.getSecondEndpoint().getVpnUuid().getValue() );
569 List<BigInteger> targetDpns = vpnIs1stEndpoint ? vpnLinkState.get().getFirstEndpointState().getDpId()
570 : vpnLinkState.get().getSecondEndpointState().getDpId();
571 Long lportTag = vpnIs1stEndpoint ? vpnLinkState.get().getSecondEndpointState().getLportTag()
572 : vpnLinkState.get().getFirstEndpointState().getLportTag();
574 for ( BigInteger dpId : targetDpns ) {
575 List<ActionInfo> actionsInfos = Arrays.asList(new ActionInfo(ActionType.pop_mpls, new String[]{}));
577 BigInteger[] metadata = new BigInteger[] {
578 MetaDataUtil.getMetaDataForLPortDispatcher(lportTag.intValue(), ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
579 MetaDataUtil.getMetaDataMaskForLPortDispatcher()
581 List<InstructionInfo> instructions =
582 Arrays.asList(new InstructionInfo(InstructionType.apply_actions, actionsInfos),
583 new InstructionInfo(InstructionType.write_metadata, metadata),
584 new InstructionInfo(InstructionType.goto_table,
585 new long[] { NwConstants.L3_INTERFACE_TABLE }));
587 makeLFibTableEntry(dpId, vrfEntry.getLabel(), instructions, LFIB_INTERVPN_PRIORITY,
588 NwConstants.ADD_FLOW, null);
595 if ( !interVpnLinkFound ) {
596 LOG.warn("VrfEntry=[prefix={} label={} nexthop={}] for VPN {} has origin INTERVPN but no InterVpnLink could be found",
597 vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList(), rd);
603 private void installRouteInInterVpnLink(final InterVpnLinkDataComposite interVpnLink, final String vpnUuid,
604 final VrfEntry vrfEntry, long vpnTag) {
605 Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
606 Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null
607 && vrfEntry.getNextHopAddressList().size() == 1);
608 String destination = vrfEntry.getDestPrefix();
609 String nextHop = vrfEntry.getNextHopAddressList().get(0);
610 String iVpnLinkName = interVpnLink.getInterVpnLinkName();
612 // After having received a static route, we should check if the vpn is part of an inter-vpn-link.
613 // In that case, we should populate the FIB table of the VPN pointing to LPortDisptacher table
614 // using as metadata the LPortTag associated to that vpn in the inter-vpn-link.
615 if ( interVpnLink.getState().or(State.Error) != State.Active ) {
616 LOG.warn("Route to {} with nexthop={} cannot be installed because the interVpnLink {} is not active",
617 destination, nextHop, iVpnLinkName);
621 Optional<Long> optOtherEndpointLportTag = interVpnLink.getOtherEndpointLportTagByVpnName(vpnUuid);
622 if ( !optOtherEndpointLportTag.isPresent() ) {
623 LOG.warn("Could not find suitable LportTag for the endpoint opposite to vpn {} in interVpnLink {}",
624 vpnUuid, iVpnLinkName);
628 List<BigInteger> targetDpns = interVpnLink.getEndpointDpnsByVpnName(vpnUuid);
629 if ( targetDpns.isEmpty() ) {
630 LOG.warn("Could not find DPNs for endpoint opposite to vpn {} in interVpnLink {}", vpnUuid, iVpnLinkName);
634 BigInteger[] metadata = new BigInteger[] {
635 MetaDataUtil.getMetaDataForLPortDispatcher(optOtherEndpointLportTag.get().intValue(),
636 ServiceIndex.getIndex(NwConstants.L3VPN_SERVICE_NAME, NwConstants.L3VPN_SERVICE_INDEX)),
637 MetaDataUtil.getMetaDataMaskForLPortDispatcher()
639 List<Instruction> instructions =
640 Arrays.asList(new InstructionInfo(InstructionType.write_metadata, metadata).buildInstruction(0),
641 new InstructionInfo(InstructionType.goto_table,
642 new long[] { NwConstants.L3_INTERFACE_TABLE }).buildInstruction(1));
644 String values[] = destination.split("/");
645 String destPrefixIpAddress = values[0];
646 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
648 List<MatchInfo> matches = new ArrayList<>();
649 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] { MetaDataUtil.getVpnIdMetadata(vpnTag),
650 MetaDataUtil.METADATA_MASK_VRFID }));
651 matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_IPV4 }));
653 if (prefixLength != 0) {
654 matches.add(new MatchInfo(MatchFieldType.ipv4_destination,
655 new String[] { destPrefixIpAddress, Integer.toString(prefixLength) }));
658 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
659 String flowRef = getInterVpnFibFlowRef(iVpnLinkName, destination, nextHop);
660 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
661 COOKIE_VM_FIB_TABLE, matches, instructions);
663 for ( BigInteger dpId : targetDpns ) {
664 mdsalManager.installFlow(dpId, flowEntity);
668 private void removeRouteFromInterVpnLink(final InterVpnLinkDataComposite interVpnLink, final String vpnUuid,
669 final VrfEntry vrfEntry) {
671 Preconditions.checkNotNull(interVpnLink, "InterVpnLink cannot be null");
672 Preconditions.checkArgument(vrfEntry.getNextHopAddressList() != null
673 && vrfEntry.getNextHopAddressList().size() == 1);
675 String iVpnLinkName = interVpnLink.getInterVpnLinkName();
677 InterVpnLinkState interVpnLinkState = interVpnLink.getInterVpnLinkState();
678 if ( interVpnLinkState == null ) {
679 LOG.warn("Could not find State for InterVpnLink {}", iVpnLinkName);
683 String nextHop = vrfEntry.getNextHopAddressList().get(0);
684 String flowRef = getInterVpnFibFlowRef(iVpnLinkName, vrfEntry.getDestPrefix(), nextHop);
685 FlowId flowId = new FlowId(flowRef);
686 Flow flow = new FlowBuilder().setKey(new FlowKey(flowId)).setId(flowId).setTableId(NwConstants.L3_FIB_TABLE)
687 .setFlowName(flowRef).build();
689 for ( BigInteger dpId : interVpnLink.getEndpointDpnsByVpnName(vpnUuid) ) {
690 mdsalManager.removeFlow(dpId, flow);
695 private <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
696 InstanceIdentifier<T> path) {
698 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
700 Optional<T> result = Optional.absent();
702 result = tx.read(datastoreType, path).get();
703 } catch (Exception e) {
704 throw new RuntimeException(e);
710 private List<BigInteger> createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
711 List<BigInteger> returnLocalDpnId = new ArrayList<>();
712 Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
713 String localNextHopIP = vrfEntry.getDestPrefix();
715 if (localNextHopInfo == null) {
716 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
717 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
718 if (extraRoute != null) {
719 for (String nextHopIp : extraRoute.getNexthopIpList()) {
720 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
721 if (nextHopIp != null) {
722 localNextHopInfo = getPrefixToInterface(vpnId, nextHopIp + "/32");
723 localNextHopIP = nextHopIp + "/32";
724 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, vpnId);
725 returnLocalDpnId.add(dpnId);
729 if (localNextHopInfo == null) {
730 /* imported routes case */
731 synchronized (vrfEntry.getLabel().toString().intern()) {
732 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
733 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
734 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
735 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) {
736 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
737 if (vpnInstanceOpDataEntryOptional.isPresent()) {
738 String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
739 if (lri.getVpnInstanceList().contains(vpnInstanceName)) {
740 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, true);
741 localNextHopIP = lri.getPrefix();
743 localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, false);
744 localNextHopIP = lri.getPrefix();
747 if (localNextHopInfo != null) {
748 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
749 vrfEntry.getLabel(), localNextHopInfo.getVpnInterfaceName(), lri.getDpnId());
750 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, lri.getParentVpnid());
751 returnLocalDpnId.add(dpnId);
758 BigInteger dpnId = checkCreateLocalFibEntry(localNextHopInfo, localNextHopIP, vpnId, rd, vrfEntry, vpnId);
759 returnLocalDpnId.add(dpnId);
762 return returnLocalDpnId;
765 private BigInteger checkCreateLocalFibEntry(Prefixes localNextHopInfo, String localNextHopIP, final Long vpnId, final String rd,
766 final VrfEntry vrfEntry, Long parentVpnId){
767 if (localNextHopInfo != null) {
768 final BigInteger dpnId = localNextHopInfo.getDpnId();
769 if (!isVpnPresentInDpn(rd, dpnId)) {
770 LOG.error("The vpnName with vpnId {} rd {} is not available on dpn {}", vpnId, rd, dpnId.toString());
771 return BigInteger.ZERO;
774 final long groupId = nextHopManager.createLocalNextHop(parentVpnId, dpnId,
775 localNextHopInfo.getVpnInterfaceName(), localNextHopIP, vrfEntry.getDestPrefix());
777 LOG.error("Unable to create Group for local prefix {} on rd {} for vpninterface {} on Node {}",
778 vrfEntry.getDestPrefix(), rd, localNextHopInfo.getVpnInterfaceName(), dpnId.toString());
779 return BigInteger.ZERO;
781 List<ActionInfo> actionsInfos =
782 Arrays.asList(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
783 final List<InstructionInfo> instructions =
784 Arrays.asList(new InstructionInfo(InstructionType.write_actions, actionsInfos));
785 actionsInfos = Arrays.asList(new ActionInfo(ActionType.pop_mpls, new String[]{}),
786 new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }) );
787 final List<InstructionInfo> lfibinstructions = Arrays.asList(new InstructionInfo(InstructionType.write_actions, actionsInfos));
788 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
789 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
790 dpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
792 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);
794 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
795 dataStoreCoordinator.enqueueJob("FIB"+vpnId.toString()+dpnId.toString()+vrfEntry.getDestPrefix(),
796 new Callable<List<ListenableFuture<Void>>>() {
798 public List<ListenableFuture<Void>> call() throws Exception {
799 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
800 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
801 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
802 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), lfibinstructions , DEFAULT_FIB_FLOW_PRIORITY, NwConstants.ADD_FLOW, tx);
803 makeTunnelTableEntry(dpnId, vrfEntry.getLabel(), groupId, tx);
805 List<ListenableFuture<Void>> futures = new ArrayList<>();
806 futures.add(tx.submit());
812 return BigInteger.ZERO;
815 private boolean isVpnPresentInDpn(String rd, BigInteger dpnId) {
816 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
817 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
818 if (dpnInVpn.isPresent()) {
824 private LabelRouteInfo getLabelRouteInfo(Long label) {
825 InstanceIdentifier<LabelRouteInfo>lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
826 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long)label)).build();
827 Optional<LabelRouteInfo> opResult = read(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid);
828 if (opResult.isPresent()) {
829 return opResult.get();
834 private boolean deleteLabelRouteInfo(LabelRouteInfo lri, String vpnInstanceName) {
835 LOG.debug("deleting LRI : for label {} vpninstancename {}", lri.getLabel(), vpnInstanceName);
836 InstanceIdentifier<LabelRouteInfo> lriId = InstanceIdentifier.builder(LabelRouteMap.class)
837 .child(LabelRouteInfo.class, new LabelRouteInfoKey((long) lri.getLabel())).build();
841 List<String> vpnInstancesList = lri.getVpnInstanceList() != null ? lri.getVpnInstanceList() : new ArrayList<String>();
842 if (vpnInstancesList.contains(vpnInstanceName)) {
843 LOG.debug("vpninstance {} name is present", vpnInstanceName);
844 vpnInstancesList.remove(vpnInstanceName);
846 if (vpnInstancesList.size() == 0) {
847 LOG.debug("deleting LRI instance object for label {}", lri.getLabel());
848 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId);
851 LOG.debug("updating LRI instance object for label {}", lri.getLabel());
852 LabelRouteInfoBuilder builder = new LabelRouteInfoBuilder(lri).setVpnInstanceList(vpnInstancesList);
853 FibUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build(), FibUtil.DEFAULT_CALLBACK);
858 private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/,
859 WriteTransaction tx) {
860 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
861 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
864 createTerminatingServiceActions(dpId, (int)label, actionsInfos, tx);
866 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully",
867 dpId, label, groupId);
870 public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos,
871 WriteTransaction tx) {
872 List<MatchInfo> mkMatches = new ArrayList<>();
874 LOG.debug("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
877 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
878 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
880 List<InstructionInfo> mkInstructions = new ArrayList<>();
881 mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
883 FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
884 getTableMissFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
885 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
887 FlowKey flowKey = new FlowKey( new FlowId(terminatingServiceTableFlowEntity.getFlowId()) );
889 FlowBuilder flowbld = terminatingServiceTableFlowEntity.getFlowBuilder();
891 Node nodeDpn = buildDpnNode(terminatingServiceTableFlowEntity.getDpnId());
892 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
893 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
894 .child(Table.class, new TableKey(terminatingServiceTableFlowEntity.getTableId())).child(Flow.class,flowKey).build();
895 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flowbld.build(),true );
898 private void removeTunnelTableEntry(BigInteger dpId, long label, WriteTransaction tx) {
899 FlowEntity flowEntity;
900 LOG.debug("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
901 List<MatchInfo> mkMatches = new ArrayList<>();
903 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
904 flowEntity = MDSALUtil.buildFlowEntity(dpId,
905 NwConstants.INTERNAL_TUNNEL_TABLE,
906 getTableMissFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
907 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
908 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
909 Node nodeDpn = buildDpnNode(flowEntity.getDpnId());
910 FlowKey flowKey = new FlowKey(new FlowId(flowEntity.getFlowId()));
911 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
912 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
913 .child(Table.class, new TableKey(flowEntity.getTableId())).child(Flow.class, flowKey).build();
915 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
916 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully", dpId, label);
920 * Delete local FIB entry
926 public List<BigInteger> deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
927 List<BigInteger> returnLocalDpnId = new ArrayList<>();
928 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
929 String localNextHopIP = vrfEntry.getDestPrefix();
931 if (localNextHopInfo == null) {
932 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
933 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
934 if (extra_route != null) {
935 for (String nextHopIp : extra_route.getNexthopIpList()) {
936 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
937 if (nextHopIp != null) {
938 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp + "/32");
939 localNextHopIP = nextHopIp + "/32";
940 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
941 vpnId, rd, vrfEntry, true /*isExtraRoute*/);
942 if (!dpnId.equals(BigInteger.ZERO)) {
943 returnLocalDpnId.add(dpnId);
949 if (localNextHopInfo == null) {
950 /* Imported VRF entry */
951 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
952 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
953 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
954 VpnNexthopBuilder vpnNexthopBuilder = new VpnNexthopBuilder();
955 vpnNexthopBuilder.setDpnId(lri.getDpnId());
956 BigInteger dpnId = checkDeleteLocalFibEntry(vpnNexthopBuilder.build(), localNextHopIP,
957 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
958 if (!dpnId.equals(BigInteger.ZERO)) {
959 returnLocalDpnId.add(dpnId);
966 BigInteger dpnId = checkDeleteLocalFibEntry(localNextHopInfo, localNextHopIP,
967 vpnId, rd, vrfEntry, false /*isExtraRoute*/);
968 if (!dpnId.equals(BigInteger.ZERO)) {
969 returnLocalDpnId.add(dpnId);
973 return returnLocalDpnId;
976 private BigInteger checkDeleteLocalFibEntry(VpnNexthop localNextHopInfo, final String localNextHopIP,
977 final Long vpnId, final String rd,
978 final VrfEntry vrfEntry, final boolean isExtraRoute) {
979 if (localNextHopInfo != null) {
980 final BigInteger dpnId = localNextHopInfo.getDpnId();;
981 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
982 dataStoreCoordinator.enqueueJob("FIB"+vpnId.toString()+dpnId.toString()+vrfEntry.getDestPrefix(),
983 new Callable<List<ListenableFuture<Void>>>() {
985 public List<ListenableFuture<Void>> call() throws Exception {
986 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
987 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null /* instructions */,
988 NwConstants.DEL_FLOW, tx);
989 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
990 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null /* instructions */,
991 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
992 removeTunnelTableEntry(dpnId, vrfEntry.getLabel(), tx);
994 List<ListenableFuture<Void>> futures = new ArrayList<>();
995 futures.add(tx.submit());
999 //TODO: verify below adjacency call need to be optimized (?)
1000 deleteLocalAdjacency(dpnId, vpnId, localNextHopIP, vrfEntry.getDestPrefix());
1003 return BigInteger.ZERO;
1007 private InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) {
1008 return InstanceIdentifier.builder(PrefixToInterface.class)
1009 .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
1012 private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
1013 Optional<Prefixes> localNextHopInfoData =
1014 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
1015 return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
1018 private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
1019 return InstanceIdentifier.builder(VpnToExtraroute.class)
1020 .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class,
1021 new ExtrarouteKey(ipPrefix)).build();
1024 private Extraroute getVpnToExtraroute(String rd, String ipPrefix) {
1025 Optional<Extraroute> extraRouteInfo =
1026 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix));
1027 return extraRouteInfo.isPresent() ? extraRouteInfo.get() : null;
1031 private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
1033 Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
1034 new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
1035 RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
1036 if(!rpcResult.isSuccessful()) {
1037 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
1039 return rpcResult.getResult().getTunnelType();
1042 } catch (InterruptedException | ExecutionException e) {
1043 LOG.warn("Exception when getting tunnel interface Id for tunnel type", e);
1049 private void createRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, final VrfTablesKey vrfTableKey,
1050 final VrfEntry vrfEntry, WriteTransaction tx) {
1051 Boolean wrTxPresent = true;
1053 wrTxPresent = false;
1054 tx = dataBroker.newWriteOnlyTransaction();
1056 String rd = vrfTableKey.getRouteDistinguisher();
1057 LOG.debug( "createremotefibentry: adding route {} for rd {} with transaction {}",
1058 vrfEntry.getDestPrefix(), rd, tx);
1059 /********************************************/
1060 List<String> tunnelInterfaceList = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
1062 if (tunnelInterfaceList.isEmpty()) {
1063 LOG.error("Could not get interface for nexthop: {} in vpn {}",
1064 vrfEntry.getNextHopAddressList(), rd);
1065 LOG.warn("Failed to add Route: {} in vpn: {}",
1066 vrfEntry.getDestPrefix(), rd);
1070 for (String tunnelInterface : tunnelInterfaceList) {
1071 List<InstructionInfo> instructions = new ArrayList<>();
1072 List<ActionInfo> actionInfos = new ArrayList<>();
1073 Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
1074 if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
1075 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
1076 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[]{null}));
1077 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[]{Long.toString(vrfEntry.getLabel())}));
1079 int label = vrfEntry.getLabel().intValue();
1080 BigInteger tunnelId;
1081 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
1082 if (tunnel_type.equals(TunnelTypeVxlan.class)) {
1083 tunnelId = BigInteger.valueOf(label);
1085 tunnelId = BigInteger.valueOf(label);
1088 LOG.debug("adding set tunnel id action for label {}", label);
1089 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{tunnelId}));
1091 List<ActionInfo> egressActions = nextHopManager.getEgressActionsForInterface(tunnelInterface);
1092 if(egressActions.isEmpty()){
1093 LOG.error("Failed to retrieve egress action for prefix {} nextHop {} interface {}. Aborting remote FIB entry creation.", vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), tunnelInterface);
1096 actionInfos.addAll(egressActions);
1097 instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
1098 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx);
1103 LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
1106 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
1107 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
1108 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1109 if (dpnInVpn.isPresent()) {
1110 List<VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
1111 VpnInterfaces currVpnInterface = new VpnInterfacesBuilder().setInterfaceName(intfName).build();
1113 if (vpnInterfaces.remove(currVpnInterface)) {
1114 if (vpnInterfaces.isEmpty()) {
1115 LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
1116 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1117 cleanUpDpnForVpn(dpnId, vpnId, rd, null);
1119 LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
1120 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id.child(
1121 VpnInterfaces.class,
1122 new VpnInterfacesKey(intfName)));
1128 private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
1129 /* Get interface info from prefix to interface mapping;
1130 Use the interface info to get the corresponding vpn interface op DS entry,
1131 remove the adjacency corresponding to this fib entry.
1132 If adjacency removed is the last adjacency, clean up the following:
1133 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
1134 - prefix to interface entry
1135 - vpn interface op DS
1137 LOG.debug("Cleanup of prefix {} in VPN {}", vrfEntry.getDestPrefix(), vpnId);
1138 Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
1139 Extraroute extraRoute = null;
1140 if (prefixInfo == null) {
1141 extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1142 if(extraRoute != null) {
1143 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1144 LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp);
1146 if (nextHopIp != null) {
1147 prefixInfo = getPrefixToInterface(vpnId, nextHopIp + "/32");
1148 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1152 if (prefixInfo == null) {
1153 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1154 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
1155 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1156 PrefixesBuilder prefixBuilder = new PrefixesBuilder();
1157 prefixBuilder.setDpnId(lri.getDpnId());
1158 prefixBuilder.setVpnInterfaceName(lri.getVpnInterfaceName());
1159 prefixBuilder.setIpAddress(lri.getPrefix());
1160 prefixInfo = prefixBuilder.build();
1161 LOG.debug("Fetched labelRouteInfo for label {} interface {} and got dpn {}",
1162 vrfEntry.getLabel(), prefixInfo.getVpnInterfaceName(), lri.getDpnId());
1163 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1167 checkCleanUpOpDataForFib(prefixInfo, vpnId, rd, vrfEntry, extraRoute);
1171 private void checkCleanUpOpDataForFib(final Prefixes prefixInfo, final Long vpnId, final String rd,
1172 final VrfEntry vrfEntry, final Extraroute extraRoute) {
1174 if (prefixInfo == null) {
1175 LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for prefix {}", vrfEntry.getDestPrefix());
1176 return; //Don't have any info for this prefix (shouldn't happen); need to return
1179 String ifName = prefixInfo.getVpnInterfaceName();
1180 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1181 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + ifName,
1182 new CleanupVpnInterfaceWorker(prefixInfo, vpnId, rd, vrfEntry, extraRoute));
1185 private class CleanupVpnInterfaceWorker implements Callable<List<ListenableFuture<Void>>> {
1186 Prefixes prefixInfo;
1190 Extraroute extraRoute;
1192 public CleanupVpnInterfaceWorker(final Prefixes prefixInfo, final Long vpnId, final String rd,
1193 final VrfEntry vrfEntry, final Extraroute extraRoute) {
1194 this.prefixInfo = prefixInfo;
1197 this.vrfEntry= vrfEntry;
1198 this.extraRoute = extraRoute;
1202 public List<ListenableFuture<Void>> call() throws Exception {
1203 // If another renderer(for eg : CSS) needs to be supported, check can be performed here
1204 // to call the respective helpers.
1206 //First Cleanup LabelRouteInfo
1207 synchronized (vrfEntry.getLabel().toString().intern()) {
1208 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1209 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) &&
1210 vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1211 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
1212 String vpnInstanceName = "";
1213 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1214 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1216 boolean lriRemoved = deleteLabelRouteInfo(lri, vpnInstanceName);
1218 String parentRd = lri.getParentVpnRd();
1219 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1220 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1223 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1224 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1227 String ifName = prefixInfo.getVpnInterfaceName();
1228 Optional<VpnInterface> optvpnInterface = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1229 FibUtil.getVpnInterfaceIdentifier(ifName));
1230 if (optvpnInterface.isPresent()) {
1231 long associatedVpnId = FibUtil.getVpnId(dataBroker, optvpnInterface.get().getVpnInstanceName());
1232 if (vpnId != associatedVpnId) {
1233 LOG.warn("Prefixes {} are associated with different vpn instance with id : {} rather than {}",
1234 vrfEntry.getDestPrefix(), associatedVpnId, vpnId);
1235 LOG.warn("Not proceeding with Cleanup op data for prefix {}", vrfEntry.getDestPrefix());
1238 LOG.debug("Processing cleanup of prefix {} associated with vpn {}",
1239 vrfEntry.getDestPrefix(), associatedVpnId);
1242 if (extraRoute != null) {
1243 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1244 FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
1246 Optional<Adjacencies> optAdjacencies = FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1247 FibUtil.getAdjListPath(ifName));
1249 if (optAdjacencies.isPresent()) {
1250 numAdj = optAdjacencies.get().getAdjacency().size();
1252 //remove adjacency corr to prefix
1254 LOG.info("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix());
1255 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1256 FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
1258 if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
1259 //clean up the vpn interface from DpnToVpn list
1260 LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
1261 FibUtil.delete(dataBroker, LogicalDatastoreType.OPERATIONAL,
1262 FibUtil.getVpnInterfaceIdentifier(ifName));
1268 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1269 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1270 final String rd = vrfTableKey.getRouteDistinguisher();
1271 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1272 if (vpnInstance == null) {
1273 LOG.error("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1276 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1278 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1279 if (subnetRoute != null) {
1280 elanTag = subnetRoute.getElantag();
1281 LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
1282 rd, vrfEntry.getDestPrefix(), elanTag);
1283 if (vpnToDpnList != null) {
1284 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1285 dataStoreCoordinator.enqueueJob("FIB" + rd.toString() + vrfEntry.getDestPrefix(),
1286 new Callable<List<ListenableFuture<Void>>>() {
1288 public List<ListenableFuture<Void>> call() throws Exception {
1289 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1291 for (final VpnToDpnList curDpn : vpnToDpnList) {
1293 makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry,
1294 vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW, tx);
1295 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) {
1296 makeLFibTableEntry(curDpn.getDpnId(), vrfEntry.getLabel(), null,
1297 DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1300 List<ListenableFuture<Void>> futures = new ArrayList<>();
1301 futures.add(tx.submit());
1306 synchronized (vrfEntry.getLabel().toString().intern()) {
1307 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1308 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) && vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1309 Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional = FibUtil.getVpnInstanceOpData(dataBroker, rd);
1310 String vpnInstanceName = "";
1311 if (vpnInstanceOpDataEntryOptional.isPresent()) {
1312 vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName();
1314 boolean lriRemoved = this.deleteLabelRouteInfo(lri, vpnInstanceName);
1316 String parentRd = lri.getParentVpnRd();
1317 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1318 FibUtil.getNextHopLabelKey(parentRd, vrfEntry.getDestPrefix()));
1319 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {} as labelRouteInfo cleared", vrfEntry.getLabel(), rd,
1320 vrfEntry.getDestPrefix());
1323 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
1324 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
1325 LOG.trace("deleteFibEntries: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd,
1326 vrfEntry.getDestPrefix());
1331 if (installRouterFibEntries(vrfEntry, vpnToDpnList, vpnInstance.getVpnId(), NwConstants.DEL_FLOW)) {
1335 final List<BigInteger> localDpnIdList = deleteLocalFibEntry(vpnInstance.getVpnId(),
1336 vrfTableKey.getRouteDistinguisher(), vrfEntry);
1337 if (vpnToDpnList != null) {
1338 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1339 dataStoreCoordinator.enqueueJob("FIB" + rd.toString() + vrfEntry.getDestPrefix(),
1340 new Callable<List<ListenableFuture<Void>>>() {
1342 public List<ListenableFuture<Void>> call() throws Exception {
1343 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1345 if (localDpnIdList.size() <= 0) {
1346 for (VpnToDpnList curDpn : vpnToDpnList) {
1347 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1348 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1349 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1352 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1356 for (BigInteger localDpnId : localDpnIdList) {
1357 for (VpnToDpnList curDpn : vpnToDpnList) {
1358 if (!curDpn.getDpnId().equals(localDpnId)) {
1359 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1360 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1361 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1364 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
1370 List<ListenableFuture<Void>> futures = new ArrayList<>();
1371 futures.add(tx.submit());
1377 //The flow/group entry has been deleted from config DS; need to clean up associated operational
1378 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
1379 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
1381 // Remove all fib entries configured due to interVpnLink, when nexthop is the opposite endPoint
1382 // of the interVpnLink.
1383 Optional<String> optVpnUuid = FibUtil.getVpnNameFromRd(this.dataBroker, rd);
1384 if ( optVpnUuid.isPresent() ) {
1385 String vpnUuid = optVpnUuid.get();
1386 List<String> routeNexthoplist = vrfEntry.getNextHopAddressList();
1387 if(routeNexthoplist.isEmpty()) {
1388 LOG.trace("NextHopList is empty for VrfEntry {}", vrfEntry);
1391 String routeNexthop = routeNexthoplist.get(0);
1392 Optional<InterVpnLinkDataComposite> optInterVpnLink = InterVpnLinkCache.getInterVpnLinkByVpnId(vpnUuid);
1393 if ( optInterVpnLink.isPresent() ) {
1394 InterVpnLinkDataComposite interVpnLink = optInterVpnLink.get();
1395 if ( interVpnLink.isIpAddrTheOtherVpnEndpoint(routeNexthop, vpnUuid))
1397 // This is route that points to the other endpoint of an InterVpnLink
1398 // In that case, we should look for the FIB table pointing to LPortDispatcher table and remove it.
1399 removeRouteFromInterVpnLink(interVpnLink, rd, vrfEntry);
1407 Please note that the following deleteFibEntries will be invoked only for BGP Imported Routes.
1408 The invocation of the following method is via delete() callback from the MDSAL Batching Infrastructure
1409 provided by ResourceBatchingManager
1411 private void deleteFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
1412 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
1414 final String rd = vrfTableKey.getRouteDistinguisher();
1415 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
1416 if (vpnInstance == null) {
1417 LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
1420 final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
1421 if (vpnToDpnList != null) {
1422 for (VpnToDpnList curDpn : vpnToDpnList) {
1423 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
1424 deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, writeTx);
1430 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
1431 final long vpnId, final VrfTablesKey vrfTableKey,
1432 final VrfEntry vrfEntry, WriteTransaction tx) {
1434 Boolean wrTxPresent = true;
1436 wrTxPresent = false;
1437 tx = dataBroker.newWriteOnlyTransaction();
1440 LOG.debug("deleting route: prefix={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
1441 String rd = vrfTableKey.getRouteDistinguisher();
1443 if(localDpnId != null) {
1444 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
1445 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1449 // below two reads are kept as is, until best way is found to identify dpnID
1450 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
1451 Extraroute extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1453 if (localNextHopInfo == null && extraRoute != null) {
1454 // Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
1455 for (String nextHopIp : extraRoute.getNexthopIpList()) {
1456 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, nextHopIp);
1457 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1460 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx);
1467 private boolean checkDpnDeleteFibEntry(VpnNexthop localNextHopInfo, BigInteger remoteDpnId, long vpnId,
1468 VrfEntry vrfEntry, String rd, WriteTransaction tx){
1469 boolean isRemoteRoute = true;
1470 if (localNextHopInfo != null) {
1471 isRemoteRoute = !remoteDpnId.equals(localNextHopInfo.getDpnId());
1473 if (isRemoteRoute) {
1474 deleteFibEntry(remoteDpnId, vpnId, vrfEntry, rd, tx);
1477 LOG.debug("Did not delete FIB entry: rd={}, vrfEntry={}, as it is local to dpnId={}", rd, vrfEntry.getDestPrefix(), remoteDpnId);
1482 private void deleteFibEntry(BigInteger remoteDpnId, long vpnId, VrfEntry vrfEntry, String rd, WriteTransaction tx){
1483 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1484 LOG.debug("Successfully delete FIB entry: vrfEntry={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
1488 (byte[] rawIpAddress) {
1489 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
1490 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
1493 private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
1494 List<InstructionInfo> instructions, int addOrRemove, WriteTransaction tx) {
1495 Boolean wrTxPresent = true;
1497 wrTxPresent = false;
1498 tx = dataBroker.newWriteOnlyTransaction();
1501 LOG.trace("makeConnectedRoute: vrfEntry {}", vrfEntry);
1502 String values[] = vrfEntry.getDestPrefix().split("/");
1503 String ipAddress = values[0];
1504 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
1505 if (addOrRemove == NwConstants.ADD_FLOW) {
1506 LOG.debug("Adding route to DPN {} for rd {} prefix {} ", dpId, rd, vrfEntry.getDestPrefix());
1508 LOG.debug("Removing route from DPN {} for rd {} prefix {}", dpId, rd, vrfEntry.getDestPrefix());
1510 InetAddress destPrefix;
1512 destPrefix = InetAddress.getByName(ipAddress);
1513 } catch (UnknownHostException e) {
1514 LOG.error("Failed to get destPrefix for prefix {} ", vrfEntry.getDestPrefix(), e);
1518 List<MatchInfo> matches = new ArrayList<>();
1520 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
1521 MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
1523 matches.add(new MatchInfo(MatchFieldType.eth_type,
1524 new long[] { NwConstants.ETHTYPE_IPV4 }));
1526 if(prefixLength != 0) {
1527 matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
1528 destPrefix.getHostAddress(), Integer.toString(prefixLength)}));
1530 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
1531 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, priority, destPrefix);
1532 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef, 0, 0,
1533 COOKIE_VM_FIB_TABLE, matches, instructions);
1535 Flow flow = flowEntity.getFlowBuilder().build();
1536 String flowId = flowEntity.getFlowId();
1537 FlowKey flowKey = new FlowKey( new FlowId(flowId));
1538 Node nodeDpn = buildDpnNode(dpId);
1540 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1541 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1542 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1544 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
1545 SubTransaction subTransaction = new SubTransactionImpl();
1546 if (addOrRemove == NwConstants.ADD_FLOW) {
1547 subTransaction.setInstanceIdentifier(flowInstanceId);
1548 subTransaction.setInstance(flow);
1549 subTransaction.setAction(SubTransaction.CREATE);
1551 subTransaction.setInstanceIdentifier(flowInstanceId);
1552 subTransaction.setAction(SubTransaction.DELETE);
1554 transactionObjects.add(subTransaction);
1557 if (addOrRemove == NwConstants.ADD_FLOW) {
1558 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true);
1560 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1568 //TODO: How to handle the below code, its a copy paste from MDSALManager.java
1569 private Node buildDpnNode(BigInteger dpnId) {
1570 NodeId nodeId = new NodeId("openflow:" + dpnId);
1571 Node nodeDpn = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();
1576 private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions, int priority,
1577 int addOrRemove, WriteTransaction tx) {
1578 Boolean wrTxPresent = true;
1580 wrTxPresent = false;
1581 tx = dataBroker.newWriteOnlyTransaction();
1584 List<MatchInfo> matches = new ArrayList<MatchInfo>();
1585 matches.add(new MatchInfo(MatchFieldType.eth_type,
1586 new long[] { NwConstants.ETHTYPE_MPLS_UC }));
1587 matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
1589 // Install the flow entry in L3_LFIB_TABLE
1590 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, priority);
1592 FlowEntity flowEntity;
1593 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef, priority, flowRef, 0, 0,
1594 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
1595 Flow flow = flowEntity.getFlowBuilder().build();
1596 String flowId = flowEntity.getFlowId();
1597 FlowKey flowKey = new FlowKey( new FlowId(flowId));
1598 Node nodeDpn = buildDpnNode(dpId);
1599 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
1600 .child(Node.class, nodeDpn.getKey()).augmentation(FlowCapableNode.class)
1601 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
1603 if (addOrRemove == NwConstants.ADD_FLOW) {
1604 tx.put(LogicalDatastoreType.CONFIGURATION, flowInstanceId,flow, true);
1606 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
1611 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} modified successfully {}",
1612 dpId, label, instructions );
1615 private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress,
1616 final String ipPrefixAddress) {
1617 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
1619 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress, ipPrefixAddress);
1620 } catch (NullPointerException e) {
1625 public void populateFibOnNewDpn(final BigInteger dpnId, final long vpnId, final String rd,
1626 final FutureCallback<List<Void>> callback) {
1627 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
1628 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1629 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1630 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1631 if (!vrfTable.isPresent()) {
1632 LOG.warn("VRF Table not yet available for RD {}", rd);
1633 if (callback != null) {
1634 List<ListenableFuture<Void>> futures = new ArrayList<>();
1635 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1636 Futures.addCallback(listenableFuture, callback);
1640 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1641 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1642 new Callable<List<ListenableFuture<Void>>>() {
1644 public List<ListenableFuture<Void>> call() throws Exception {
1645 List<ListenableFuture<Void>> futures = new ArrayList<>();
1646 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1647 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1648 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1649 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1650 if (subnetRoute != null) {
1651 long elanTag = subnetRoute.getElantag();
1652 installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, tx);
1655 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
1656 if (routerInt != null) {
1657 LOG.trace( "Router augmented vrfentry found rd:{}, uuid:{}, ip:{}, mac:{}",
1658 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
1659 installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(), routerInt.getIpAddress(),
1660 new MacAddress(routerInt.getMacAddress()), NwConstants.ADD_FLOW);
1663 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) { //Handle local flow creation for imports
1664 LabelRouteInfo lri = getLabelRouteInfo(vrfEntry.getLabel());
1665 if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix())
1666 && vrfEntry.getNextHopAddressList().contains(lri.getNextHopIpList().get(0))) {
1667 if (lri.getDpnId().equals(dpnId)) {
1668 createLocalFibEntry(vpnId, rd, vrfEntry);
1673 // Passing null as we don't know the dpn
1674 // to which prefix is attached at this point
1675 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1677 //TODO: if we have 100K entries in FIB, can it fit in one Tranasaction (?)
1678 futures.add(tx.submit());
1680 if (callback != null) {
1681 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1682 Futures.addCallback(listenableFuture, callback);
1690 public void populateFibOnDpn(final BigInteger dpnId, final long vpnId, final String rd,
1691 final String localNextHopIp, final String remoteNextHopIp) {
1692 LOG.trace("dpn {}, vpn {}, rd {}, localNexthopIp {} , remoteNextHopIp {} : populateFibOnDpn",
1693 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1694 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1695 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1696 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1697 if (vrfTable.isPresent()) {
1698 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1699 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1700 new Callable<List<ListenableFuture<Void>>>() {
1702 public List<ListenableFuture<Void>> call() throws Exception {
1703 List<ListenableFuture<Void>> futures = new ArrayList<>();
1704 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1705 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1706 LOG.trace("populate FIB starts on Dpn " + dpnId
1707 + "rd " + rd.toString()
1708 + "localNextHopIp " + localNextHopIp
1709 + "remoteNextHopIp" + remoteNextHopIp
1710 + "vpnId " + vpnId );
1711 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1712 LOG.trace("old vrfEntry before populate:: {}", vrfEntry);
1714 if (vrfEntry.getOrigin().equals(RouteOrigin.BGP.getValue())) {
1715 if (remoteNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1716 LOG.trace(" creating remote FIB entry for vfEntry {}", vrfEntry);
1717 createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeTransaction);
1719 } else if (vrfEntry.getOrigin().equals(RouteOrigin.STATIC.getValue())) {
1720 BigInteger dpnIdForPrefix = null;
1721 String destPfx = vrfEntry.getDestPrefix();
1722 if (vrfEntry.getAugmentation(SubnetRoute.class) == null) {
1723 Optional<Extraroute> extraRouteInfo =
1724 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1725 getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
1726 if (extraRouteInfo.isPresent()) {
1729 dpnIdForPrefix = nextHopManager.getDpnForPrefix(vpnId, destPfx);
1731 // Subnet Route handling
1732 Optional<Prefixes> localNextHopInfoData =
1733 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
1734 FibUtil.getPrefixToInterfaceIdentifier(vpnId, destPfx));
1735 if (localNextHopInfoData.isPresent()) {
1736 Prefixes prefixes = localNextHopInfoData.get();
1737 dpnIdForPrefix = prefixes.getDpnId();
1740 if (dpnIdForPrefix == null) {
1741 LOG.trace("Populate::the dpnIdForPrefix is null for prefix {}.",
1742 vrfEntry.getDestPrefix());
1745 int sameDpnId = dpnIdForPrefix.compareTo(dpnId);
1746 if (sameDpnId != 0) {
1747 LOG.trace("Populate::Different srcDpnId {} and dpnIdForPrefix {} for prefix {}",
1748 dpnId, dpnIdForPrefix, vrfEntry.getDestPrefix());
1751 InstanceIdentifier<VrfEntry> vrfEntryId = getVrfEntryId(rd, vrfEntry.getDestPrefix());
1752 List<String> newNextHopAddrList = vrfEntry.getNextHopAddressList();
1753 newNextHopAddrList.add(localNextHopIp);
1754 VrfEntry newVrfEntry =
1755 new VrfEntryBuilder(vrfEntry).setNextHopAddressList(newNextHopAddrList).build();
1756 // Just update the VrfEntry
1757 FibUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
1758 vrfEntryId, newVrfEntry);
1759 // writeTransaction.put(LogicalDatastoreType.CONFIGURATION,
1760 // vrfEntryId, newVrfEntry);
1761 vrfEntry = getVrfEntry(dataBroker, rd, destPfx);
1762 LOG.trace("updated vrfEntry after populate:: {}", vrfEntry);
1765 futures.add(writeTransaction.submit());
1766 LOG.trace("populate FIB ends on Dpn " + dpnId
1767 + "rd " + rd.toString()
1768 + "localNextHopIp " + localNextHopIp
1769 + "remoteNextHopIp" + remoteNextHopIp
1770 + "vpnId " + vpnId);
1778 public void handleRemoteRoute(final boolean action, final BigInteger localDpnId, final BigInteger remoteDpnId,
1779 final long vpnId, final String rd, final String destPrefix ,
1780 final String localNextHopIP, final String remoteNextHopIp) {
1782 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1783 dataStoreCoordinator.enqueueJob( "FIB" + rd.toString()
1784 + "local dpid" + localDpnId
1785 + "remote dpid" + remoteDpnId
1787 + "localNHIp" + localNextHopIP
1788 + "remoteNHIp" + remoteNextHopIp,
1789 new Callable<List<ListenableFuture<Void>>>() {
1791 public List<ListenableFuture<Void>> call() throws Exception {
1792 List<ListenableFuture<Void>> futures = new ArrayList<>();
1793 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1794 VrfTablesKey vrfTablesKey = new VrfTablesKey(rd);
1795 VrfEntry vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1796 if (vrfEntry == null) {
1799 LOG.trace("handleRemoteRoute :: action {}, localDpnId {}, " +
1800 "remoteDpnId {} , vpnId {}, rd {}, destPfx {}",
1801 action, localDpnId, remoteDpnId, vpnId, rd, destPrefix);
1802 if (action == true) {
1803 vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1804 LOG.trace("handleRemoteRoute updated(add) vrfEntry :: {}", vrfEntry);
1805 createRemoteFibEntry(remoteDpnId, vpnId, vrfTablesKey, vrfEntry, writeTransaction);
1807 vrfEntry = getVrfEntry(dataBroker, rd, destPrefix);
1808 LOG.trace("handleRemoteRoute updated(remove) vrfEntry :: {}", vrfEntry);
1809 deleteRemoteRoute(null, remoteDpnId, vpnId, vrfTablesKey, vrfEntry, writeTransaction);
1811 futures.add(writeTransaction.submit());
1817 public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd,
1818 final FutureCallback<List<Void>> callback) {
1819 LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
1820 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1821 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1822 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1823 if (vrfTable.isPresent()) {
1824 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1825 dataStoreCoordinator.enqueueJob("FIB-" + vpnId + "-" + dpnId.toString(),
1826 new Callable<List<ListenableFuture<Void>>>() {
1828 public List<ListenableFuture<Void>> call() throws Exception {
1829 List<ListenableFuture<Void>> futures = new ArrayList<>();
1830 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1831 WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
1832 for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1833 /* Handle subnet routes here */
1834 SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
1835 if (subnetRoute != null) {
1836 LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(),
1838 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx);
1839 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx);
1840 LOG.trace("cleanUpDpnForVpn: Released subnetroute label {} for rd {} prefix {}", vrfEntry.getLabel(), rd,
1841 vrfEntry.getDestPrefix());
1844 // ping responder for router interfaces
1845 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
1846 if (routerInt != null) {
1847 LOG.trace("Router augmented vrfentry found for rd:{}, uuid:{}, ip:{}, mac:{}",
1848 rd, routerInt.getUuid(), routerInt.getIpAddress(), routerInt.getMacAddress());
1849 installRouterFibEntry(vrfEntry, dpnId, vpnId, routerInt.getUuid(), routerInt.getIpAddress(),
1850 new MacAddress(routerInt.getMacAddress()), NwConstants.DEL_FLOW);
1853 // Passing null as we don't know the dpn
1854 // to which prefix is attached at this point
1855 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, tx);
1857 futures.add(tx.submit());
1858 if (callback != null) {
1859 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1860 Futures.addCallback(listenableFuture, callback);
1870 public void cleanUpDpnForVpn(final BigInteger dpnId, final long vpnId, final String rd,
1871 final String localNextHopIp, final String remoteNextHopIp,
1872 final FutureCallback<List<Void>> callback) {
1873 LOG.trace( " cleanup remote routes on dpn {} for vpn {}, rd {}, " +
1874 " localNexthopIp {} , remoteNexhtHopIp {} : cleanUpDpnForVpn",
1875 dpnId, vpnId, rd, localNextHopIp, remoteNextHopIp);
1876 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
1877 final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
1878 final Optional<VrfTables> vrfTable = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1879 if (vrfTable.isPresent()) {
1880 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
1881 dataStoreCoordinator.enqueueJob(" FIB-" + vpnId + "-" + dpnId.toString(),
1882 new Callable<List<ListenableFuture<Void>>>() {
1884 public List<ListenableFuture<Void>> call() throws Exception {
1885 List<ListenableFuture<Void>> futures = new ArrayList<>();
1886 synchronized (vpnInstance.getVpnInstanceName().intern()) {
1887 WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
1888 LOG.trace("cleanup FIB starts on Dpn " + dpnId
1889 + "rd " + rd.toString()
1890 + "localNextHopIp " + localNextHopIp
1891 + "remoteNextHopIp" + remoteNextHopIp
1892 + "vpnId " + vpnId);
1894 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
1895 LOG.trace("old vrfEntry before cleanup:: {}", vrfEntry);
1896 if (remoteNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1897 LOG.trace(" deleting remote FIB entry {}", vrfEntry);
1898 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry, writeTransaction);
1901 if (localNextHopIp.trim().equals(vrfEntry.getNextHopAddressList().get(0).trim())) {
1902 LOG.trace("changing the nexthopip for local VM routes {} on dpn {}",
1903 vrfEntry.getDestPrefix(), dpnId);
1904 String destPfx = vrfEntry.getDestPrefix();
1905 InstanceIdentifier<VrfEntry> vrfEntryId = getVrfEntryId(rd, destPfx);
1906 List<java.lang.String> newList = vrfEntry.getNextHopAddressList();
1907 newList.remove(localNextHopIp);
1908 VrfEntry newVrfEntry =
1909 new VrfEntryBuilder(vrfEntry).setNextHopAddressList(newList).build();
1910 FibUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
1911 vrfEntryId, newVrfEntry);
1912 vrfEntry = getVrfEntry(dataBroker, rd, destPfx);
1913 LOG.trace("updated vrfEntry after cleanup:: {}", vrfEntry);
1916 futures.add(writeTransaction.submit());
1917 if (callback != null) {
1918 ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
1919 Futures.addCallback(listenableFuture, callback);
1921 LOG.trace("cleanup FIB ends on Dpn " + dpnId
1922 + "rd " + rd.toString()
1923 + "localNextHopIp " + localNextHopIp
1924 + "remoteNextHopIp" + remoteNextHopIp
1925 + "vpnId " + vpnId);
1934 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
1935 InstanceIdentifierBuilder<VrfTables> idBuilder =
1936 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
1937 InstanceIdentifier<VrfTables> id = idBuilder.build();
1941 private String getFlowRef(BigInteger dpnId, short tableId, long label, int priority) {
1942 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
1943 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(label).append(NwConstants.FLOWID_SEPARATOR)
1944 .append(priority).toString();
1947 private String getFlowRef(BigInteger dpnId, short tableId, String rd, int priority, InetAddress destPrefix) {
1948 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
1949 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
1950 .append(rd).append(NwConstants.FLOWID_SEPARATOR)
1951 .append(priority).append(NwConstants.FLOWID_SEPARATOR)
1952 .append(destPrefix.getHostAddress()).toString();
1955 private String getInterVpnFibFlowRef(String interVpnLinkName, String prefix, String nextHop ) {
1956 return new StringBuilder(64).append(FLOWID_PREFIX)
1957 .append(interVpnLinkName).append(NwConstants.FLOWID_SEPARATOR)
1958 .append(prefix).append(NwConstants.FLOWID_SEPARATOR)
1959 .append(nextHop).toString();
1962 protected List<String> resolveAdjacency(final BigInteger remoteDpnId, final long vpnId,
1963 final VrfEntry vrfEntry, String rd) {
1964 List<String> adjacencyList = new ArrayList<>();
1965 List<String> prefixIpList = new ArrayList<>();
1966 LOG.trace("resolveAdjacency called with remotedpid {}, vpnId{}, VrfEntry {}",
1967 remoteDpnId, vpnId, vrfEntry);
1969 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
1970 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
1971 if (extra_route == null) {
1972 prefixIpList = Arrays.asList(vrfEntry.getDestPrefix());
1974 prefixIpList = new ArrayList<>();
1975 for (String extraRouteIp : extra_route.getNexthopIpList()) {
1976 prefixIpList.add(extraRouteIp + "/32");
1980 prefixIpList = Arrays.asList(vrfEntry.getDestPrefix());
1983 for (String prefixIp : prefixIpList) {
1984 for (String nextHopIp : vrfEntry.getNextHopAddressList()) {
1985 LOG.debug("NextHop IP for destination {} is {}", prefixIp, nextHopIp);
1986 String adjacency = nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId,
1987 prefixIp, nextHopIp);
1988 if (adjacency != null && !adjacency.isEmpty() && !adjacencyList.contains(adjacency)) {
1989 adjacencyList.add(adjacency);
1993 } catch (NullPointerException e) {
1996 return adjacencyList;
1999 protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
2000 InstanceIdentifier<VpnInstanceOpDataEntry> id =
2001 InstanceIdentifier.create(VpnInstanceOpData.class)
2002 .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
2003 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData =
2004 FibUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
2005 return vpnInstanceOpData.isPresent() ? vpnInstanceOpData.get() : null;
2008 private String getTableMissFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
2009 return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
2010 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
2011 .append(FLOWID_PREFIX).toString();
2015 * Install flow entry in protocol table to forward mpls
2016 * coming through gre tunnel to LFIB table.
2018 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
2019 final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
2020 // Instruction to goto L3 InterfaceTable
2021 List<InstructionInfo> instructions = new ArrayList<>();
2022 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
2023 List<MatchInfo> matches = new ArrayList<MatchInfo>();
2024 matches.add(new MatchInfo(MatchFieldType.eth_type,
2025 new long[] { NwConstants.ETHTYPE_MPLS_UC }));
2026 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2027 getTableMissFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE,
2028 NwConstants.L3_LFIB_TABLE),
2029 DEFAULT_FIB_FLOW_PRIORITY,
2030 "Protocol Table For LFIB",
2032 COOKIE_PROTOCOL_TABLE,
2033 matches, instructions);
2035 if (addOrRemove == NwConstants.ADD_FLOW) {
2036 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
2037 mdsalManager.installFlow(flowEntityToLfib);
2039 mdsalManager.removeFlow(flowEntityToLfib);
2043 public List<String> printFibEntries() {
2044 List<String> result = new ArrayList<>();
2045 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s", "RD", "Prefix", "NextHop", "Label", "Origin"));
2046 result.add("-------------------------------------------------------------------");
2047 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
2048 Optional<FibEntries> fibEntries = FibUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
2049 if (fibEntries.isPresent()) {
2050 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
2051 for (VrfTables vrfTable : vrfTables) {
2052 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
2053 for (String nextHop : vrfEntry.getNextHopAddressList()) {
2054 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s",
2055 vrfTable.getRouteDistinguisher(),
2056 vrfEntry.getDestPrefix(), nextHop, vrfEntry.getLabel(), vrfEntry.getOrigin()));
2058 if (vrfEntry.getNextHopAddressList().isEmpty()) {
2059 result.add(String.format(" %-7s %-20s %-20s %-7s %-7s",
2060 vrfTable.getRouteDistinguisher(),
2061 vrfEntry.getDestPrefix(), "local", vrfEntry.getLabel(), vrfEntry.getOrigin()));
2070 private VrfEntry getVrfEntry(DataBroker broker, String rd, String ipPrefix) {
2071 InstanceIdentifier<VrfEntry> vrfEntryId =
2072 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).
2073 child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2074 Optional<VrfEntry> vrfEntry = read(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryId);
2075 if (vrfEntry.isPresent()) {
2076 return vrfEntry.get();
2081 private InstanceIdentifier<VrfEntry> getVrfEntryId(String rd, String ipPrefix) {
2082 InstanceIdentifier<VrfEntry> vrfEntryId =
2083 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd)).
2084 child(VrfEntry.class, new VrfEntryKey(ipPrefix)).build();
2088 protected Boolean installRouterFibEntries(final VrfEntry vrfEntry, final Collection<VpnToDpnList> vpnToDpnList,
2089 long vpnId, int addOrRemove) {
2090 RouterInterface routerInt = vrfEntry.getAugmentation(RouterInterface.class);
2091 if (routerInt != null && vpnToDpnList != null) {
2092 String routerId = routerInt.getUuid();
2093 String macAddress = routerInt.getMacAddress();
2094 String ipValue = routerInt.getIpAddress();
2095 LOG.trace("createFibEntries - Router augmented vrfentry found for for router uuid:{}, ip:{}, mac:{}",
2096 routerId, ipValue, macAddress);
2097 for (VpnToDpnList vpnDpn : vpnToDpnList) {
2098 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
2099 installRouterFibEntry(vrfEntry, vpnDpn.getDpnId(), vpnId, routerId, ipValue,
2100 new MacAddress(macAddress), addOrRemove);
2108 public void installRouterFibEntry(final VrfEntry vrfEntry, BigInteger dpnId, long vpnId, String routerUuid,
2109 String routerInternalIp, MacAddress routerMac, int addOrRemove) {
2110 String[] subSplit = routerInternalIp.split("/");
2112 String addRemoveStr = (addOrRemove == NwConstants.ADD_FLOW) ? "ADD_FLOW" : "DELETE_FLOW";
2113 LOG.trace("{}: bulding Echo Flow entity for dpid:{}, router_ip:{}, vpnId:{}, subSplit:{} ", addRemoveStr,
2114 dpnId, routerInternalIp, vpnId, subSplit[0]);
2116 List<MatchInfo> matches = new ArrayList<>();
2118 matches.add(new MatchInfo(MatchFieldType.ip_proto, new long[] { IPProtocols.ICMP.intValue() }));
2119 matches.add(new MatchInfo(MatchFieldType.metadata,
2120 new BigInteger[] { MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
2121 matches.add(new MatchInfo(MatchFieldType.icmp_v4, new long[] { (short) 8, (short) 0 }));
2122 matches.add(new MatchInfo(MatchFieldType.eth_type, new long[] { NwConstants.ETHTYPE_IPV4 }));
2123 matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] { subSplit[0], "32" }));
2125 List<ActionInfo> actionsInfos = new ArrayList<>();
2127 // Set Eth Src and Eth Dst
2128 actionsInfos.add(new ActionInfo(ActionType.move_src_dst_eth, new String[] {}));
2129 actionsInfos.add(new ActionInfo(ActionType.set_field_eth_src, new String[] { routerMac.getValue() }));
2131 // Move Ip Src to Ip Dst
2132 actionsInfos.add(new ActionInfo(ActionType.move_src_dst_ip, new String[] {}));
2133 actionsInfos.add(new ActionInfo(ActionType.set_source_ip, new String[] { subSplit[0], "32" }));
2135 // Set the ICMP type to 0 (echo reply)
2136 actionsInfos.add(new ActionInfo(ActionType.set_icmp_type, new String[] { "0" }));
2138 actionsInfos.add(new ActionInfo(ActionType.nx_load_in_port, new BigInteger[]{ BigInteger.ZERO }));
2140 actionsInfos.add(new ActionInfo(ActionType.nx_resubmit,
2141 new String[] { Short.toString(NwConstants.L3_FIB_TABLE) }));
2143 List<InstructionInfo> instructions = new ArrayList<>();
2145 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
2147 int priority = FibConstants.DEFAULT_FIB_FLOW_PRIORITY;
2148 String flowRef = getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, vrfEntry.getLabel(), priority);
2150 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef,
2151 0, 0, NwConstants.COOKIE_VM_FIB_TABLE, matches, instructions);
2153 if (addOrRemove == NwConstants.ADD_FLOW) {
2154 mdsalManager.installFlow(flowEntity);
2156 mdsalManager.removeFlow(flowEntity);