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 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);
230 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
231 // reinitialize instructions list for LFIB Table
232 instructions = new ArrayList<InstructionInfo>();
234 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
235 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
236 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
237 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
239 makeLFibTableEntry(dpnId,vrfEntry.getLabel(),instructions,
240 vrfEntry.getNextHopAddress(),NwConstants.ADD_FLOW);
241 // TODO makeTunnelTableEntry();
244 private RdToElanOpEntry getRdToElanOpEntry(DataBroker broker, String rd, String subnetIp) {
245 InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(rd,subnetIp);
246 Optional<RdToElanOpEntry> sn = read(broker, LogicalDatastoreType.OPERATIONAL, id);
253 private InstanceIdentifier<RdToElanOpEntry> getRdToElanOpEntryDataPath(String rd, String subnetIp) {
254 return InstanceIdentifier.builder(RdToElanOp.class).child(RdToElanOpEntry.class,
255 new RdToElanOpEntryKey(rd,subnetIp)).build();
257 private <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
258 InstanceIdentifier<T> path) {
260 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
262 Optional<T> result = Optional.absent();
264 result = tx.read(datastoreType, path).get();
265 } catch (Exception e) {
266 throw new RuntimeException(e);
272 private void makeSubnetRouteFlow(BigInteger dpnId) {
274 final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
275 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
276 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
277 actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{}));
278 instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
279 List<MatchInfo> matches = new ArrayList<MatchInfo>();
280 String flowRef = getFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, NwConstants.TABLE_MISS_FLOW);
281 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef,
282 NwConstants.TABLE_MISS_PRIORITY, "Subnet Route Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
284 LOG.debug("Invoking MDSAL to install Table Miss Entries");
285 mdsalManager.syncInstallFlow(flowEntity,1);
288 private Collection<BigInteger> getDpnsForVpn(VpnInstanceOpDataEntry vpnInstance) {
289 Collection<BigInteger> dpns = new HashSet<>();
290 for(VpnToDpnList dpn : vpnInstance.getVpnToDpnList()) {
291 dpns.add(dpn.getDpnId());
297 public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
298 BigInteger localDpnId = BigInteger.ZERO;
299 Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
300 String localNextHopIP = vrfEntry.getDestPrefix();
302 if(localNextHopInfo == null) {
303 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
304 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
305 if (extra_route != null) {
306 localNextHopInfo = getPrefixToInterface(vpnId, extra_route.getNexthopIp() + "/32");
307 localNextHopIP = extra_route.getNexthopIp() + "/32";
311 if(localNextHopInfo != null) {
312 localDpnId = localNextHopInfo.getDpnId();
313 long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
315 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
316 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
318 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
319 instructions.add(new InstructionInfo(InstructionType.write_actions,actionsInfos));
320 makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
322 actionsInfos=new ArrayList<ActionInfo>();;
323 instructions=new ArrayList<InstructionInfo>();
324 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
325 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
326 instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
327 makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), instructions, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW);
329 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
330 localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
331 makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId);
337 private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/) {
338 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
339 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
342 createTerminatingServiceActions(dpId, (int)label, actionsInfos);
344 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully {}",
345 dpId, label, groupId);
348 public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos) {
349 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
351 LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
354 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
355 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
357 List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
358 mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
360 FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
361 getFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
362 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
364 mdsalManager.installFlow(terminatingServiceTableFlowEntity);
367 private void removeTunnelTableEntry(BigInteger dpId, long label) {
368 FlowEntity flowEntity;
369 LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
370 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
372 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
373 flowEntity = MDSALUtil.buildFlowEntity(dpId,
374 NwConstants.INTERNAL_TUNNEL_TABLE,
375 getFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
376 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
377 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
378 mdsalManager.removeFlow(flowEntity);
379 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpId, label);
382 public BigInteger deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
383 BigInteger localDpnId = BigInteger.ZERO;
384 boolean isExtraRoute = false;
385 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
386 String localNextHopIP = vrfEntry.getDestPrefix();
388 if(localNextHopInfo == null) {
389 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
390 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
391 if (extra_route != null) {
392 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp() + "/32");
393 localNextHopIP = extra_route.getNexthopIp() + "/32";
399 if(localNextHopInfo != null) {
400 localDpnId = localNextHopInfo.getDpnId();
401 Prefixes prefix = getPrefixToInterface(vpnId, isExtraRoute ? localNextHopIP : vrfEntry.getDestPrefix());
402 makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */,
403 NwConstants.DEL_FLOW);
404 makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), null /* invalid */,
405 vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW);
406 removeTunnelTableEntry(localDpnId, vrfEntry.getLabel());
407 deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP);
412 private InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) {
413 return InstanceIdentifier.builder(PrefixToInterface.class)
414 .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
417 private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
418 Optional<Prefixes> localNextHopInfoData =
419 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
420 return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
423 private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
424 return InstanceIdentifier.builder(VpnToExtraroute.class)
425 .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class,
426 new ExtrarouteKey(ipPrefix)).build();
429 private Extraroute getVpnToExtraroute(String rd, String ipPrefix) {
430 Optional<Extraroute> extraRouteInfo =
431 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix));
432 return extraRouteInfo.isPresent() ? extraRouteInfo.get() : null;
436 private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
438 Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
439 new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
440 RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
441 if(!rpcResult.isSuccessful()) {
442 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
444 return rpcResult.getResult().getTunnelType();
447 } catch (InterruptedException | ExecutionException e) {
448 LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e);
454 private void createRemoteFibEntry(final BigInteger localDpnId, final BigInteger remoteDpnId,
455 final long vpnId, final VrfTablesKey vrfTableKey,
456 final VrfEntry vrfEntry) {
457 String rd = vrfTableKey.getRouteDistinguisher();
458 LOG.debug("adding route " + vrfEntry.getDestPrefix() + " " + rd);
459 /********************************************/
460 String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd);
461 if(tunnelInterface == null) {
462 LOG.error("Could not get interface for nexthop: {} in vpn {}",
463 vrfEntry.getNextHopAddress(), rd);
464 LOG.warn("Failed to add Route: {} in vpn: {}",
465 vrfEntry.getDestPrefix(), rd);
468 List<ActionInfo> actionInfos = new ArrayList<>();
469 Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
470 if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
471 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
472 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
473 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
475 int label = vrfEntry.getLabel().intValue();
477 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
478 if(tunnel_type.equals(TunnelTypeVxlan.class)) {
479 tunnelId = BigInteger.valueOf(label);
481 tunnelId = BigInteger.valueOf(label);
483 LOG.debug("adding set tunnel id action for label {}", label);
484 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{
487 actionInfos.addAll(nextHopManager.getEgressActionsForInterface(tunnelInterface));
488 List<InstructionInfo> instructions= new ArrayList<InstructionInfo>();
489 instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
491 List<ActionInfo> actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry);
492 if(actionInfos == null) {
493 LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}",
494 vrfEntry.getNextHopAddress(), rd);
495 LOG.warn("Failed to add Route: {} in vpn: {}",
496 vrfEntry.getDestPrefix(), rd);
499 BigInteger dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getDestPrefix());
501 //This route may be extra route... try to query with nexthop Ip
502 LOG.debug("Checking for extra route to install remote fib entry {}", vrfEntry.getDestPrefix());
503 dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getNextHopAddress() + "/32");
506 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
507 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
508 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
510 int label = vrfEntry.getLabel().intValue();
511 LOG.debug("adding set tunnel id action for label {}", label);
512 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
513 MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label),
514 MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
517 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
518 LOG.debug("Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId);
521 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
522 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
523 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
524 if (dpnInVpn.isPresent()) {
525 List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
526 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
527 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
528 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();
530 if (vpnInterfaces.remove(currVpnInterface)) {
531 if (vpnInterfaces.isEmpty()) {
532 LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
533 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id);
534 cleanUpDpnForVpn(dpnId, vpnId, rd);
536 LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
537 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
538 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
539 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
540 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)));
546 private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
547 /* Get interface info from prefix to interface mapping;
548 Use the interface info to get the corresponding vpn interface op DS entry,
549 remove the adjacency corresponding to this fib entry.
550 If adjacency removed is the last adjacency, clean up the following:
551 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
552 - prefix to interface entry
553 - vpn interface op DS
555 Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
556 Extraroute extraRoute = null;
557 if (prefixInfo == null) {
558 extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
559 if(extraRoute != null) {
560 prefixInfo = getPrefixToInterface(vpnId, extraRoute.getNexthopIp() + "/32");
561 //clean up the vpn to extra route entry in DS
562 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
565 if (prefixInfo == null) {
566 LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for " + vrfEntry.getDestPrefix());
567 return; //Don't have any info for this prefix (shouldn't happen); need to return
569 String ifName = prefixInfo.getVpnInterfaceName();
570 Optional<Adjacencies> optAdjacencies = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getAdjListPath(ifName));
572 if (optAdjacencies.isPresent()) {
573 numAdj = optAdjacencies.get().getAdjacency().size();
575 LOG.trace("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix());
576 //remove adjacency corr to prefix
578 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
579 FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
582 if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
583 //clean up the vpn interface from DpnToVpn list
584 LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
585 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
586 FibUtil.getVpnInterfaceIdentifier(ifName));
589 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
590 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
594 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier,
595 final VrfEntry vrfEntry) {
596 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
597 Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
598 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
600 String rd = vrfTableKey.getRouteDistinguisher();
601 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
602 if (vpnInstance == null) {
603 LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
606 Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
607 RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker,vrfTableKey.getRouteDistinguisher(),
608 vrfEntry.getDestPrefix());
609 if (rdToElanOpEntry != null) {
610 if (vpnToDpnList!=null) {
611 for(VpnToDpnList curDpn : vpnToDpnList) {
612 makeConnectedRoute(curDpn.getDpnId(),vpnInstance.getVpnId(),vrfEntry,vrfTableKey
613 .getRouteDistinguisher(), null,NwConstants.DEL_FLOW);
614 makeLFibTableEntry(curDpn.getDpnId(),vrfEntry.getLabel(),null,
615 vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
616 // TODO DeleteTunnelTableEntry();
619 //Delete rd-to-elan-op-entry
620 InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(vrfTableKey.getRouteDistinguisher(),
621 vrfEntry.getDestPrefix());
622 MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL,id);
623 FibUtil.releaseId(idManager,FibConstants.VPN_IDPOOL_NAME,
624 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
627 BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(),
628 vrfTableKey.getRouteDistinguisher(), vrfEntry);
629 if (vpnToDpnList != null) {
630 for (VpnToDpnList curDpn : vpnToDpnList) {
631 if (!curDpn.getDpnId().equals(localDpnId)) {
632 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry);
636 //The flow/group entry has been deleted from config DS; need to clean up associated operational
637 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
638 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
641 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
642 final long vpnId, final VrfTablesKey vrfTableKey,
643 final VrfEntry vrfEntry) {
644 LOG.debug("deleting route "+ vrfEntry.getDestPrefix() + " "+vpnId);
645 String rd = vrfTableKey.getRouteDistinguisher();
646 boolean isRemoteRoute = true;
647 if (localDpnId == null) {
648 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
649 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
650 if(localNextHopInfo == null) {
651 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
652 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
653 if (extra_route != null) {
654 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp());
657 if (localNextHopInfo != null) {
658 isRemoteRoute = (!remoteDpnId.equals(localNextHopInfo.getDpnId()));
662 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
663 LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId);
665 LOG.debug("Did not delete fib entry rd: {} =, prefix: {} as it is local to dpn {}", rd, vrfEntry.getDestPrefix(), remoteDpnId);
669 private long getIpAddress(byte[] rawIpAddress) {
670 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
671 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
674 private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
675 List<InstructionInfo> instructions, int addOrRemove) { LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
676 String values[] = vrfEntry.getDestPrefix().split("/");
677 String ipAddress = values[0];
678 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
679 LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength);
680 InetAddress destPrefix = null;
682 destPrefix = InetAddress.getByName(ipAddress);
683 } catch (UnknownHostException e) {
684 LOG.error("UnknowHostException in addRoute. Failed to add Route for ipPrefix {}", vrfEntry.getDestPrefix());
688 List<MatchInfo> matches = new ArrayList<MatchInfo>();
690 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
691 BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
693 matches.add(new MatchInfo(MatchFieldType.eth_type,
694 new long[] { 0x0800L }));
696 if(prefixLength != 0) {
697 matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
698 destPrefix.getHostAddress(), Integer.toString(prefixLength)}));
701 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, destPrefix);
703 FlowEntity flowEntity;
705 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
706 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
707 priority, flowRef, 0, 0,
708 COOKIE_VM_FIB_TABLE, matches, instructions);
710 if (addOrRemove == NwConstants.ADD_FLOW) {
711 /* We need to call sync API to install flow so that 2 DS operations on the same object do not
712 * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
713 * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
714 * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
715 * wait indefinitely. */
716 mdsalManager.syncInstallFlow(flowEntity, 1);
718 mdsalManager.syncRemoveFlow(flowEntity, 1);
722 private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions,
723 String nextHop, int addOrRemove) {
724 List<MatchInfo> matches = new ArrayList<MatchInfo>();
725 matches.add(new MatchInfo(MatchFieldType.eth_type,
726 new long[] { 0x8847L }));
727 matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
729 // Install the flow entry in L3_LFIB_TABLE
730 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, nextHop);
732 FlowEntity flowEntity;
733 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef,
734 DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
735 COOKIE_VM_LFIB_TABLE, matches, instructions);
737 if (addOrRemove == NwConstants.ADD_FLOW) {
738 /* We need to call sync API to install flow so that 2 DS operations on the same object do not
739 * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
740 * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
741 * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
742 * wait indefinitely. */
744 mdsalManager.syncInstallFlow(flowEntity, 1);
746 mdsalManager.syncRemoveFlow(flowEntity, 1);
748 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} modified successfully {}",dpId, label, instructions );
751 private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
752 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
754 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
755 } catch (NullPointerException e) {
760 public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) {
761 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
762 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
763 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
764 synchronized (lockOnDpnVpn.intern()) {
765 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
766 if (vrfTable.isPresent()) {
767 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
768 RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, rd,
769 vrfEntry.getDestPrefix());
770 if (rdToElanOpEntry!= null) {
771 installSubnetRouteInFib(dpnId, rdToElanOpEntry, vpnId, vrfEntry);
774 // Passing null as we don't know the dpn
775 // to which prefix is attached at this point
776 createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
782 public void populateFibOnDpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
783 LOG.trace("dpn {} for vpn {}, nexthopIp {} : populateFibOnDpn", dpnId, rd, nexthopIp);
784 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
785 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
786 synchronized (lockOnDpnVpn.intern()) {
787 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
788 if (vrfTable.isPresent()) {
789 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
790 // Passing null as we don't know the dpn
791 // to which prefix is attached at this point
792 if (nexthopIp == vrfEntry.getNextHopAddress()) {
793 createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
800 public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) {
801 LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
802 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
803 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
804 synchronized (lockOnDpnVpn.intern()) {
805 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
806 if (vrfTable.isPresent()) {
807 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
808 /* Handle subnet routes here */
809 RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker, rd,
810 vrfEntry.getDestPrefix());
811 if (rdToElanOpEntry != null) {
812 LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(),
814 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
815 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null,
816 vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
819 // Passing null as we don't know the dpn
820 // to which prefix is attached at this point
821 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
827 public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
828 LOG.trace("dpn {} for vpn {}, nexthopIp {} : cleanUpDpnForVpn", dpnId, rd, nexthopIp);
829 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
830 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
831 synchronized (lockOnDpnVpn.intern()) {
832 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
833 if (vrfTable.isPresent()) {
834 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
835 // Passing null as we don't know the dpn
836 // to which prefix is attached at this point
837 if (nexthopIp == vrfEntry.getNextHopAddress()) {
838 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
845 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
846 InstanceIdentifierBuilder<VrfTables> idBuilder =
847 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
848 InstanceIdentifier<VrfTables> id = idBuilder.build();
852 private String getFlowRef(BigInteger dpnId, short tableId, long label, String nextHop) {
853 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
854 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
855 .append(label).append(NwConstants.FLOWID_SEPARATOR)
856 .append(nextHop).toString();
859 private String getFlowRef(BigInteger dpnId, short tableId, String rd, InetAddress destPrefix) {
860 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
861 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
862 .append(rd).append(NwConstants.FLOWID_SEPARATOR)
863 .append(destPrefix.getHostAddress()).toString();
866 protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId,
867 final long vpnId, final VrfEntry vrfEntry, String rd) {
868 String adjacency = null;
869 boolean staticRoute = false;
870 LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry);
872 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
873 if(extra_route != null) {
878 nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId,
879 (staticRoute == true) ? extra_route.getNexthopIp() + "/32" : vrfEntry.getDestPrefix(),
880 vrfEntry.getNextHopAddress());
881 } catch (NullPointerException e) {
887 protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
888 InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.create(VpnInstanceOpData.class).child(
889 VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
890 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
891 if(vpnInstanceOpData.isPresent()) {
892 return vpnInstanceOpData.get();
897 public void processNodeAdd(BigInteger dpnId) {
898 LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
899 makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
900 makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
903 private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
904 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
905 // Instruction to goto L3 InterfaceTable
906 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
907 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE }));
908 List<MatchInfo> matches = new ArrayList<MatchInfo>();
909 FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE,
910 getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW),
911 NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
913 FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE, getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, NwConstants.TABLE_MISS_FLOW),
914 NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow", 0, 0, COOKIE_VM_FIB_TABLE,
915 matches, instructions);
917 if (addOrRemove == NwConstants.ADD_FLOW) {
918 LOG.debug("Invoking MDSAL to install Table Miss Entries");
919 mdsalManager.installFlow(flowEntityLfib);
920 mdsalManager.installFlow(flowEntityFib);
922 mdsalManager.removeFlow(flowEntityLfib);
923 mdsalManager.removeFlow(flowEntityFib);
928 private String getFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
929 return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
930 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
931 .append(FLOWID_PREFIX).toString();
935 * Install flow entry in protocol table to forward mpls
936 * coming through gre tunnel to LFIB table.
938 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
939 final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
940 // Instruction to goto L3 InterfaceTable
941 List<InstructionInfo> instructions = new ArrayList<>();
942 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
943 List<MatchInfo> matches = new ArrayList<MatchInfo>();
944 matches.add(new MatchInfo(MatchFieldType.eth_type,
945 new long[] { 0x8847L }));
946 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_PROTOCOL_TABLE,
947 getFlowRef(dpnId, NwConstants.L3_PROTOCOL_TABLE,
948 NwConstants.L3_LFIB_TABLE),
949 DEFAULT_FIB_FLOW_PRIORITY,
950 "Protocol Table For LFIB",
952 COOKIE_PROTOCOL_TABLE,
953 matches, instructions);
955 if (addOrRemove == NwConstants.ADD_FLOW) {
956 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
957 mdsalManager.installFlow(flowEntityToLfib);
959 mdsalManager.removeFlow(flowEntityToLfib);
963 public List<String> printFibEntries() {
964 List<String> result = new ArrayList<String>();
965 result.add(String.format(" %-7s %-20s %-20s %-7s", "RD", "Prefix", "Nexthop", "Label"));
966 result.add("-------------------------------------------------------------------");
967 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
968 Optional<FibEntries> fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
969 if (fibEntries.isPresent()) {
970 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
971 for (VrfTables vrfTable : vrfTables) {
972 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
973 result.add(String.format(" %-7s %-20s %-20s %-7s", vrfTable.getRouteDistinguisher(),
974 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress(), vrfEntry.getLabel()));
981 private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) {
982 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
983 List<MatchInfo> matches = new ArrayList<MatchInfo>();
984 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
985 // Instruction to clear metadata except SI and LportTag bits
986 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] {
987 CLEAR_METADATA, METADATA_MASK_CLEAR }));
988 // Instruction to clear action
989 instructions.add(new InstructionInfo(InstructionType.clear_actions));
990 // Instruction to goto L3 InterfaceTable
992 List <ActionInfo> actionsInfos = new ArrayList <ActionInfo> ();
993 actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{
994 Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)}));
995 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
996 //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE }));
998 FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE,
999 getFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW),
1000 NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
1001 if (addOrRemove == NwConstants.ADD_FLOW) {
1002 LOG.info("Invoking MDSAL to install L3 interface Table Miss Entries");
1003 mdsalManager.installFlow(flowEntityL3Intf);
1005 mdsalManager.removeFlow(flowEntityL3Intf);