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.vpnservice.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;
15 import java.math.BigInteger;
16 import java.net.InetAddress;
17 import java.net.UnknownHostException;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.concurrent.ExecutionException;
23 import java.util.concurrent.Future;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
27 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
28 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
29 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.vpnmanager.api.IVpnManager;
32 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
33 import org.opendaylight.vpnservice.itm.globals.ITMConstants;
34 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
35 import org.opendaylight.vpnservice.mdsalutil.ActionType;
36 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
37 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
38 import org.opendaylight.vpnservice.mdsalutil.InstructionType;
39 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
40 import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
41 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
42 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
43 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
44 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.RdToElanOp;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntry;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntryKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnToExtraroute;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIds;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIdsKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.Vpn;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.VpnKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeMplsOverGre;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeInputBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeOutput;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies;
79 import org.opendaylight.yangtools.concepts.ListenerRegistration;
80 import org.opendaylight.yangtools.yang.binding.DataObject;
81 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
82 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
83 import org.opendaylight.yangtools.yang.common.RpcResult;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
87 public class FibManager extends AbstractDataChangeListener<VrfEntry> implements AutoCloseable{
88 private static final Logger LOG = LoggerFactory.getLogger(FibManager.class);
89 private static final String FLOWID_PREFIX = "L3.";
90 private ListenerRegistration<DataChangeListener> listenerRegistration;
91 private final DataBroker broker;
92 private IMdsalApiManager mdsalManager;
93 private IVpnManager vpnmanager;
94 private NexthopManager nextHopManager;
95 private ItmRpcService itmManager;
96 private OdlInterfaceRpcService interfaceManager;
97 private IdManagerService idManager;
98 private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
99 private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16);
100 private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
101 private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16);
102 private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0);
103 public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
106 public FibManager(final DataBroker db) {
107 super(VrfEntry.class);
109 registerListener(db);
113 public void close() throws Exception {
114 if (listenerRegistration != null) {
116 listenerRegistration.close();
117 } catch (final Exception e) {
118 LOG.error("Error when cleaning up DataChangeListener.", e);
120 listenerRegistration = null;
122 LOG.info("Fib Manager Closed");
125 public void setNextHopManager(NexthopManager nextHopManager) {
126 this.nextHopManager = nextHopManager;
129 public void setMdsalManager(IMdsalApiManager mdsalManager) {
130 this.mdsalManager = mdsalManager;
133 public void setVpnmanager(IVpnManager vpnmanager) {
134 this.vpnmanager = vpnmanager;
137 public void setITMRpcService(ItmRpcService itmManager) {
138 this.itmManager = itmManager;
141 public void setInterfaceManager(OdlInterfaceRpcService ifManager) {
142 this.interfaceManager = ifManager;
145 public void setIdManager(IdManagerService idManager) {
146 this.idManager = idManager;
149 private void registerListener(final DataBroker db) {
151 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
152 getWildCardPath(), FibManager.this, DataChangeScope.SUBTREE);
153 } catch (final Exception e) {
154 LOG.error("FibManager DataChange listener registration fail!", e);
155 throw new IllegalStateException("FibManager registration Listener failed.", e);
160 private InstanceIdentifier<VrfEntry> getWildCardPath() {
161 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
166 protected void add(final InstanceIdentifier<VrfEntry> identifier,
167 final VrfEntry vrfEntry) {
168 LOG.trace("Add key: " + identifier + ", value=" + vrfEntry );
169 createFibEntries(identifier, vrfEntry);
173 protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
174 LOG.trace("Remove key: " + identifier + ", value=" + vrfEntry);
175 deleteFibEntries(identifier, vrfEntry);
179 protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
180 LOG.trace("Update key: " + identifier + ", original=" + original + ", update=" + update );
181 createFibEntries(identifier, update);
184 private void createFibEntries(final InstanceIdentifier<VrfEntry> identifier,
185 final VrfEntry vrfEntry) {
186 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
187 Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
188 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
190 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
191 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
192 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
194 Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
195 Long vpnId = vpnInstance.getVpnId();
196 String rd = vrfTableKey.getRouteDistinguisher();
197 RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, rd,
198 vrfEntry.getDestPrefix());
199 if (rdToElanOpEntry!=null) {
200 if (vpnToDpnList!=null) {
201 for (VpnToDpnList curDpn : vpnToDpnList) {
202 installSubnetRouteInFib(curDpn.getDpnId(), rdToElanOpEntry, vpnId.longValue(), vrfEntry);
207 BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(),
209 if (vpnToDpnList != null) {
210 for (VpnToDpnList curDpn : vpnToDpnList) {
211 if (!curDpn.getDpnId().equals(localDpnId)) {
212 createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(),
213 vrfTableKey, vrfEntry);
219 private void installSubnetRouteInFib(BigInteger dpnId, RdToElanOpEntry rdToElanOpEntry,
220 long vpnId, VrfEntry vrfEntry){
221 makeSubnetRouteFlow(dpnId);
222 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
223 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
224 Long elanTag = rdToElanOpEntry.getElanTag();
225 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
226 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
227 makeConnectedRoute(dpnId,vpnId,vrfEntry,rdToElanOpEntry.getRd(),
228 instructions,NwConstants.ADD_FLOW);
229 makeLFibTableEntry(dpnId,vrfEntry.getLabel(),instructions,
230 vrfEntry.getNextHopAddress(),NwConstants.ADD_FLOW);
231 // TODO makeTunnelTableEntry();
234 private RdToElanOpEntry getRdToElanOpEntry(DataBroker broker, String rd, String subnetIp) {
235 InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(rd,subnetIp);
236 Optional<RdToElanOpEntry> sn = read(broker, LogicalDatastoreType.OPERATIONAL, id);
243 private InstanceIdentifier<RdToElanOpEntry> getRdToElanOpEntryDataPath(String rd, String subnetIp) {
244 return InstanceIdentifier.builder(RdToElanOp.class).child(RdToElanOpEntry.class,
245 new RdToElanOpEntryKey(rd,subnetIp)).build();
247 private <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
248 InstanceIdentifier<T> path) {
250 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
252 Optional<T> result = Optional.absent();
254 result = tx.read(datastoreType, path).get();
255 } catch (Exception e) {
256 throw new RuntimeException(e);
262 private void makeSubnetRouteFlow(BigInteger dpnId) {
264 final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
265 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
266 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
267 actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{}));
268 instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
269 List<MatchInfo> matches = new ArrayList<MatchInfo>();
270 String flowRef = getFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, NwConstants.TABLE_MISS_FLOW);
271 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef,
272 NwConstants.TABLE_MISS_PRIORITY, "Subnet Route Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
274 LOG.debug("Invoking MDSAL to install Table Miss Entries");
275 mdsalManager.syncInstallFlow(flowEntity,1);
278 private Collection<BigInteger> getDpnsForVpn(VpnInstanceOpDataEntry vpnInstance) {
279 Collection<BigInteger> dpns = new HashSet<>();
280 for(VpnToDpnList dpn : vpnInstance.getVpnToDpnList()) {
281 dpns.add(dpn.getDpnId());
287 public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
288 BigInteger localDpnId = BigInteger.ZERO;
289 Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
290 String localNextHopIP = vrfEntry.getDestPrefix();
292 if(localNextHopInfo == null) {
293 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
294 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
295 if (extra_route != null) {
296 localNextHopInfo = getPrefixToInterface(vpnId, extra_route.getNexthopIp() + "/32");
297 localNextHopIP = extra_route.getNexthopIp() + "/32";
301 if(localNextHopInfo != null) {
302 localDpnId = localNextHopInfo.getDpnId();
303 long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
305 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
306 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
308 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
309 instructions.add(new InstructionInfo(InstructionType.write_actions,actionsInfos));
310 makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
312 actionsInfos=new ArrayList<ActionInfo>();;
313 instructions=new ArrayList<InstructionInfo>();
314 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
315 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
316 instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
317 makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), instructions, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW);
319 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
320 localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
321 makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId);
327 private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/) {
328 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
329 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
332 createTerminatingServiceActions(dpId, (int)label, actionsInfos);
334 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully {}",
335 dpId, label, groupId);
338 public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos) {
339 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
341 LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
344 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
345 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
347 List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
348 mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
350 FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
351 getFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
352 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
354 mdsalManager.installFlow(terminatingServiceTableFlowEntity);
357 private void removeTunnelTableEntry(BigInteger dpId, long label) {
358 FlowEntity flowEntity;
359 LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
360 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
362 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
363 flowEntity = MDSALUtil.buildFlowEntity(dpId,
364 NwConstants.INTERNAL_TUNNEL_TABLE,
365 getFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
366 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
367 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
368 mdsalManager.removeFlow(flowEntity);
369 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpId, label);
372 public BigInteger deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
373 BigInteger localDpnId = BigInteger.ZERO;
374 boolean isExtraRoute = false;
375 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
376 String localNextHopIP = vrfEntry.getDestPrefix();
378 if(localNextHopInfo == null) {
379 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
380 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
381 if (extra_route != null) {
382 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp() + "/32");
383 localNextHopIP = extra_route.getNexthopIp() + "/32";
389 if(localNextHopInfo != null) {
390 localDpnId = localNextHopInfo.getDpnId();
391 Prefixes prefix = getPrefixToInterface(vpnId, isExtraRoute ? localNextHopIP : vrfEntry.getDestPrefix());
392 makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */,
393 NwConstants.DEL_FLOW);
394 makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), null /* invalid */,
395 vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW);
396 removeTunnelTableEntry(localDpnId, vrfEntry.getLabel());
397 deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP);
402 private InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) {
403 return InstanceIdentifier.builder(PrefixToInterface.class)
404 .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
407 private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
408 Optional<Prefixes> localNextHopInfoData =
409 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
410 return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
413 private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
414 return InstanceIdentifier.builder(VpnToExtraroute.class)
415 .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class,
416 new ExtrarouteKey(ipPrefix)).build();
419 private Extraroute getVpnToExtraroute(String rd, String ipPrefix) {
420 Optional<Extraroute> extraRouteInfo =
421 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix));
422 return extraRouteInfo.isPresent() ? extraRouteInfo.get() : null;
426 private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
428 Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
429 new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
430 RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
431 if(!rpcResult.isSuccessful()) {
432 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
434 return rpcResult.getResult().getTunnelType();
437 } catch (InterruptedException | ExecutionException e) {
438 LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e);
444 private void createRemoteFibEntry(final BigInteger localDpnId, final BigInteger remoteDpnId,
445 final long vpnId, final VrfTablesKey vrfTableKey,
446 final VrfEntry vrfEntry) {
447 String rd = vrfTableKey.getRouteDistinguisher();
448 LOG.debug("adding route " + vrfEntry.getDestPrefix() + " " + rd);
449 /********************************************/
450 String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd);
451 if(tunnelInterface == null) {
452 LOG.error("Could not get interface for nexthop: {} in vpn {}",
453 vrfEntry.getNextHopAddress(), rd);
454 LOG.warn("Failed to add Route: {} in vpn: {}",
455 vrfEntry.getDestPrefix(), rd);
458 List<ActionInfo> actionInfos = new ArrayList<>();
459 Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
460 if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
461 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
462 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
463 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
465 int label = vrfEntry.getLabel().intValue();
467 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
468 if(tunnel_type.equals(TunnelTypeVxlan.class)) {
469 tunnelId = BigInteger.valueOf(label);
471 tunnelId = BigInteger.valueOf(label);
473 LOG.debug("adding set tunnel id action for label {}", label);
474 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{
477 actionInfos.addAll(nextHopManager.getEgressActionsForInterface(tunnelInterface));
478 List<InstructionInfo> instructions= new ArrayList<InstructionInfo>();
479 instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
481 List<ActionInfo> actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry);
482 if(actionInfos == null) {
483 LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}",
484 vrfEntry.getNextHopAddress(), rd);
485 LOG.warn("Failed to add Route: {} in vpn: {}",
486 vrfEntry.getDestPrefix(), rd);
489 BigInteger dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getDestPrefix());
491 //This route may be extra route... try to query with nexthop Ip
492 LOG.debug("Checking for extra route to install remote fib entry {}", vrfEntry.getDestPrefix());
493 dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getNextHopAddress() + "/32");
496 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
497 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
498 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
500 int label = vrfEntry.getLabel().intValue();
501 LOG.debug("adding set tunnel id action for label {}", label);
502 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
503 MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label),
504 MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
507 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
508 LOG.debug("Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId);
511 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
512 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
513 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
514 if (dpnInVpn.isPresent()) {
515 List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
516 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
517 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
518 currVpnInterface = new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder().setInterfaceName(intfName).build();
520 if (vpnInterfaces.remove(currVpnInterface)) {
521 if (vpnInterfaces.isEmpty()) {
522 LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
523 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id);
524 cleanUpDpnForVpn(dpnId, vpnId, rd);
526 LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
527 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
528 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
529 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
530 new org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey(intfName)));
536 private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
537 /* Get interface info from prefix to interface mapping;
538 Use the interface info to get the corresponding vpn interface op DS entry,
539 remove the adjacency corresponding to this fib entry.
540 If adjacency removed is the last adjacency, clean up the following:
541 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
542 - prefix to interface entry
543 - vpn interface op DS
545 Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
546 Extraroute extraRoute = null;
547 if (prefixInfo == null) {
548 extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
549 if(extraRoute != null) {
550 prefixInfo = getPrefixToInterface(vpnId, extraRoute.getNexthopIp() + "/32");
551 //clean up the vpn to extra route entry in DS
552 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
555 if (prefixInfo == null) {
556 LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for " + vrfEntry.getDestPrefix());
557 return; //Don't have any info for this prefix (shouldn't happen); need to return
559 String ifName = prefixInfo.getVpnInterfaceName();
560 Optional<Adjacencies> optAdjacencies = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getAdjListPath(ifName));
562 if (optAdjacencies.isPresent()) {
563 numAdj = optAdjacencies.get().getAdjacency().size();
565 LOG.trace("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix());
566 //remove adjacency corr to prefix
568 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
569 FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
572 if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
573 //clean up the vpn interface from DpnToVpn list
574 LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
575 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
576 FibUtil.getVpnInterfaceIdentifier(ifName));
579 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
580 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
584 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier,
585 final VrfEntry vrfEntry) {
586 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
587 Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
588 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
590 String rd = vrfTableKey.getRouteDistinguisher();
591 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
592 if (vpnInstance == null) {
593 LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
596 Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
597 RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker,vrfTableKey.getRouteDistinguisher(),
598 vrfEntry.getDestPrefix());
599 if (rdToElanOpEntry != null) {
600 if (vpnToDpnList!=null) {
601 for(VpnToDpnList curDpn : vpnToDpnList) {
602 makeConnectedRoute(curDpn.getDpnId(),vpnInstance.getVpnId(),vrfEntry,vrfTableKey
603 .getRouteDistinguisher(), null,NwConstants.DEL_FLOW);
604 makeLFibTableEntry(curDpn.getDpnId(),vrfEntry.getLabel(),null,
605 vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
606 // TODO DeleteTunnelTableEntry();
609 //Delete rd-to-elan-op-entry
610 InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(vrfTableKey.getRouteDistinguisher(),
611 vrfEntry.getDestPrefix());
612 MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL,id);
613 FibUtil.releaseId(idManager,FibConstants.VPN_IDPOOL_NAME,
614 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
617 BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(),
618 vrfTableKey.getRouteDistinguisher(), vrfEntry);
619 if (vpnToDpnList != null) {
620 for (VpnToDpnList curDpn : vpnToDpnList) {
621 if (!curDpn.getDpnId().equals(localDpnId)) {
622 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry);
626 //The flow/group entry has been deleted from config DS; need to clean up associated operational
627 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
628 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
631 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
632 final long vpnId, final VrfTablesKey vrfTableKey,
633 final VrfEntry vrfEntry) {
634 LOG.debug("deleting route "+ vrfEntry.getDestPrefix() + " "+vpnId);
635 String rd = vrfTableKey.getRouteDistinguisher();
636 boolean isRemoteRoute = true;
637 if (localDpnId == null) {
638 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
639 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
640 if(localNextHopInfo == null) {
641 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
642 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
643 if (extra_route != null) {
644 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp());
647 if (localNextHopInfo != null) {
648 isRemoteRoute = (!remoteDpnId.equals(localNextHopInfo.getDpnId()));
652 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
653 LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId);
655 LOG.debug("Did not delete fib entry rd: {} =, prefix: {} as it is local to dpn {}", rd, vrfEntry.getDestPrefix(), remoteDpnId);
659 private long getIpAddress(byte[] rawIpAddress) {
660 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
661 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
664 private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
665 List<InstructionInfo> instructions, int addOrRemove) { LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
666 String values[] = vrfEntry.getDestPrefix().split("/");
667 String ipAddress = values[0];
668 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
669 LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength);
670 InetAddress destPrefix = null;
672 destPrefix = InetAddress.getByName(ipAddress);
673 } catch (UnknownHostException e) {
674 LOG.error("UnknowHostException in addRoute. Failed to add Route for ipPrefix {}", vrfEntry.getDestPrefix());
678 List<MatchInfo> matches = new ArrayList<MatchInfo>();
680 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
681 BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
683 matches.add(new MatchInfo(MatchFieldType.eth_type,
684 new long[] { 0x0800L }));
686 if(prefixLength != 0) {
687 matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
688 destPrefix.getHostAddress(), Integer.toString(prefixLength)}));
691 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, destPrefix);
693 FlowEntity flowEntity;
695 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
696 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
697 priority, flowRef, 0, 0,
698 COOKIE_VM_FIB_TABLE, matches, instructions);
700 if (addOrRemove == NwConstants.ADD_FLOW) {
701 /* We need to call sync API to install flow so that 2 DS operations on the same object do not
702 * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
703 * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
704 * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
705 * wait indefinitely. */
706 mdsalManager.syncInstallFlow(flowEntity, 1);
708 mdsalManager.syncRemoveFlow(flowEntity, 1);
712 private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions,
713 String nextHop, int addOrRemove) {
714 List<MatchInfo> matches = new ArrayList<MatchInfo>();
715 matches.add(new MatchInfo(MatchFieldType.eth_type,
716 new long[] { 0x8847L }));
717 matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
719 // Install the flow entry in L3_LFIB_TABLE
720 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, nextHop);
722 FlowEntity flowEntity;
723 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef,
724 DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
725 COOKIE_VM_LFIB_TABLE, matches, instructions);
727 if (addOrRemove == NwConstants.ADD_FLOW) {
728 /* We need to call sync API to install flow so that 2 DS operations on the same object do not
729 * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
730 * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
731 * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
732 * wait indefinitely. */
734 mdsalManager.syncInstallFlow(flowEntity, 1);
736 mdsalManager.syncRemoveFlow(flowEntity, 1);
738 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} modified successfully {}",dpId, label, instructions );
741 private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
742 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
744 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
745 } catch (NullPointerException e) {
750 public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) {
751 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
752 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
753 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
754 synchronized (lockOnDpnVpn.intern()) {
755 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
756 if (vrfTable.isPresent()) {
757 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
758 RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, rd,
759 vrfEntry.getDestPrefix());
760 if (rdToElanOpEntry!= null) {
761 installSubnetRouteInFib(dpnId, rdToElanOpEntry, vpnId, vrfEntry);
764 // Passing null as we don't know the dpn
765 // to which prefix is attached at this point
766 createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
772 public void populateFibOnDpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
773 LOG.trace("dpn {} for vpn {}, nexthopIp {} : populateFibOnDpn", dpnId, rd, nexthopIp);
774 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
775 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
776 synchronized (lockOnDpnVpn.intern()) {
777 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
778 if (vrfTable.isPresent()) {
779 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
780 // Passing null as we don't know the dpn
781 // to which prefix is attached at this point
782 if (nexthopIp == vrfEntry.getNextHopAddress()) {
783 createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
790 public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) {
791 LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
792 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
793 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
794 synchronized (lockOnDpnVpn.intern()) {
795 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
796 if (vrfTable.isPresent()) {
797 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
798 /* Handle subnet routes here */
799 RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker, rd,
800 vrfEntry.getDestPrefix());
801 if (rdToElanOpEntry != null) {
802 LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(),
804 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
805 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null,
806 vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
809 // Passing null as we don't know the dpn
810 // to which prefix is attached at this point
811 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
817 public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
818 LOG.trace("dpn {} for vpn {}, nexthopIp {} : cleanUpDpnForVpn", dpnId, rd, nexthopIp);
819 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
820 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
821 synchronized (lockOnDpnVpn.intern()) {
822 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
823 if (vrfTable.isPresent()) {
824 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
825 // Passing null as we don't know the dpn
826 // to which prefix is attached at this point
827 if (nexthopIp == vrfEntry.getNextHopAddress()) {
828 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
835 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
836 InstanceIdentifierBuilder<VrfTables> idBuilder =
837 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
838 InstanceIdentifier<VrfTables> id = idBuilder.build();
842 private String getFlowRef(BigInteger dpnId, short tableId, long label, String nextHop) {
843 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
844 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
845 .append(label).append(NwConstants.FLOWID_SEPARATOR)
846 .append(nextHop).toString();
849 private String getFlowRef(BigInteger dpnId, short tableId, String rd, InetAddress destPrefix) {
850 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
851 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
852 .append(rd).append(NwConstants.FLOWID_SEPARATOR)
853 .append(destPrefix.getHostAddress()).toString();
856 protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId,
857 final long vpnId, final VrfEntry vrfEntry, String rd) {
858 String adjacency = null;
859 boolean staticRoute = false;
860 LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry);
862 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
863 if(extra_route != null) {
868 nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId,
869 (staticRoute == true) ? extra_route.getNexthopIp() + "/32" : vrfEntry.getDestPrefix(),
870 vrfEntry.getNextHopAddress());
871 } catch (NullPointerException e) {
877 protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
878 InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.create(VpnInstanceOpData.class).child(
879 VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
880 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
881 if(vpnInstanceOpData.isPresent()) {
882 return vpnInstanceOpData.get();
887 public void processNodeAdd(BigInteger dpnId) {
888 LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
889 makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
890 makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
893 private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
894 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
895 // Instruction to goto L3 InterfaceTable
896 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
897 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE }));
898 List<MatchInfo> matches = new ArrayList<MatchInfo>();
899 FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE,
900 getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW),
901 NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
903 FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE, getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, NwConstants.TABLE_MISS_FLOW),
904 NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow", 0, 0, COOKIE_VM_FIB_TABLE,
905 matches, instructions);
907 if (addOrRemove == NwConstants.ADD_FLOW) {
908 LOG.debug("Invoking MDSAL to install Table Miss Entries");
909 mdsalManager.installFlow(flowEntityLfib);
910 mdsalManager.installFlow(flowEntityFib);
912 mdsalManager.removeFlow(flowEntityLfib);
913 mdsalManager.removeFlow(flowEntityFib);
918 private String getFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
919 return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
920 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
921 .append(FLOWID_PREFIX).toString();
925 * Install flow entry in protocol table to forward mpls
926 * coming through gre tunnel to LFIB table.
928 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
929 final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
930 // Instruction to goto L3 InterfaceTable
931 List<InstructionInfo> instructions = new ArrayList<>();
932 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
933 List<MatchInfo> matches = new ArrayList<MatchInfo>();
934 matches.add(new MatchInfo(MatchFieldType.eth_type,
935 new long[] { 0x8847L }));
936 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_PROTOCOL_TABLE,
937 getFlowRef(dpnId, NwConstants.L3_PROTOCOL_TABLE,
938 NwConstants.L3_LFIB_TABLE),
939 DEFAULT_FIB_FLOW_PRIORITY,
940 "Protocol Table For LFIB",
942 COOKIE_PROTOCOL_TABLE,
943 matches, instructions);
945 if (addOrRemove == NwConstants.ADD_FLOW) {
946 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
947 mdsalManager.installFlow(flowEntityToLfib);
949 mdsalManager.removeFlow(flowEntityToLfib);
953 public List<String> printFibEntries() {
954 List<String> result = new ArrayList<String>();
955 result.add(String.format(" %-7s %-20s %-20s %-7s", "RD", "Prefix", "Nexthop", "Label"));
956 result.add("-------------------------------------------------------------------");
957 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
958 Optional<FibEntries> fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
959 if (fibEntries.isPresent()) {
960 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
961 for (VrfTables vrfTable : vrfTables) {
962 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
963 result.add(String.format(" %-7s %-20s %-20s %-7s", vrfTable.getRouteDistinguisher(),
964 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress(), vrfEntry.getLabel()));
971 private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) {
972 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
973 List<MatchInfo> matches = new ArrayList<MatchInfo>();
974 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
975 // Instruction to clear metadata except SI and LportTag bits
976 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] {
977 CLEAR_METADATA, METADATA_MASK_CLEAR }));
978 // Instruction to clear action
979 instructions.add(new InstructionInfo(InstructionType.clear_actions));
980 // Instruction to goto L3 InterfaceTable
982 List <ActionInfo> actionsInfos = new ArrayList <ActionInfo> ();
983 actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{
984 Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)}));
985 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
986 //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE }));
988 FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE,
989 getFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW),
990 NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
991 if (addOrRemove == NwConstants.ADD_FLOW) {
992 LOG.info("Invoking MDSAL to install L3 interface Table Miss Entries");
993 mdsalManager.installFlow(flowEntityL3Intf);
995 mdsalManager.removeFlow(flowEntityL3Intf);