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.itm.rpcs.rev151217.ItmRpcService;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.Vpn;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.VpnKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeMplsOverGre;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeInputBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeOutput;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies;
78 import org.opendaylight.yangtools.concepts.ListenerRegistration;
79 import org.opendaylight.yangtools.yang.binding.DataObject;
80 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
81 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
82 import org.opendaylight.yangtools.yang.common.RpcResult;
83 import org.slf4j.Logger;
84 import org.slf4j.LoggerFactory;
86 public class FibManager extends AbstractDataChangeListener<VrfEntry> implements AutoCloseable{
87 private static final Logger LOG = LoggerFactory.getLogger(FibManager.class);
88 private static final String FLOWID_PREFIX = "L3.";
89 private ListenerRegistration<DataChangeListener> listenerRegistration;
90 private final DataBroker broker;
91 private IMdsalApiManager mdsalManager;
92 private IVpnManager vpnmanager;
93 private NexthopManager nextHopManager;
94 private ItmRpcService itmManager;
95 private OdlInterfaceRpcService interfaceManager;
96 private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
97 private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16);
98 private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
99 private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16);
100 private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0);
101 public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
104 public FibManager(final DataBroker db) {
105 super(VrfEntry.class);
107 registerListener(db);
111 public void close() throws Exception {
112 if (listenerRegistration != null) {
114 listenerRegistration.close();
115 } catch (final Exception e) {
116 LOG.error("Error when cleaning up DataChangeListener.", e);
118 listenerRegistration = null;
120 LOG.info("Fib Manager Closed");
123 public void setNextHopManager(NexthopManager nextHopManager) {
124 this.nextHopManager = nextHopManager;
127 public void setMdsalManager(IMdsalApiManager mdsalManager) {
128 this.mdsalManager = mdsalManager;
131 public void setVpnmanager(IVpnManager vpnmanager) {
132 this.vpnmanager = vpnmanager;
135 public void setITMRpcService(ItmRpcService itmManager) {
136 this.itmManager = itmManager;
139 public void setInterfaceManager(OdlInterfaceRpcService ifManager) {
140 this.interfaceManager = ifManager;
143 private void registerListener(final DataBroker db) {
145 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
146 getWildCardPath(), FibManager.this, DataChangeScope.SUBTREE);
147 } catch (final Exception e) {
148 LOG.error("FibManager DataChange listener registration fail!", e);
149 throw new IllegalStateException("FibManager registration Listener failed.", e);
154 private InstanceIdentifier<VrfEntry> getWildCardPath() {
155 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
160 protected void add(final InstanceIdentifier<VrfEntry> identifier,
161 final VrfEntry vrfEntry) {
162 LOG.trace("key: " + identifier + ", value=" + vrfEntry );
163 createFibEntries(identifier, vrfEntry);
167 protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
168 LOG.trace("key: " + identifier + ", value=" + vrfEntry);
169 deleteFibEntries(identifier, vrfEntry);
173 protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
174 LOG.trace("key: " + identifier + ", original=" + original + ", update=" + update );
175 createFibEntries(identifier, update);
178 private void createFibEntries(final InstanceIdentifier<VrfEntry> identifier,
179 final VrfEntry vrfEntry) {
180 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
181 Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
182 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
184 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
185 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
186 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + "has null vpnId!");
188 Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
189 Long vpnId = vpnInstance.getVpnId();
190 RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, vrfTableKey.getRouteDistinguisher(),
191 vrfEntry.getDestPrefix());
192 if (rdToElanOpEntry!=null) {
193 if (vpnToDpnList!=null) {
194 for (VpnToDpnList curDpn : vpnToDpnList) {
195 installSubnetRouteInFib(curDpn.getDpnId(), rdToElanOpEntry, vpnId.longValue(), vrfEntry);
200 BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(),
201 vrfTableKey.getRouteDistinguisher(), vrfEntry);
202 if (vpnToDpnList != null) {
203 for (VpnToDpnList curDpn : vpnToDpnList) {
204 if (!curDpn.getDpnId().equals(localDpnId)) {
205 createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(),
206 vrfTableKey, vrfEntry);
212 private void installSubnetRouteInFib(BigInteger dpnId, RdToElanOpEntry rdToElanOpEntry,
213 long vpnId, VrfEntry vrfEntry){
214 makeSubnetRouteFlow(dpnId);
215 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
216 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
217 Long elanTag = rdToElanOpEntry.getElanTag();
218 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
219 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
220 makeConnectedRoute(dpnId,vpnId,vrfEntry,rdToElanOpEntry.getRd(),
221 instructions,NwConstants.ADD_FLOW);
222 makeLFibTableEntry(dpnId,vrfEntry.getLabel(),instructions,
223 vrfEntry.getNextHopAddress(),NwConstants.ADD_FLOW);
224 // TODO makeTunnelTableEntry();
227 private RdToElanOpEntry getRdToElanOpEntry(DataBroker broker, String rd, String subnetIp) {
228 InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(rd,subnetIp);
229 Optional<RdToElanOpEntry> sn = read(broker, LogicalDatastoreType.OPERATIONAL, id);
236 private InstanceIdentifier<RdToElanOpEntry> getRdToElanOpEntryDataPath(String rd, String subnetIp) {
237 return InstanceIdentifier.builder(RdToElanOp.class).child(RdToElanOpEntry.class,
238 new RdToElanOpEntryKey(rd,subnetIp)).build();
240 private <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
241 InstanceIdentifier<T> path) {
243 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
245 Optional<T> result = Optional.absent();
247 result = tx.read(datastoreType, path).get();
248 } catch (Exception e) {
249 throw new RuntimeException(e);
255 private void makeSubnetRouteFlow(BigInteger dpnId) {
257 final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
258 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
259 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
260 actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{}));
261 instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
262 List<MatchInfo> matches = new ArrayList<MatchInfo>();
263 String flowRef = getFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, NwConstants.TABLE_MISS_FLOW);
264 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef,
265 NwConstants.TABLE_MISS_PRIORITY, "Subnet Route Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
267 LOG.debug("Invoking MDSAL to install Table Miss Entries");
268 mdsalManager.syncInstallFlow(flowEntity,1);
271 private Collection<BigInteger> getDpnsForVpn(VpnInstanceOpDataEntry vpnInstance) {
272 Collection<BigInteger> dpns = new HashSet<>();
273 for(VpnToDpnList dpn : vpnInstance.getVpnToDpnList()) {
274 dpns.add(dpn.getDpnId());
280 public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
281 BigInteger localDpnId = BigInteger.ZERO;
282 Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
283 String localNextHopIP = vrfEntry.getDestPrefix();
285 if(localNextHopInfo == null) {
286 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
287 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
288 if (extra_route != null) {
289 localNextHopInfo = getPrefixToInterface(vpnId, extra_route.getNexthopIp() + "/32");
290 localNextHopIP = extra_route.getNexthopIp() + "/32";
294 if(localNextHopInfo != null) {
295 localDpnId = localNextHopInfo.getDpnId();
296 long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
298 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
299 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
301 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
302 instructions.add(new InstructionInfo(InstructionType.write_actions,actionsInfos));
303 makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
305 actionsInfos=new ArrayList<ActionInfo>();;
306 instructions=new ArrayList<InstructionInfo>();
307 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
308 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
309 instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
310 makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), instructions, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW);
312 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
313 localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
314 makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId);
320 private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/) {
321 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
322 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
325 createTerminatingServiceActions(dpId, (int)label, actionsInfos);
327 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully {}",
328 dpId, label, groupId);
331 public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos) {
332 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
334 LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
337 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
338 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
340 List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
341 mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
343 FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
344 getFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
345 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
347 mdsalManager.installFlow(terminatingServiceTableFlowEntity);
350 private void removeTunnelTableEntry(BigInteger dpId, long label) {
351 FlowEntity flowEntity;
352 LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
353 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
355 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
356 flowEntity = MDSALUtil.buildFlowEntity(dpId,
357 NwConstants.INTERNAL_TUNNEL_TABLE,
358 getFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
359 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
360 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
361 mdsalManager.removeFlow(flowEntity);
362 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpId, label);
365 public BigInteger deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
366 BigInteger localDpnId = BigInteger.ZERO;
367 boolean isExtraRoute = false;
368 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
369 String localNextHopIP = vrfEntry.getDestPrefix();
371 if(localNextHopInfo == null) {
372 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
373 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
374 if (extra_route != null) {
375 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp() + "/32");
376 localNextHopIP = extra_route.getNexthopIp() + "/32";
382 if(localNextHopInfo != null) {
383 localDpnId = localNextHopInfo.getDpnId();
384 Prefixes prefix = getPrefixToInterface(vpnId, isExtraRoute ? localNextHopIP : vrfEntry.getDestPrefix());
385 makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */,
386 NwConstants.DEL_FLOW);
387 makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), null /* invalid */,
388 vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW);
389 removeTunnelTableEntry(localDpnId, vrfEntry.getLabel());
390 deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP);
395 private InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) {
396 return InstanceIdentifier.builder(PrefixToInterface.class)
397 .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
400 private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
401 Optional<Prefixes> localNextHopInfoData =
402 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
403 return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
406 private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
407 return InstanceIdentifier.builder(VpnToExtraroute.class)
408 .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class,
409 new ExtrarouteKey(ipPrefix)).build();
412 private Extraroute getVpnToExtraroute(String rd, String ipPrefix) {
413 Optional<Extraroute> extraRouteInfo =
414 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix));
415 return extraRouteInfo.isPresent() ? extraRouteInfo.get() : null;
419 private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
421 Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
422 new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
423 RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
424 if(!rpcResult.isSuccessful()) {
425 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
427 return rpcResult.getResult().getTunnelType();
430 } catch (InterruptedException | ExecutionException e) {
431 LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e);
437 private void createRemoteFibEntry(final BigInteger localDpnId, final BigInteger remoteDpnId,
438 final long vpnId, final VrfTablesKey vrfTableKey,
439 final VrfEntry vrfEntry) {
440 String rd = vrfTableKey.getRouteDistinguisher();
441 LOG.debug("adding route " + vrfEntry.getDestPrefix() + " " + rd);
442 /********************************************/
443 String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd);
444 if(tunnelInterface == null) {
445 LOG.error("Could not get interface for nexthop: {} in vpn {}",
446 vrfEntry.getNextHopAddress(), rd);
447 LOG.warn("Failed to add Route: {} in vpn: {}",
448 vrfEntry.getDestPrefix(), rd);
451 List<ActionInfo> actionInfos = new ArrayList<>();
452 Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
453 if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
454 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
455 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
456 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
458 int label = vrfEntry.getLabel().intValue();
460 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
461 if(tunnel_type.equals(TunnelTypeVxlan.class)) {
462 tunnelId = BigInteger.valueOf(label);
464 tunnelId = BigInteger.valueOf(label);
466 LOG.debug("adding set tunnel id action for label {}", label);
467 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{
470 actionInfos.addAll(nextHopManager.getEgressActionsForInterface(tunnelInterface));
471 List<InstructionInfo> instructions= new ArrayList<InstructionInfo>();
472 instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
474 List<ActionInfo> actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry);
475 if(actionInfos == null) {
476 LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}",
477 vrfEntry.getNextHopAddress(), rd);
478 LOG.warn("Failed to add Route: {} in vpn: {}",
479 vrfEntry.getDestPrefix(), rd);
482 BigInteger dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getDestPrefix());
484 //This route may be extra route... try to query with nexthop Ip
485 LOG.debug("Checking for extra route to install remote fib entry {}", vrfEntry.getDestPrefix());
486 dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getNextHopAddress() + "/32");
489 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
490 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
491 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
493 int label = vrfEntry.getLabel().intValue();
494 LOG.debug("adding set tunnel id action for label {}", label);
495 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
496 MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label),
497 MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
500 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
501 LOG.debug("Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId);
504 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
505 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
506 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
507 if (dpnInVpn.isPresent()) {
508 List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
509 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
510 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
511 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();
513 if (vpnInterfaces.remove(currVpnInterface)) {
514 if (vpnInterfaces.isEmpty()) {
515 LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
516 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id);
517 cleanUpDpnForVpn(dpnId, vpnId, rd);
519 LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
520 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
521 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
522 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
523 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)));
529 private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
530 /* Get interface info from prefix to interface mapping;
531 Use the interface info to get the corresponding vpn interface op DS entry,
532 remove the adjacency corresponding to this fib entry.
533 If adjacency removed is the last adjacency, clean up the following:
534 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
535 - prefix to interface entry
536 - vpn interface op DS
538 Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
539 Extraroute extraRoute = null;
540 if (prefixInfo == null) {
541 extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
542 if(extraRoute != null) {
543 prefixInfo = getPrefixToInterface(vpnId, extraRoute.getNexthopIp() + "/32");
544 //clean up the vpn to extra route entry in DS
545 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
548 if (prefixInfo == null) {
549 LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for " + vrfEntry.getDestPrefix());
550 return; //Don't have any info for this prefix (shouldn't happen); need to return
552 String ifName = prefixInfo.getVpnInterfaceName();
553 Optional<Adjacencies> optAdjacencies = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getAdjListPath(ifName));
555 if (optAdjacencies.isPresent()) {
556 numAdj = optAdjacencies.get().getAdjacency().size();
558 LOG.trace("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix());
559 //remove adjacency corr to prefix
561 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
562 FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
565 if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
566 //clean up the vpn interface from DpnToVpn list
567 LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
568 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
569 FibUtil.getVpnInterfaceIdentifier(ifName));
573 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier,
574 final VrfEntry vrfEntry) {
575 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
576 Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
577 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
579 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
580 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
581 Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
582 RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker,vrfTableKey.getRouteDistinguisher(),
583 vrfEntry.getDestPrefix());
584 if (rdToElanOpEntry != null) {
585 if (vpnToDpnList!=null) {
586 for(VpnToDpnList curDpn : vpnToDpnList) {
587 makeConnectedRoute(curDpn.getDpnId(),vpnInstance.getVpnId(),vrfEntry,vrfTableKey
588 .getRouteDistinguisher(), null,NwConstants.DEL_FLOW);
589 makeLFibTableEntry(curDpn.getDpnId(),vrfEntry.getLabel(),null,
590 vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
591 // TODO DeleteTunnelTableEntry();
594 //Delete rd-to-elan-op-entry
595 InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(vrfTableKey.getRouteDistinguisher(),
596 vrfEntry.getDestPrefix());
597 MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL,id);
600 BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(),
601 vrfTableKey.getRouteDistinguisher(), vrfEntry);
602 if (vpnToDpnList != null) {
603 for (VpnToDpnList curDpn : vpnToDpnList) {
604 if (!curDpn.getDpnId().equals(localDpnId)) {
605 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry);
609 //The flow/group entry has been deleted from config DS; need to clean up associated operational
610 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
611 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
614 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
615 final long vpnId, final VrfTablesKey vrfTableKey,
616 final VrfEntry vrfEntry) {
617 LOG.debug("deleting route "+ vrfEntry.getDestPrefix() + " "+vpnId);
618 String rd = vrfTableKey.getRouteDistinguisher();
619 boolean isRemoteRoute = true;
620 if (localDpnId == null) {
621 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
622 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
623 if(localNextHopInfo == null) {
624 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
625 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
626 if (extra_route != null) {
627 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp());
630 if (localNextHopInfo != null) {
631 isRemoteRoute = (!remoteDpnId.equals(localNextHopInfo.getDpnId()));
635 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
636 LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId);
638 LOG.debug("Did not delete fib entry rd: {} =, prefix: {} as it is local to dpn {}", rd, vrfEntry.getDestPrefix(), remoteDpnId);
642 private long getIpAddress(byte[] rawIpAddress) {
643 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
644 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
647 private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
648 List<InstructionInfo> instructions, int addOrRemove) { LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
649 String values[] = vrfEntry.getDestPrefix().split("/");
650 String ipAddress = values[0];
651 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
652 LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength);
653 InetAddress destPrefix = null;
655 destPrefix = InetAddress.getByName(ipAddress);
656 } catch (UnknownHostException e) {
657 LOG.error("UnknowHostException in addRoute. Failed to add Route for ipPrefix {}", vrfEntry.getDestPrefix());
661 List<MatchInfo> matches = new ArrayList<MatchInfo>();
663 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
664 BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
666 matches.add(new MatchInfo(MatchFieldType.eth_type,
667 new long[] { 0x0800L }));
669 if(prefixLength != 0) {
670 matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
671 destPrefix.getHostAddress(), Integer.toString(prefixLength)}));
674 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, destPrefix);
676 FlowEntity flowEntity;
678 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
679 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
680 priority, flowRef, 0, 0,
681 COOKIE_VM_FIB_TABLE, matches, instructions);
683 if (addOrRemove == NwConstants.ADD_FLOW) {
684 /* We need to call sync API to install flow so that 2 DS operations on the same object do not
685 * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
686 * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
687 * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
688 * wait indefinitely. */
689 mdsalManager.syncInstallFlow(flowEntity, 1);
691 mdsalManager.syncRemoveFlow(flowEntity, 1);
695 private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions,
696 String nextHop, int addOrRemove) {
697 List<MatchInfo> matches = new ArrayList<MatchInfo>();
698 matches.add(new MatchInfo(MatchFieldType.eth_type,
699 new long[] { 0x8847L }));
700 matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
702 // Install the flow entry in L3_LFIB_TABLE
703 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, nextHop);
705 FlowEntity flowEntity;
706 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef,
707 DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
708 COOKIE_VM_LFIB_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. */
717 mdsalManager.syncInstallFlow(flowEntity, 1);
719 mdsalManager.syncRemoveFlow(flowEntity, 1);
721 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} modified successfully {}",dpId, label, instructions );
724 private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
725 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
727 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
728 } catch (NullPointerException e) {
733 public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) {
734 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
735 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
736 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
737 synchronized (lockOnDpnVpn.intern()) {
738 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
739 if (vrfTable.isPresent()) {
740 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
741 RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, rd,
742 vrfEntry.getDestPrefix());
743 if (rdToElanOpEntry!= null) {
744 installSubnetRouteInFib(dpnId, rdToElanOpEntry, vpnId, vrfEntry);
747 // Passing null as we don't know the dpn
748 // to which prefix is attached at this point
749 createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
755 public void populateFibOnDpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
756 LOG.trace("dpn {} for vpn {}, nexthopIp {} : populateFibOnDpn", dpnId, rd, nexthopIp);
757 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
758 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
759 synchronized (lockOnDpnVpn.intern()) {
760 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
761 if (vrfTable.isPresent()) {
762 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
763 // Passing null as we don't know the dpn
764 // to which prefix is attached at this point
765 if (nexthopIp == vrfEntry.getNextHopAddress()) {
766 createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
773 public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) {
774 LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
775 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
776 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
777 synchronized (lockOnDpnVpn.intern()) {
778 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
779 if (vrfTable.isPresent()) {
780 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
781 /* Handle subnet routes here */
782 RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker, rd,
783 vrfEntry.getDestPrefix());
784 if (rdToElanOpEntry != null) {
785 LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(),
787 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
788 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null,
789 vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
792 // Passing null as we don't know the dpn
793 // to which prefix is attached at this point
794 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
800 public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
801 LOG.trace("dpn {} for vpn {}, nexthopIp {} : cleanUpDpnForVpn", dpnId, rd, nexthopIp);
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 // Passing null as we don't know the dpn
809 // to which prefix is attached at this point
810 if (nexthopIp == vrfEntry.getNextHopAddress()) {
811 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
818 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
819 InstanceIdentifierBuilder<VrfTables> idBuilder =
820 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
821 InstanceIdentifier<VrfTables> id = idBuilder.build();
825 private String getFlowRef(BigInteger dpnId, short tableId, long label, String nextHop) {
826 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
827 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
828 .append(label).append(NwConstants.FLOWID_SEPARATOR)
829 .append(nextHop).toString();
832 private String getFlowRef(BigInteger dpnId, short tableId, String rd, InetAddress destPrefix) {
833 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
834 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
835 .append(rd).append(NwConstants.FLOWID_SEPARATOR)
836 .append(destPrefix.getHostAddress()).toString();
839 protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId,
840 final long vpnId, final VrfEntry vrfEntry, String rd) {
841 String adjacency = null;
842 boolean staticRoute = false;
843 LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry);
845 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
846 if(extra_route != null) {
851 nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId,
852 (staticRoute == true) ? extra_route.getNexthopIp() + "/32" : vrfEntry.getDestPrefix(),
853 vrfEntry.getNextHopAddress());
854 } catch (NullPointerException e) {
860 protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
861 InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.create(VpnInstanceOpData.class).child(
862 VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
863 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
864 if(vpnInstanceOpData.isPresent()) {
865 return vpnInstanceOpData.get();
870 public void processNodeAdd(BigInteger dpnId) {
871 LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
872 makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
873 makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
876 private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
877 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
878 // Instruction to goto L3 InterfaceTable
879 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
880 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE }));
881 List<MatchInfo> matches = new ArrayList<MatchInfo>();
882 FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE,
883 getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW),
884 NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
886 FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE, getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, NwConstants.TABLE_MISS_FLOW),
887 NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow", 0, 0, COOKIE_VM_FIB_TABLE,
888 matches, instructions);
890 if (addOrRemove == NwConstants.ADD_FLOW) {
891 LOG.debug("Invoking MDSAL to install Table Miss Entries");
892 mdsalManager.installFlow(flowEntityLfib);
893 mdsalManager.installFlow(flowEntityFib);
895 mdsalManager.removeFlow(flowEntityLfib);
896 mdsalManager.removeFlow(flowEntityFib);
901 private String getFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
902 return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
903 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
904 .append(FLOWID_PREFIX).toString();
908 * Install flow entry in protocol table to forward mpls
909 * coming through gre tunnel to LFIB table.
911 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
912 final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
913 // Instruction to goto L3 InterfaceTable
914 List<InstructionInfo> instructions = new ArrayList<>();
915 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
916 List<MatchInfo> matches = new ArrayList<MatchInfo>();
917 matches.add(new MatchInfo(MatchFieldType.eth_type,
918 new long[] { 0x8847L }));
919 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_PROTOCOL_TABLE,
920 getFlowRef(dpnId, NwConstants.L3_PROTOCOL_TABLE,
921 NwConstants.L3_LFIB_TABLE),
922 DEFAULT_FIB_FLOW_PRIORITY,
923 "Protocol Table For LFIB",
925 COOKIE_PROTOCOL_TABLE,
926 matches, instructions);
928 if (addOrRemove == NwConstants.ADD_FLOW) {
929 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
930 mdsalManager.installFlow(flowEntityToLfib);
932 mdsalManager.removeFlow(flowEntityToLfib);
936 public List<String> printFibEntries() {
937 List<String> result = new ArrayList<String>();
938 result.add(String.format(" %-7s %-20s %-20s %-7s", "RD", "Prefix", "Nexthop", "Label"));
939 result.add("-------------------------------------------------------------------");
940 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
941 Optional<FibEntries> fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
942 if (fibEntries.isPresent()) {
943 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
944 for (VrfTables vrfTable : vrfTables) {
945 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
946 result.add(String.format(" %-7s %-20s %-20s %-7s", vrfTable.getRouteDistinguisher(),
947 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress(), vrfEntry.getLabel()));
954 private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) {
955 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
956 List<MatchInfo> matches = new ArrayList<MatchInfo>();
957 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
958 // Instruction to clear metadata except SI and LportTag bits
959 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] {
960 CLEAR_METADATA, METADATA_MASK_CLEAR }));
961 // Instruction to clear action
962 instructions.add(new InstructionInfo(InstructionType.clear_actions));
963 // Instruction to goto L3 InterfaceTable
965 List <ActionInfo> actionsInfos = new ArrayList <ActionInfo> ();
966 actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{
967 Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)}));
968 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
969 //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE }));
971 FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE,
972 getFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW),
973 NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
974 if (addOrRemove == NwConstants.ADD_FLOW) {
975 LOG.info("Invoking MDSAL to install L3 interface Table Miss Entries");
976 mdsalManager.installFlow(flowEntityL3Intf);
978 mdsalManager.removeFlow(flowEntityL3Intf);