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 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
222 Long elanTag = rdToElanOpEntry.getElanTag();
224 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
225 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
226 makeConnectedRoute(dpnId,vpnId,vrfEntry,rdToElanOpEntry.getRd(),
227 instructions,NwConstants.ADD_FLOW);
229 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
230 // reinitialize instructions list for LFIB Table
231 instructions = new ArrayList<InstructionInfo>();
233 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
234 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
235 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
236 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
238 makeLFibTableEntry(dpnId,vrfEntry.getLabel(),instructions,
239 vrfEntry.getNextHopAddress(),NwConstants.ADD_FLOW);
240 // TODO makeTunnelTableEntry();
243 private RdToElanOpEntry getRdToElanOpEntry(DataBroker broker, String rd, String subnetIp) {
244 InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(rd,subnetIp);
245 Optional<RdToElanOpEntry> sn = read(broker, LogicalDatastoreType.OPERATIONAL, id);
252 private InstanceIdentifier<RdToElanOpEntry> getRdToElanOpEntryDataPath(String rd, String subnetIp) {
253 return InstanceIdentifier.builder(RdToElanOp.class).child(RdToElanOpEntry.class,
254 new RdToElanOpEntryKey(rd,subnetIp)).build();
256 private <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
257 InstanceIdentifier<T> path) {
259 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
261 Optional<T> result = Optional.absent();
263 result = tx.read(datastoreType, path).get();
264 } catch (Exception e) {
265 throw new RuntimeException(e);
271 private void makeSubnetRouteTableMissFlow(BigInteger dpnId, int addOrRemove) {
272 final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
273 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
274 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
275 actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{}));
276 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
277 List<MatchInfo> matches = new ArrayList<MatchInfo>();
278 String flowRef = getFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, NwConstants.TABLE_MISS_FLOW);
279 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef,
280 NwConstants.TABLE_MISS_PRIORITY, "Subnet Route Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
282 if (addOrRemove == NwConstants.ADD_FLOW) {
283 LOG.debug("Invoking MDSAL to install SubnetRoute Table Miss Entries for DPN" + dpnId);
284 mdsalManager.installFlow(flowEntity);
286 LOG.debug("Invoking MDSAL to remove SubnetRoute Table Miss Entries for DPN " + dpnId);
287 mdsalManager.removeFlow(flowEntity);
291 private Collection<BigInteger> getDpnsForVpn(VpnInstanceOpDataEntry vpnInstance) {
292 Collection<BigInteger> dpns = new HashSet<>();
293 for(VpnToDpnList dpn : vpnInstance.getVpnToDpnList()) {
294 dpns.add(dpn.getDpnId());
300 public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
301 BigInteger localDpnId = BigInteger.ZERO;
302 Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
303 String localNextHopIP = vrfEntry.getDestPrefix();
305 if(localNextHopInfo == null) {
306 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
307 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
308 if (extra_route != null) {
309 localNextHopInfo = getPrefixToInterface(vpnId, extra_route.getNexthopIp() + "/32");
310 localNextHopIP = extra_route.getNexthopIp() + "/32";
314 if(localNextHopInfo != null) {
315 localDpnId = localNextHopInfo.getDpnId();
316 long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
318 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
319 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
321 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
322 instructions.add(new InstructionInfo(InstructionType.write_actions,actionsInfos));
323 makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
325 actionsInfos=new ArrayList<ActionInfo>();;
326 instructions=new ArrayList<InstructionInfo>();
327 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
328 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
329 instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
330 makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), instructions, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW);
332 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
333 localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
334 makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId);
340 private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/) {
341 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
342 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
345 createTerminatingServiceActions(dpId, (int)label, actionsInfos);
347 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully {}",
348 dpId, label, groupId);
351 public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos) {
352 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
354 LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
357 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
358 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
360 List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
361 mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
363 FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
364 getFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
365 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
367 mdsalManager.installFlow(terminatingServiceTableFlowEntity);
370 private void removeTunnelTableEntry(BigInteger dpId, long label) {
371 FlowEntity flowEntity;
372 LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
373 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
375 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
376 flowEntity = MDSALUtil.buildFlowEntity(dpId,
377 NwConstants.INTERNAL_TUNNEL_TABLE,
378 getFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
379 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
380 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
381 mdsalManager.removeFlow(flowEntity);
382 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpId, label);
385 public BigInteger deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
386 BigInteger localDpnId = BigInteger.ZERO;
387 boolean isExtraRoute = false;
388 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
389 String localNextHopIP = vrfEntry.getDestPrefix();
391 if(localNextHopInfo == null) {
392 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
393 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
394 if (extra_route != null) {
395 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp() + "/32");
396 localNextHopIP = extra_route.getNexthopIp() + "/32";
402 if(localNextHopInfo != null) {
403 localDpnId = localNextHopInfo.getDpnId();
404 Prefixes prefix = getPrefixToInterface(vpnId, isExtraRoute ? localNextHopIP : vrfEntry.getDestPrefix());
405 makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */,
406 NwConstants.DEL_FLOW);
407 makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), null /* invalid */,
408 vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW);
409 removeTunnelTableEntry(localDpnId, vrfEntry.getLabel());
410 deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP);
415 private InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) {
416 return InstanceIdentifier.builder(PrefixToInterface.class)
417 .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
420 private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
421 Optional<Prefixes> localNextHopInfoData =
422 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
423 return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
426 private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
427 return InstanceIdentifier.builder(VpnToExtraroute.class)
428 .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class,
429 new ExtrarouteKey(ipPrefix)).build();
432 private Extraroute getVpnToExtraroute(String rd, String ipPrefix) {
433 Optional<Extraroute> extraRouteInfo =
434 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix));
435 return extraRouteInfo.isPresent() ? extraRouteInfo.get() : null;
439 private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
441 Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
442 new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
443 RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
444 if(!rpcResult.isSuccessful()) {
445 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
447 return rpcResult.getResult().getTunnelType();
450 } catch (InterruptedException | ExecutionException e) {
451 LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e);
457 private void createRemoteFibEntry(final BigInteger localDpnId, final BigInteger remoteDpnId,
458 final long vpnId, final VrfTablesKey vrfTableKey,
459 final VrfEntry vrfEntry) {
460 String rd = vrfTableKey.getRouteDistinguisher();
461 LOG.debug("adding route " + vrfEntry.getDestPrefix() + " " + rd);
462 /********************************************/
463 String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd);
464 if(tunnelInterface == null) {
465 LOG.error("Could not get interface for nexthop: {} in vpn {}",
466 vrfEntry.getNextHopAddress(), rd);
467 LOG.warn("Failed to add Route: {} in vpn: {}",
468 vrfEntry.getDestPrefix(), rd);
471 List<ActionInfo> actionInfos = new ArrayList<>();
472 Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
473 if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
474 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
475 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
476 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
478 int label = vrfEntry.getLabel().intValue();
480 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
481 if(tunnel_type.equals(TunnelTypeVxlan.class)) {
482 tunnelId = BigInteger.valueOf(label);
484 tunnelId = BigInteger.valueOf(label);
486 LOG.debug("adding set tunnel id action for label {}", label);
487 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{
490 actionInfos.addAll(nextHopManager.getEgressActionsForInterface(tunnelInterface));
491 List<InstructionInfo> instructions= new ArrayList<InstructionInfo>();
492 instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
494 List<ActionInfo> actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry);
495 if(actionInfos == null) {
496 LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}",
497 vrfEntry.getNextHopAddress(), rd);
498 LOG.warn("Failed to add Route: {} in vpn: {}",
499 vrfEntry.getDestPrefix(), rd);
502 BigInteger dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getDestPrefix());
504 //This route may be extra route... try to query with nexthop Ip
505 LOG.debug("Checking for extra route to install remote fib entry {}", vrfEntry.getDestPrefix());
506 dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getNextHopAddress() + "/32");
509 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
510 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
511 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
513 int label = vrfEntry.getLabel().intValue();
514 LOG.debug("adding set tunnel id action for label {}", label);
515 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
516 MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label),
517 MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
520 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
521 LOG.debug("Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId);
524 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
525 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
526 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
527 if (dpnInVpn.isPresent()) {
528 List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
529 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
530 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
531 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();
533 if (vpnInterfaces.remove(currVpnInterface)) {
534 if (vpnInterfaces.isEmpty()) {
535 LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
536 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id);
537 cleanUpDpnForVpn(dpnId, vpnId, rd);
539 LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
540 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
541 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
542 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
543 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)));
549 private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
550 /* Get interface info from prefix to interface mapping;
551 Use the interface info to get the corresponding vpn interface op DS entry,
552 remove the adjacency corresponding to this fib entry.
553 If adjacency removed is the last adjacency, clean up the following:
554 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
555 - prefix to interface entry
556 - vpn interface op DS
558 Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
559 Extraroute extraRoute = null;
560 if (prefixInfo == null) {
561 extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
562 if(extraRoute != null) {
563 prefixInfo = getPrefixToInterface(vpnId, extraRoute.getNexthopIp() + "/32");
564 //clean up the vpn to extra route entry in DS
565 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
568 if (prefixInfo == null) {
569 LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for " + vrfEntry.getDestPrefix());
570 return; //Don't have any info for this prefix (shouldn't happen); need to return
572 String ifName = prefixInfo.getVpnInterfaceName();
573 Optional<Adjacencies> optAdjacencies = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getAdjListPath(ifName));
575 if (optAdjacencies.isPresent()) {
576 numAdj = optAdjacencies.get().getAdjacency().size();
578 LOG.trace("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix());
579 //remove adjacency corr to prefix
581 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
582 FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
585 if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
586 //clean up the vpn interface from DpnToVpn list
587 LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
588 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
589 FibUtil.getVpnInterfaceIdentifier(ifName));
592 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
593 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
597 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier,
598 final VrfEntry vrfEntry) {
599 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
600 Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
601 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
603 String rd = vrfTableKey.getRouteDistinguisher();
604 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
605 if (vpnInstance == null) {
606 LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
609 Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
610 RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker,vrfTableKey.getRouteDistinguisher(),
611 vrfEntry.getDestPrefix());
612 if (rdToElanOpEntry != null) {
613 if (vpnToDpnList!=null) {
614 for(VpnToDpnList curDpn : vpnToDpnList) {
615 makeConnectedRoute(curDpn.getDpnId(),vpnInstance.getVpnId(),vrfEntry,vrfTableKey
616 .getRouteDistinguisher(), null,NwConstants.DEL_FLOW);
617 makeLFibTableEntry(curDpn.getDpnId(),vrfEntry.getLabel(),null,
618 vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
619 // TODO DeleteTunnelTableEntry();
622 //Delete rd-to-elan-op-entry
623 InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(vrfTableKey.getRouteDistinguisher(),
624 vrfEntry.getDestPrefix());
625 MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL,id);
626 FibUtil.releaseId(idManager,FibConstants.VPN_IDPOOL_NAME,
627 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
630 BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(),
631 vrfTableKey.getRouteDistinguisher(), vrfEntry);
632 if (vpnToDpnList != null) {
633 for (VpnToDpnList curDpn : vpnToDpnList) {
634 if (!curDpn.getDpnId().equals(localDpnId)) {
635 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry);
639 //The flow/group entry has been deleted from config DS; need to clean up associated operational
640 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
641 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
644 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
645 final long vpnId, final VrfTablesKey vrfTableKey,
646 final VrfEntry vrfEntry) {
647 LOG.debug("deleting route "+ vrfEntry.getDestPrefix() + " "+vpnId);
648 String rd = vrfTableKey.getRouteDistinguisher();
649 boolean isRemoteRoute = true;
650 if (localDpnId == null) {
651 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
652 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
653 if(localNextHopInfo == null) {
654 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
655 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
656 if (extra_route != null) {
657 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp());
660 if (localNextHopInfo != null) {
661 isRemoteRoute = (!remoteDpnId.equals(localNextHopInfo.getDpnId()));
665 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
666 LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId);
668 LOG.debug("Did not delete fib entry rd: {} =, prefix: {} as it is local to dpn {}", rd, vrfEntry.getDestPrefix(), remoteDpnId);
672 private long getIpAddress(byte[] rawIpAddress) {
673 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
674 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
677 private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
678 List<InstructionInfo> instructions, int addOrRemove) { LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
679 String values[] = vrfEntry.getDestPrefix().split("/");
680 String ipAddress = values[0];
681 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
682 LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength);
683 InetAddress destPrefix = null;
685 destPrefix = InetAddress.getByName(ipAddress);
686 } catch (UnknownHostException e) {
687 LOG.error("UnknowHostException in addRoute. Failed to add Route for ipPrefix {}", vrfEntry.getDestPrefix());
691 List<MatchInfo> matches = new ArrayList<MatchInfo>();
693 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
694 BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
696 matches.add(new MatchInfo(MatchFieldType.eth_type,
697 new long[] { 0x0800L }));
699 if(prefixLength != 0) {
700 matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
701 destPrefix.getHostAddress(), Integer.toString(prefixLength)}));
704 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, destPrefix);
706 FlowEntity flowEntity;
708 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
709 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
710 priority, flowRef, 0, 0,
711 COOKIE_VM_FIB_TABLE, matches, instructions);
713 if (addOrRemove == NwConstants.ADD_FLOW) {
714 /* We need to call sync API to install flow so that 2 DS operations on the same object do not
715 * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
716 * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
717 * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
718 * wait indefinitely. */
719 mdsalManager.syncInstallFlow(flowEntity, 1);
721 mdsalManager.syncRemoveFlow(flowEntity, 1);
725 private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions,
726 String nextHop, int addOrRemove) {
727 List<MatchInfo> matches = new ArrayList<MatchInfo>();
728 matches.add(new MatchInfo(MatchFieldType.eth_type,
729 new long[] { 0x8847L }));
730 matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
732 // Install the flow entry in L3_LFIB_TABLE
733 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, nextHop);
735 FlowEntity flowEntity;
736 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef,
737 DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
738 COOKIE_VM_LFIB_TABLE, matches, instructions);
740 if (addOrRemove == NwConstants.ADD_FLOW) {
741 /* We need to call sync API to install flow so that 2 DS operations on the same object do not
742 * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
743 * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
744 * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
745 * wait indefinitely. */
747 mdsalManager.syncInstallFlow(flowEntity, 1);
749 mdsalManager.syncRemoveFlow(flowEntity, 1);
751 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} modified successfully {}",dpId, label, instructions );
754 private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
755 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
757 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
758 } catch (NullPointerException e) {
763 public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) {
764 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
765 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
766 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
767 synchronized (lockOnDpnVpn.intern()) {
768 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
769 if (vrfTable.isPresent()) {
770 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
771 RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, rd,
772 vrfEntry.getDestPrefix());
773 if (rdToElanOpEntry!= null) {
774 installSubnetRouteInFib(dpnId, rdToElanOpEntry, vpnId, vrfEntry);
777 // Passing null as we don't know the dpn
778 // to which prefix is attached at this point
779 createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
785 public void populateFibOnDpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
786 LOG.trace("dpn {} for vpn {}, nexthopIp {} : populateFibOnDpn", dpnId, rd, nexthopIp);
787 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
788 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
789 synchronized (lockOnDpnVpn.intern()) {
790 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
791 if (vrfTable.isPresent()) {
792 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
793 // Passing null as we don't know the dpn
794 // to which prefix is attached at this point
795 if (nexthopIp == vrfEntry.getNextHopAddress()) {
796 createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
803 public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) {
804 LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
805 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
806 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
807 synchronized (lockOnDpnVpn.intern()) {
808 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
809 if (vrfTable.isPresent()) {
810 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
811 /* Handle subnet routes here */
812 RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker, rd,
813 vrfEntry.getDestPrefix());
814 if (rdToElanOpEntry != null) {
815 LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(),
817 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
818 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null,
819 vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
822 // Passing null as we don't know the dpn
823 // to which prefix is attached at this point
824 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
830 public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
831 LOG.trace("dpn {} for vpn {}, nexthopIp {} : cleanUpDpnForVpn", dpnId, rd, nexthopIp);
832 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
833 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
834 synchronized (lockOnDpnVpn.intern()) {
835 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
836 if (vrfTable.isPresent()) {
837 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
838 // Passing null as we don't know the dpn
839 // to which prefix is attached at this point
840 if (nexthopIp == vrfEntry.getNextHopAddress()) {
841 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
848 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
849 InstanceIdentifierBuilder<VrfTables> idBuilder =
850 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
851 InstanceIdentifier<VrfTables> id = idBuilder.build();
855 private String getFlowRef(BigInteger dpnId, short tableId, long label, String nextHop) {
856 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
857 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
858 .append(label).append(NwConstants.FLOWID_SEPARATOR)
859 .append(nextHop).toString();
862 private String getFlowRef(BigInteger dpnId, short tableId, String rd, InetAddress destPrefix) {
863 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
864 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
865 .append(rd).append(NwConstants.FLOWID_SEPARATOR)
866 .append(destPrefix.getHostAddress()).toString();
869 protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId,
870 final long vpnId, final VrfEntry vrfEntry, String rd) {
871 String adjacency = null;
872 boolean staticRoute = false;
873 LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry);
875 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
876 if(extra_route != null) {
881 nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId,
882 (staticRoute == true) ? extra_route.getNexthopIp() + "/32" : vrfEntry.getDestPrefix(),
883 vrfEntry.getNextHopAddress());
884 } catch (NullPointerException e) {
890 protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
891 InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.create(VpnInstanceOpData.class).child(
892 VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
893 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
894 if(vpnInstanceOpData.isPresent()) {
895 return vpnInstanceOpData.get();
900 public void processNodeAdd(BigInteger dpnId) {
901 LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
902 makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
903 makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
904 makeSubnetRouteTableMissFlow(dpnId, NwConstants.ADD_FLOW);
907 private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
908 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
909 // Instruction to goto L3 InterfaceTable
910 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
911 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE }));
912 List<MatchInfo> matches = new ArrayList<MatchInfo>();
913 FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE,
914 getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW),
915 NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
917 FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE, getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, NwConstants.TABLE_MISS_FLOW),
918 NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow", 0, 0, COOKIE_VM_FIB_TABLE,
919 matches, instructions);
921 if (addOrRemove == NwConstants.ADD_FLOW) {
922 LOG.debug("Invoking MDSAL to install Table Miss Entries");
923 mdsalManager.installFlow(flowEntityLfib);
924 mdsalManager.installFlow(flowEntityFib);
926 mdsalManager.removeFlow(flowEntityLfib);
927 mdsalManager.removeFlow(flowEntityFib);
932 private String getFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
933 return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
934 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
935 .append(FLOWID_PREFIX).toString();
939 * Install flow entry in protocol table to forward mpls
940 * coming through gre tunnel to LFIB table.
942 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
943 final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
944 // Instruction to goto L3 InterfaceTable
945 List<InstructionInfo> instructions = new ArrayList<>();
946 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
947 List<MatchInfo> matches = new ArrayList<MatchInfo>();
948 matches.add(new MatchInfo(MatchFieldType.eth_type,
949 new long[] { 0x8847L }));
950 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_PROTOCOL_TABLE,
951 getFlowRef(dpnId, NwConstants.L3_PROTOCOL_TABLE,
952 NwConstants.L3_LFIB_TABLE),
953 DEFAULT_FIB_FLOW_PRIORITY,
954 "Protocol Table For LFIB",
956 COOKIE_PROTOCOL_TABLE,
957 matches, instructions);
959 if (addOrRemove == NwConstants.ADD_FLOW) {
960 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
961 mdsalManager.installFlow(flowEntityToLfib);
963 mdsalManager.removeFlow(flowEntityToLfib);
967 public List<String> printFibEntries() {
968 List<String> result = new ArrayList<String>();
969 result.add(String.format(" %-7s %-20s %-20s %-7s", "RD", "Prefix", "Nexthop", "Label"));
970 result.add("-------------------------------------------------------------------");
971 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
972 Optional<FibEntries> fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
973 if (fibEntries.isPresent()) {
974 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
975 for (VrfTables vrfTable : vrfTables) {
976 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
977 result.add(String.format(" %-7s %-20s %-20s %-7s", vrfTable.getRouteDistinguisher(),
978 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress(), vrfEntry.getLabel()));
985 private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) {
986 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
987 List<MatchInfo> matches = new ArrayList<MatchInfo>();
988 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
989 // Instruction to clear metadata except SI and LportTag bits
990 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] {
991 CLEAR_METADATA, METADATA_MASK_CLEAR }));
992 // Instruction to clear action
993 instructions.add(new InstructionInfo(InstructionType.clear_actions));
994 // Instruction to goto L3 InterfaceTable
996 List <ActionInfo> actionsInfos = new ArrayList <ActionInfo> ();
997 actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{
998 Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)}));
999 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
1000 //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE }));
1002 FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE,
1003 getFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW),
1004 NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
1005 if (addOrRemove == NwConstants.ADD_FLOW) {
1006 LOG.info("Invoking MDSAL to install L3 interface Table Miss Entries");
1007 mdsalManager.installFlow(flowEntityL3Intf);
1009 mdsalManager.removeFlow(flowEntityL3Intf);