2 * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netvirt.fibmanager;
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
13 import java.math.BigInteger;
14 import java.net.InetAddress;
15 import java.net.UnknownHostException;
16 import java.util.ArrayList;
17 import java.util.Collection;
18 import java.util.HashSet;
19 import java.util.List;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Future;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
25 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
29 import org.opendaylight.genius.mdsalutil.AbstractDataChangeListener;
30 import org.opendaylight.genius.itm.globals.ITMConstants;
31 import org.opendaylight.genius.mdsalutil.ActionInfo;
32 import org.opendaylight.genius.mdsalutil.ActionType;
33 import org.opendaylight.genius.mdsalutil.FlowEntity;
34 import org.opendaylight.genius.mdsalutil.InstructionInfo;
35 import org.opendaylight.genius.mdsalutil.InstructionType;
36 import org.opendaylight.genius.mdsalutil.MDSALUtil;
37 import org.opendaylight.genius.mdsalutil.MatchFieldType;
38 import org.opendaylight.genius.mdsalutil.MatchInfo;
39 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
40 import org.opendaylight.genius.mdsalutil.NwConstants;
41 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.RdToElanOp;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntry;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntryKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroute;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIds;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.VpnIdsKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.Vpn;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.VpnKey;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetTunnelTypeInputBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetTunnelTypeOutput;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
74 import org.opendaylight.yangtools.concepts.ListenerRegistration;
75 import org.opendaylight.yangtools.yang.binding.DataObject;
76 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
77 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
78 import org.opendaylight.yangtools.yang.common.RpcResult;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
82 public class FibManager extends AbstractDataChangeListener<VrfEntry> implements AutoCloseable{
83 private static final Logger LOG = LoggerFactory.getLogger(FibManager.class);
84 private static final String FLOWID_PREFIX = "L3.";
85 private ListenerRegistration<DataChangeListener> listenerRegistration;
86 private final DataBroker broker;
87 private IMdsalApiManager mdsalManager;
88 private IVpnManager vpnmanager;
89 private NexthopManager nextHopManager;
90 private ItmRpcService itmManager;
91 private OdlInterfaceRpcService interfaceManager;
92 private IdManagerService idManager;
93 private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
94 private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16);
95 private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
96 private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16);
97 private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0);
98 public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
101 public FibManager(final DataBroker db) {
102 super(VrfEntry.class);
104 registerListener(db);
108 public void close() throws Exception {
109 if (listenerRegistration != null) {
111 listenerRegistration.close();
112 } catch (final Exception e) {
113 LOG.error("Error when cleaning up DataChangeListener.", e);
115 listenerRegistration = null;
117 LOG.info("Fib Manager Closed");
120 public void setNextHopManager(NexthopManager nextHopManager) {
121 this.nextHopManager = nextHopManager;
124 public NexthopManager getNextHopManager() {
125 return this.nextHopManager;
128 public void setMdsalManager(IMdsalApiManager mdsalManager) {
129 this.mdsalManager = mdsalManager;
132 public void setVpnmanager(IVpnManager vpnmanager) {
133 this.vpnmanager = vpnmanager;
136 public void setITMRpcService(ItmRpcService itmManager) {
137 this.itmManager = itmManager;
140 public void setInterfaceManager(OdlInterfaceRpcService ifManager) {
141 this.interfaceManager = ifManager;
144 public void setIdManager(IdManagerService idManager) {
145 this.idManager = idManager;
148 private void registerListener(final DataBroker db) {
150 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
151 getWildCardPath(), FibManager.this, DataChangeScope.SUBTREE);
152 } catch (final Exception e) {
153 LOG.error("FibManager DataChange listener registration fail!", e);
154 throw new IllegalStateException("FibManager registration Listener failed.", e);
159 private InstanceIdentifier<VrfEntry> getWildCardPath() {
160 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
165 protected void add(final InstanceIdentifier<VrfEntry> identifier,
166 final VrfEntry vrfEntry) {
167 LOG.trace("Add key: " + identifier + ", value=" + vrfEntry );
168 createFibEntries(identifier, vrfEntry);
172 protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
173 LOG.trace("Remove key: " + identifier + ", value=" + vrfEntry);
174 deleteFibEntries(identifier, vrfEntry);
178 protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
179 LOG.trace("Update key: " + identifier + ", original=" + original + ", update=" + update );
180 createFibEntries(identifier, update);
183 private void createFibEntries(final InstanceIdentifier<VrfEntry> identifier,
184 final VrfEntry vrfEntry) {
185 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
186 Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
187 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
189 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
190 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
191 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
193 Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
194 Long vpnId = vpnInstance.getVpnId();
195 String rd = vrfTableKey.getRouteDistinguisher();
196 RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, rd,
197 vrfEntry.getDestPrefix());
198 if (rdToElanOpEntry!=null) {
199 if (vpnToDpnList!=null) {
200 for (VpnToDpnList curDpn : vpnToDpnList) {
201 installSubnetRouteInFib(curDpn.getDpnId(), rdToElanOpEntry, vpnId.longValue(), vrfEntry);
206 BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(),
208 if (vpnToDpnList != null) {
209 for (VpnToDpnList curDpn : vpnToDpnList) {
210 if (!curDpn.getDpnId().equals(localDpnId)) {
211 createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(),
212 vrfTableKey, vrfEntry);
218 private void installSubnetRouteInFib(BigInteger dpnId, RdToElanOpEntry rdToElanOpEntry,
219 long vpnId, VrfEntry vrfEntry){
220 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
221 Long elanTag = rdToElanOpEntry.getElanTag();
223 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
224 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
225 makeConnectedRoute(dpnId,vpnId,vrfEntry,rdToElanOpEntry.getRd(),
226 instructions,NwConstants.ADD_FLOW);
228 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
229 // reinitialize instructions list for LFIB Table
230 instructions = new ArrayList<InstructionInfo>();
232 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
233 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
234 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
235 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
237 makeLFibTableEntry(dpnId,vrfEntry.getLabel(),instructions,
238 vrfEntry.getNextHopAddress(),NwConstants.ADD_FLOW);
239 // TODO makeTunnelTableEntry();
242 private RdToElanOpEntry getRdToElanOpEntry(DataBroker broker, String rd, String subnetIp) {
243 InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(rd,subnetIp);
244 Optional<RdToElanOpEntry> sn = read(broker, LogicalDatastoreType.OPERATIONAL, id);
251 private InstanceIdentifier<RdToElanOpEntry> getRdToElanOpEntryDataPath(String rd, String subnetIp) {
252 return InstanceIdentifier.builder(RdToElanOp.class).child(RdToElanOpEntry.class,
253 new RdToElanOpEntryKey(rd,subnetIp)).build();
255 private <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
256 InstanceIdentifier<T> path) {
258 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
260 Optional<T> result = Optional.absent();
262 result = tx.read(datastoreType, path).get();
263 } catch (Exception e) {
264 throw new RuntimeException(e);
270 private void makeSubnetRouteTableMissFlow(BigInteger dpnId, int addOrRemove) {
271 final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
272 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
273 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
274 actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{}));
275 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
276 List<MatchInfo> matches = new ArrayList<MatchInfo>();
277 String flowRef = getFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, NwConstants.TABLE_MISS_FLOW);
278 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef,
279 NwConstants.TABLE_MISS_PRIORITY, "Subnet Route Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
281 if (addOrRemove == NwConstants.ADD_FLOW) {
282 LOG.debug("Invoking MDSAL to install SubnetRoute Table Miss Entries for DPN" + dpnId);
283 mdsalManager.installFlow(flowEntity);
285 LOG.debug("Invoking MDSAL to remove SubnetRoute Table Miss Entries for DPN " + dpnId);
286 mdsalManager.removeFlow(flowEntity);
290 private Collection<BigInteger> getDpnsForVpn(VpnInstanceOpDataEntry vpnInstance) {
291 Collection<BigInteger> dpns = new HashSet<>();
292 for(VpnToDpnList dpn : vpnInstance.getVpnToDpnList()) {
293 dpns.add(dpn.getDpnId());
299 public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
300 BigInteger localDpnId = BigInteger.ZERO;
301 Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
302 String localNextHopIP = vrfEntry.getDestPrefix();
304 if(localNextHopInfo == null) {
305 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
306 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
307 if (extra_route != null) {
308 localNextHopInfo = getPrefixToInterface(vpnId, extra_route.getNexthopIp() + "/32");
309 localNextHopIP = extra_route.getNexthopIp() + "/32";
313 if(localNextHopInfo != null) {
314 localDpnId = localNextHopInfo.getDpnId();
315 long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
317 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
318 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
320 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
321 instructions.add(new InstructionInfo(InstructionType.write_actions,actionsInfos));
322 makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
324 actionsInfos=new ArrayList<ActionInfo>();
325 instructions=new ArrayList<InstructionInfo>();
326 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
327 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
328 instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
329 makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), instructions, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW);
331 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
332 localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
333 makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId);
339 private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/) {
340 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
341 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
344 createTerminatingServiceActions(dpId, (int)label, actionsInfos);
346 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully {}",
347 dpId, label, groupId);
350 public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos) {
351 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
353 LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
356 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
357 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
359 List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
360 mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
362 FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
363 getFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
364 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
366 mdsalManager.installFlow(terminatingServiceTableFlowEntity);
369 private void removeTunnelTableEntry(BigInteger dpId, long label) {
370 FlowEntity flowEntity;
371 LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
372 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
374 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
375 flowEntity = MDSALUtil.buildFlowEntity(dpId,
376 NwConstants.INTERNAL_TUNNEL_TABLE,
377 getFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
378 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
379 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
380 mdsalManager.removeFlow(flowEntity);
381 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpId, label);
384 public BigInteger deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
385 BigInteger localDpnId = BigInteger.ZERO;
386 boolean isExtraRoute = false;
387 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
388 String localNextHopIP = vrfEntry.getDestPrefix();
390 if(localNextHopInfo == null) {
391 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
392 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
393 if (extra_route != null) {
394 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp() + "/32");
395 localNextHopIP = extra_route.getNexthopIp() + "/32";
401 if(localNextHopInfo != null) {
402 localDpnId = localNextHopInfo.getDpnId();
403 Prefixes prefix = getPrefixToInterface(vpnId, isExtraRoute ? localNextHopIP : vrfEntry.getDestPrefix());
404 makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */,
405 NwConstants.DEL_FLOW);
406 makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), null /* invalid */,
407 vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW);
408 removeTunnelTableEntry(localDpnId, vrfEntry.getLabel());
409 deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP);
414 private InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) {
415 return InstanceIdentifier.builder(PrefixToInterface.class)
416 .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
419 private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
420 Optional<Prefixes> localNextHopInfoData =
421 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
422 return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
425 private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
426 return InstanceIdentifier.builder(VpnToExtraroute.class)
427 .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class,
428 new ExtrarouteKey(ipPrefix)).build();
431 private Extraroute getVpnToExtraroute(String rd, String ipPrefix) {
432 Optional<Extraroute> extraRouteInfo =
433 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix));
434 return extraRouteInfo.isPresent() ? extraRouteInfo.get() : null;
438 private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
440 Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
441 new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
442 RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
443 if(!rpcResult.isSuccessful()) {
444 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
446 return rpcResult.getResult().getTunnelType();
449 } catch (InterruptedException | ExecutionException e) {
450 LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e);
456 private void createRemoteFibEntry(final BigInteger localDpnId, final BigInteger remoteDpnId,
457 final long vpnId, final VrfTablesKey vrfTableKey,
458 final VrfEntry vrfEntry) {
459 String rd = vrfTableKey.getRouteDistinguisher();
460 LOG.debug("adding route " + vrfEntry.getDestPrefix() + " " + rd);
461 /********************************************/
462 String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd);
463 if(tunnelInterface == null) {
464 LOG.error("Could not get interface for nexthop: {} in vpn {}",
465 vrfEntry.getNextHopAddress(), rd);
466 LOG.warn("Failed to add Route: {} in vpn: {}",
467 vrfEntry.getDestPrefix(), rd);
470 List<ActionInfo> actionInfos = new ArrayList<>();
471 Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
472 if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
473 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
474 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
475 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
477 int label = vrfEntry.getLabel().intValue();
479 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
480 if(tunnel_type.equals(TunnelTypeVxlan.class)) {
481 tunnelId = BigInteger.valueOf(label);
483 tunnelId = BigInteger.valueOf(label);
485 LOG.debug("adding set tunnel id action for label {}", label);
486 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{
489 actionInfos.addAll(nextHopManager.getEgressActionsForInterface(tunnelInterface));
490 List<InstructionInfo> instructions= new ArrayList<InstructionInfo>();
491 instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
493 List<ActionInfo> actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry);
494 if(actionInfos == null) {
495 LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}",
496 vrfEntry.getNextHopAddress(), rd);
497 LOG.warn("Failed to add Route: {} in vpn: {}",
498 vrfEntry.getDestPrefix(), rd);
501 BigInteger dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getDestPrefix());
503 //This route may be extra route... try to query with nexthop Ip
504 LOG.debug("Checking for extra route to install remote fib entry {}", vrfEntry.getDestPrefix());
505 dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getNextHopAddress() + "/32");
508 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
509 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
510 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
512 int label = vrfEntry.getLabel().intValue();
513 LOG.debug("adding set tunnel id action for label {}", label);
514 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
515 MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label),
516 MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
519 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
520 LOG.debug("Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId);
523 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
524 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
525 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
526 if (dpnInVpn.isPresent()) {
527 List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
528 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
529 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
530 currVpnInterface = new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesBuilder().setInterfaceName(intfName).build();
532 if (vpnInterfaces.remove(currVpnInterface)) {
533 if (vpnInterfaces.isEmpty()) {
534 LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
535 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id);
536 cleanUpDpnForVpn(dpnId, vpnId, rd);
538 LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
539 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
540 org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
541 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
542 new org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfacesKey(intfName)));
548 private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
549 /* Get interface info from prefix to interface mapping;
550 Use the interface info to get the corresponding vpn interface op DS entry,
551 remove the adjacency corresponding to this fib entry.
552 If adjacency removed is the last adjacency, clean up the following:
553 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
554 - prefix to interface entry
555 - vpn interface op DS
557 Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
558 Extraroute extraRoute = null;
559 if (prefixInfo == null) {
560 extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
561 if(extraRoute != null) {
562 prefixInfo = getPrefixToInterface(vpnId, extraRoute.getNexthopIp() + "/32");
563 //clean up the vpn to extra route entry in DS
564 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
567 if (prefixInfo == null) {
568 LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for " + vrfEntry.getDestPrefix());
569 return; //Don't have any info for this prefix (shouldn't happen); need to return
571 String ifName = prefixInfo.getVpnInterfaceName();
572 Optional<Adjacencies> optAdjacencies = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getAdjListPath(ifName));
574 if (optAdjacencies.isPresent()) {
575 numAdj = optAdjacencies.get().getAdjacency().size();
577 LOG.trace("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix());
578 //remove adjacency corr to prefix
580 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
581 FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
584 if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
585 //clean up the vpn interface from DpnToVpn list
586 LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
587 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
588 FibUtil.getVpnInterfaceIdentifier(ifName));
591 FibUtil.releaseId(idManager, FibConstants.VPN_IDPOOL_NAME,
592 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
596 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier,
597 final VrfEntry vrfEntry) {
598 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
599 Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
600 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
602 String rd = vrfTableKey.getRouteDistinguisher();
603 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
604 if (vpnInstance == null) {
605 LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
608 Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
609 RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker,vrfTableKey.getRouteDistinguisher(),
610 vrfEntry.getDestPrefix());
611 if (rdToElanOpEntry != null) {
612 if (vpnToDpnList!=null) {
613 for(VpnToDpnList curDpn : vpnToDpnList) {
614 makeConnectedRoute(curDpn.getDpnId(),vpnInstance.getVpnId(),vrfEntry,vrfTableKey
615 .getRouteDistinguisher(), null,NwConstants.DEL_FLOW);
616 makeLFibTableEntry(curDpn.getDpnId(),vrfEntry.getLabel(),null,
617 vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
618 // TODO DeleteTunnelTableEntry();
621 //Delete rd-to-elan-op-entry
622 InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(vrfTableKey.getRouteDistinguisher(),
623 vrfEntry.getDestPrefix());
624 MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL,id);
625 FibUtil.releaseId(idManager,FibConstants.VPN_IDPOOL_NAME,
626 FibUtil.getNextHopLabelKey(rd, vrfEntry.getDestPrefix()));
629 BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(),
630 vrfTableKey.getRouteDistinguisher(), vrfEntry);
631 if (vpnToDpnList != null) {
632 for (VpnToDpnList curDpn : vpnToDpnList) {
633 if (!curDpn.getDpnId().equals(localDpnId)) {
634 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry);
638 //The flow/group entry has been deleted from config DS; need to clean up associated operational
639 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
640 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
643 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
644 final long vpnId, final VrfTablesKey vrfTableKey,
645 final VrfEntry vrfEntry) {
646 LOG.debug("deleting route "+ vrfEntry.getDestPrefix() + " "+vpnId);
647 String rd = vrfTableKey.getRouteDistinguisher();
648 boolean isRemoteRoute = true;
649 if (localDpnId == null) {
650 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
651 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
652 if(localNextHopInfo == null) {
653 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
654 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
655 if (extra_route != null) {
656 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp());
659 if (localNextHopInfo != null) {
660 isRemoteRoute = (!remoteDpnId.equals(localNextHopInfo.getDpnId()));
664 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
665 LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId);
667 LOG.debug("Did not delete fib entry rd: {} =, prefix: {} as it is local to dpn {}", rd, vrfEntry.getDestPrefix(), remoteDpnId);
671 private long getIpAddress(byte[] rawIpAddress) {
672 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
673 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
676 private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
677 List<InstructionInfo> instructions, int addOrRemove) { LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
678 String values[] = vrfEntry.getDestPrefix().split("/");
679 String ipAddress = values[0];
680 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
681 LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength);
682 InetAddress destPrefix = null;
684 destPrefix = InetAddress.getByName(ipAddress);
685 } catch (UnknownHostException e) {
686 LOG.error("UnknowHostException in addRoute. Failed to add Route for ipPrefix {}", vrfEntry.getDestPrefix());
690 List<MatchInfo> matches = new ArrayList<MatchInfo>();
692 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
693 BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
695 matches.add(new MatchInfo(MatchFieldType.eth_type,
696 new long[] { 0x0800L }));
698 if(prefixLength != 0) {
699 matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
700 destPrefix.getHostAddress(), Integer.toString(prefixLength)}));
703 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, destPrefix);
705 FlowEntity flowEntity;
707 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
708 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
709 priority, flowRef, 0, 0,
710 COOKIE_VM_FIB_TABLE, matches, instructions);
712 if (addOrRemove == NwConstants.ADD_FLOW) {
713 /* We need to call sync API to install flow so that 2 DS operations on the same object do not
714 * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
715 * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
716 * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
717 * wait indefinitely. */
718 mdsalManager.syncInstallFlow(flowEntity, 1);
720 mdsalManager.syncRemoveFlow(flowEntity, 1);
724 private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions,
725 String nextHop, int addOrRemove) {
726 List<MatchInfo> matches = new ArrayList<MatchInfo>();
727 matches.add(new MatchInfo(MatchFieldType.eth_type,
728 new long[] { 0x8847L }));
729 matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
731 // Install the flow entry in L3_LFIB_TABLE
732 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, nextHop);
734 FlowEntity flowEntity;
735 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef,
736 DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
737 COOKIE_VM_LFIB_TABLE, matches, instructions);
739 if (addOrRemove == NwConstants.ADD_FLOW) {
740 /* We need to call sync API to install flow so that 2 DS operations on the same object do not
741 * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
742 * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
743 * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
744 * wait indefinitely. */
746 mdsalManager.syncInstallFlow(flowEntity, 1);
748 mdsalManager.syncRemoveFlow(flowEntity, 1);
750 LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} modified successfully {}",dpId, label, instructions );
753 private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
754 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
756 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
757 } catch (NullPointerException e) {
762 public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) {
763 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
764 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
765 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
766 synchronized (lockOnDpnVpn.intern()) {
767 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
768 if (vrfTable.isPresent()) {
769 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
770 RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, rd,
771 vrfEntry.getDestPrefix());
772 if (rdToElanOpEntry!= null) {
773 installSubnetRouteInFib(dpnId, rdToElanOpEntry, vpnId, vrfEntry);
776 // Passing null as we don't know the dpn
777 // to which prefix is attached at this point
778 createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
784 public void populateFibOnDpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
785 LOG.trace("dpn {} for vpn {}, nexthopIp {} : populateFibOnDpn", dpnId, rd, nexthopIp);
786 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
787 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
788 synchronized (lockOnDpnVpn.intern()) {
789 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
790 if (vrfTable.isPresent()) {
791 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
792 // Passing null as we don't know the dpn
793 // to which prefix is attached at this point
794 if (nexthopIp == vrfEntry.getNextHopAddress()) {
795 createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
802 public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) {
803 LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
804 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
805 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
806 synchronized (lockOnDpnVpn.intern()) {
807 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
808 if (vrfTable.isPresent()) {
809 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
810 /* Handle subnet routes here */
811 RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker, rd,
812 vrfEntry.getDestPrefix());
813 if (rdToElanOpEntry != null) {
814 LOG.trace("Cleaning subnetroute {} on dpn {} for vpn {} : cleanUpDpnForVpn", vrfEntry.getDestPrefix(),
816 makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
817 makeLFibTableEntry(dpnId, vrfEntry.getLabel(), null,
818 vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
821 // Passing null as we don't know the dpn
822 // to which prefix is attached at this point
823 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
829 public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
830 LOG.trace("dpn {} for vpn {}, nexthopIp {} : cleanUpDpnForVpn", dpnId, rd, nexthopIp);
831 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
832 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
833 synchronized (lockOnDpnVpn.intern()) {
834 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
835 if (vrfTable.isPresent()) {
836 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
837 // Passing null as we don't know the dpn
838 // to which prefix is attached at this point
839 if (nexthopIp == vrfEntry.getNextHopAddress()) {
840 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
847 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
848 InstanceIdentifierBuilder<VrfTables> idBuilder =
849 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
850 InstanceIdentifier<VrfTables> id = idBuilder.build();
854 private String getFlowRef(BigInteger dpnId, short tableId, long label, String nextHop) {
855 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
856 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
857 .append(label).append(NwConstants.FLOWID_SEPARATOR)
858 .append(nextHop).toString();
861 private String getFlowRef(BigInteger dpnId, short tableId, String rd, InetAddress destPrefix) {
862 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
863 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
864 .append(rd).append(NwConstants.FLOWID_SEPARATOR)
865 .append(destPrefix.getHostAddress()).toString();
868 protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId,
869 final long vpnId, final VrfEntry vrfEntry, String rd) {
870 String adjacency = null;
871 boolean staticRoute = false;
872 LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry);
874 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
875 if(extra_route != null) {
880 nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId,
881 (staticRoute == true) ? extra_route.getNexthopIp() + "/32" : vrfEntry.getDestPrefix(),
882 vrfEntry.getNextHopAddress());
883 } catch (NullPointerException e) {
889 protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
890 InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.create(VpnInstanceOpData.class).child(
891 VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
892 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
893 if(vpnInstanceOpData.isPresent()) {
894 return vpnInstanceOpData.get();
899 public void processNodeAdd(BigInteger dpnId) {
900 LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
901 makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
902 makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
903 makeSubnetRouteTableMissFlow(dpnId, NwConstants.ADD_FLOW);
906 private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
907 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
908 // Instruction to goto L3 InterfaceTable
909 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
910 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE }));
911 List<MatchInfo> matches = new ArrayList<MatchInfo>();
912 FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE,
913 getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW),
914 NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
916 FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE, getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, NwConstants.TABLE_MISS_FLOW),
917 NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow", 0, 0, COOKIE_VM_FIB_TABLE,
918 matches, instructions);
920 if (addOrRemove == NwConstants.ADD_FLOW) {
921 LOG.debug("Invoking MDSAL to install Table Miss Entries");
922 mdsalManager.installFlow(flowEntityLfib);
923 mdsalManager.installFlow(flowEntityFib);
925 mdsalManager.removeFlow(flowEntityLfib);
926 mdsalManager.removeFlow(flowEntityFib);
931 private String getFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
932 return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
933 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
934 .append(FLOWID_PREFIX).toString();
938 * Install flow entry in protocol table to forward mpls
939 * coming through gre tunnel to LFIB table.
941 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
942 final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
943 // Instruction to goto L3 InterfaceTable
944 List<InstructionInfo> instructions = new ArrayList<>();
945 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
946 List<MatchInfo> matches = new ArrayList<MatchInfo>();
947 matches.add(new MatchInfo(MatchFieldType.eth_type,
948 new long[] { 0x8847L }));
949 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_PROTOCOL_TABLE,
950 getFlowRef(dpnId, NwConstants.L3_PROTOCOL_TABLE,
951 NwConstants.L3_LFIB_TABLE),
952 DEFAULT_FIB_FLOW_PRIORITY,
953 "Protocol Table For LFIB",
955 COOKIE_PROTOCOL_TABLE,
956 matches, instructions);
958 if (addOrRemove == NwConstants.ADD_FLOW) {
959 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
960 mdsalManager.installFlow(flowEntityToLfib);
962 mdsalManager.removeFlow(flowEntityToLfib);
966 public List<String> printFibEntries() {
967 List<String> result = new ArrayList<String>();
968 result.add(String.format(" %-7s %-20s %-20s %-7s", "RD", "Prefix", "Nexthop", "Label"));
969 result.add("-------------------------------------------------------------------");
970 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
971 Optional<FibEntries> fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
972 if (fibEntries.isPresent()) {
973 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
974 for (VrfTables vrfTable : vrfTables) {
975 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
976 result.add(String.format(" %-7s %-20s %-20s %-7s", vrfTable.getRouteDistinguisher(),
977 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress(), vrfEntry.getLabel()));
984 private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) {
985 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
986 List<MatchInfo> matches = new ArrayList<MatchInfo>();
987 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
988 // Instruction to clear metadata except SI and LportTag bits
989 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] {
990 CLEAR_METADATA, METADATA_MASK_CLEAR }));
991 // Instruction to clear action
992 instructions.add(new InstructionInfo(InstructionType.clear_actions));
993 // Instruction to goto L3 InterfaceTable
995 List <ActionInfo> actionsInfos = new ArrayList <ActionInfo> ();
996 actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{
997 Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)}));
998 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
999 //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE }));
1001 FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE,
1002 getFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW),
1003 NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
1004 if (addOrRemove == NwConstants.ADD_FLOW) {
1005 LOG.info("Invoking MDSAL to install L3 interface Table Miss Entries");
1006 mdsalManager.installFlow(flowEntityL3Intf);
1008 mdsalManager.removeFlow(flowEntityL3Intf);