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.List;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.Future;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
26 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
27 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.vpnmanager.api.IVpnManager;
31 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
32 import org.opendaylight.vpnservice.itm.globals.ITMConstants;
33 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
34 import org.opendaylight.vpnservice.mdsalutil.ActionType;
35 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
36 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
37 import org.opendaylight.vpnservice.mdsalutil.InstructionType;
38 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
39 import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
40 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
41 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
42 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
43 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnToExtraroute;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIds;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIdsKey;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.Vpn;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.VpnKey;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeMplsOverGre;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeInputBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeOutput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.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 static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
93 private static final BigInteger COOKIE_VM_FIB_TABLE = new BigInteger("8000003", 16);
94 private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
95 private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16);
96 private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0);
97 public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
100 public FibManager(final DataBroker db) {
101 super(VrfEntry.class);
103 registerListener(db);
107 public void close() throws Exception {
108 if (listenerRegistration != null) {
110 listenerRegistration.close();
111 } catch (final Exception e) {
112 LOG.error("Error when cleaning up DataChangeListener.", e);
114 listenerRegistration = null;
116 LOG.info("Fib Manager Closed");
119 public void setNextHopManager(NexthopManager nextHopManager) {
120 this.nextHopManager = nextHopManager;
123 public void setMdsalManager(IMdsalApiManager mdsalManager) {
124 this.mdsalManager = mdsalManager;
127 public void setVpnmanager(IVpnManager vpnmanager) {
128 this.vpnmanager = vpnmanager;
131 public void setITMRpcService(ItmRpcService itmManager) {
132 this.itmManager = itmManager;
135 public void setInterfaceManager(OdlInterfaceRpcService ifManager) {
136 this.interfaceManager = ifManager;
139 private void registerListener(final DataBroker db) {
141 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
142 getWildCardPath(), FibManager.this, DataChangeScope.SUBTREE);
143 } catch (final Exception e) {
144 LOG.error("FibManager DataChange listener registration fail!", e);
145 throw new IllegalStateException("FibManager registration Listener failed.", e);
150 private InstanceIdentifier<VrfEntry> getWildCardPath() {
151 return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
156 protected void add(final InstanceIdentifier<VrfEntry> identifier,
157 final VrfEntry vrfEntry) {
158 LOG.trace("key: " + identifier + ", value=" + vrfEntry );
159 createFibEntries(identifier, vrfEntry);
163 protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
164 LOG.trace("key: " + identifier + ", value=" + vrfEntry);
165 deleteFibEntries(identifier, vrfEntry);
169 protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
170 LOG.trace("key: " + identifier + ", original=" + original + ", update=" + update );
171 createFibEntries(identifier, update);
174 private void createFibEntries(final InstanceIdentifier<VrfEntry> identifier,
175 final VrfEntry vrfEntry) {
176 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
177 Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
178 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
180 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
181 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
182 Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + "has null vpnId!");
184 Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
185 BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(),
186 vrfTableKey.getRouteDistinguisher(), vrfEntry);
187 if (vpnToDpnList != null) {
188 for (VpnToDpnList curDpn : vpnToDpnList) {
189 if (!curDpn.getDpnId().equals(localDpnId)) {
190 createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(),
191 vrfTableKey, vrfEntry);
197 public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
198 BigInteger localDpnId = BigInteger.ZERO;
199 Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
200 String localNextHopIP = vrfEntry.getDestPrefix();
202 if(localNextHopInfo == null) {
203 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
204 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
205 if (extra_route != null) {
206 localNextHopInfo = getPrefixToInterface(vpnId, extra_route.getNexthopIp() + "/32");
207 localNextHopIP = extra_route.getNexthopIp() + "/32";
211 if(localNextHopInfo != null) {
212 localDpnId = localNextHopInfo.getDpnId();
213 long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
214 List<ActionInfo> actionInfos = new ArrayList<ActionInfo>();
216 actionInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
218 makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW);
219 makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), groupId, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW);
221 LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
222 localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
223 makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId);
229 private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/) {
230 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
231 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
234 createTerminatingServiceActions(dpId, (int)label, actionsInfos);
236 LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully {}",
237 dpId, label, groupId);
240 public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos) {
241 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
243 LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
246 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
247 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
249 List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
250 mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
252 FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
253 getFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
254 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
256 mdsalManager.installFlow(terminatingServiceTableFlowEntity);
259 private void removeTunnelTableEntry(BigInteger dpId, long label) {
260 FlowEntity flowEntity;
261 LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
262 List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
264 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
265 flowEntity = MDSALUtil.buildFlowEntity(dpId,
266 NwConstants.INTERNAL_TUNNEL_TABLE,
267 getFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
268 5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
269 COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
270 mdsalManager.removeFlow(flowEntity);
271 LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpId, label);
274 public BigInteger deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
275 BigInteger localDpnId = BigInteger.ZERO;
276 boolean isExtraRoute = false;
277 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
278 String localNextHopIP = vrfEntry.getDestPrefix();
280 if(localNextHopInfo == null) {
281 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
282 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
283 if (extra_route != null) {
284 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp());
285 localNextHopIP = extra_route.getNexthopIp() + "/32";
291 if(localNextHopInfo != null) {
292 localDpnId = localNextHopInfo.getDpnId();
293 Prefixes prefix = getPrefixToInterface(vpnId, isExtraRoute ? localNextHopIP : vrfEntry.getDestPrefix());
294 makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */,
295 NwConstants.DEL_FLOW);
296 makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), 0 /* invalid */,
297 vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW);
298 removeTunnelTableEntry(localDpnId, vrfEntry.getLabel());
299 deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP);
304 private InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) {
305 return InstanceIdentifier.builder(PrefixToInterface.class)
306 .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
309 private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
310 Optional<Prefixes> localNextHopInfoData =
311 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
312 return localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
315 private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
316 return InstanceIdentifier.builder(VpnToExtraroute.class)
317 .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class,
318 new ExtrarouteKey(ipPrefix)).build();
321 private Extraroute getVpnToExtraroute(String rd, String ipPrefix) {
322 Optional<Extraroute> extraRouteInfo =
323 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix));
324 return extraRouteInfo.isPresent() ? extraRouteInfo.get() : null;
328 private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
330 Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
331 new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
332 RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
333 if(!rpcResult.isSuccessful()) {
334 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
336 return rpcResult.getResult().getTunnelType();
339 } catch (InterruptedException | ExecutionException e) {
340 LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e);
346 private void createRemoteFibEntry(final BigInteger localDpnId, final BigInteger remoteDpnId,
347 final long vpnId, final VrfTablesKey vrfTableKey,
348 final VrfEntry vrfEntry) {
349 String rd = vrfTableKey.getRouteDistinguisher();
350 LOG.debug("adding route " + vrfEntry.getDestPrefix() + " " + rd);
351 /********************************************/
352 String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd);
353 if(tunnelInterface == null) {
354 LOG.error("Could not get interface for nexthop: {} in vpn {}",
355 vrfEntry.getNextHopAddress(), rd);
356 LOG.warn("Failed to add Route: {} in vpn: {}",
357 vrfEntry.getDestPrefix(), rd);
360 List<ActionInfo> actionInfos = new ArrayList<>();
361 Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
362 if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
363 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
364 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
365 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
367 int label = vrfEntry.getLabel().intValue();
369 // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
370 if(tunnel_type.equals(TunnelTypeVxlan.class)) {
371 tunnelId = BigInteger.valueOf(label);
373 tunnelId = BigInteger.valueOf(label);
375 LOG.debug("adding set tunnel id action for label {}", label);
376 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{
379 actionInfos.addAll(nextHopManager.getEgressActionsForInterface(tunnelInterface));
381 List<ActionInfo> actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry);
382 if(actionInfos == null) {
383 LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}",
384 vrfEntry.getNextHopAddress(), rd);
385 LOG.warn("Failed to add Route: {} in vpn: {}",
386 vrfEntry.getDestPrefix(), rd);
389 BigInteger dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getDestPrefix());
391 //This route may be extra route... try to query with nexthop Ip
392 LOG.debug("Checking for extra route to install remote fib entry {}", vrfEntry.getDestPrefix());
393 dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getNextHopAddress() + "/32");
396 LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
397 actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
398 actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
400 int label = vrfEntry.getLabel().intValue();
401 LOG.debug("adding set tunnel id action for label {}", label);
402 actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
403 MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label),
404 MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
407 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW);
409 "Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId);
412 private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
413 InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
414 Optional<VpnToDpnList> dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
415 if (dpnInVpn.isPresent()) {
416 List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
417 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
418 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
419 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();
421 if (vpnInterfaces.remove(currVpnInterface)) {
422 if (vpnInterfaces.isEmpty()) {
423 LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
424 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id);
425 cleanUpDpnForVpn(dpnId, vpnId, rd);
427 LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
428 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
429 org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
430 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
431 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)));
437 private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
438 /* Get interface info from prefix to interface mapping;
439 Use the interface info to get the corresponding vpn interface op DS entry,
440 remove the adjacency corresponding to this fib entry.
441 If adjacency removed is the last adjacency, clean up the following:
442 - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
443 - prefix to interface entry
444 - vpn interface op DS
446 Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
447 boolean extra_route = false;
448 if (prefixInfo == null) {
449 prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getNextHopAddress() + "/32");
452 if (prefixInfo == null)
453 return; //Don't have any info for this prefix (shouldn't happen); need to return
454 String ifName = prefixInfo.getVpnInterfaceName();
455 Optional<Adjacencies> optAdjacencies = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getAdjListPath(ifName));
457 if (optAdjacencies.isPresent()) {
458 numAdj = optAdjacencies.get().getAdjacency().size();
460 LOG.trace("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix());
461 //remove adjacency corr to prefix
463 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
464 FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
467 if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
468 //clean up the vpn interface from DpnToVpn list
469 LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
470 FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
471 FibUtil.getVpnInterfaceIdentifier(ifName));
475 private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier,
476 final VrfEntry vrfEntry) {
477 final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
478 Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
479 Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
481 VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
482 Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
483 Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
484 BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(),
485 vrfTableKey.getRouteDistinguisher(), vrfEntry);
486 if (vpnToDpnList != null) {
487 for (VpnToDpnList curDpn : vpnToDpnList) {
488 if (!curDpn.getDpnId().equals(localDpnId)) {
489 deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry);
493 //The flow/group entry has been deleted from config DS; need to clean up associated operational
494 //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
495 cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
498 public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
499 final long vpnId, final VrfTablesKey vrfTableKey,
500 final VrfEntry vrfEntry) {
501 LOG.debug("deleting route "+ vrfEntry.getDestPrefix() + " "+vpnId);
502 String rd = vrfTableKey.getRouteDistinguisher();
503 boolean isRemoteRoute = true;
504 if (localDpnId == null) {
505 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
506 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
507 if(localNextHopInfo == null) {
508 //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
509 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
510 if (extra_route != null) {
511 localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp());
514 if (localNextHopInfo != null) {
515 isRemoteRoute = (!remoteDpnId.equals(localNextHopInfo.getDpnId()));
519 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
520 LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId);
522 LOG.debug("Did not delete fib entry rd: {} =, prefix: {} as it is local to dpn {}", rd, vrfEntry.getDestPrefix(), remoteDpnId);
526 private long getIpAddress(byte[] rawIpAddress) {
527 return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
528 + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
531 private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
532 List<ActionInfo> actionInfos, int addOrRemove) {
533 LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
534 String values[] = vrfEntry.getDestPrefix().split("/");
535 String ipAddress = values[0];
536 int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
537 LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength);
538 InetAddress destPrefix = null;
540 destPrefix = InetAddress.getByName(ipAddress);
541 } catch (UnknownHostException e) {
542 LOG.error("UnknowHostException in addRoute. Failed to add Route for ipPrefix {}", vrfEntry.getDestPrefix());
546 List<MatchInfo> matches = new ArrayList<MatchInfo>();
548 matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
549 BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
551 matches.add(new MatchInfo(MatchFieldType.eth_type,
552 new long[] { 0x0800L }));
554 if(prefixLength != 0) {
555 matches.add(new MatchInfo(MatchFieldType.ipv4_dst, new long[] {
556 getIpAddress(destPrefix.getAddress()), prefixLength }));
559 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
560 if(addOrRemove == NwConstants.ADD_FLOW) {
561 instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
564 String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, destPrefix);
566 FlowEntity flowEntity;
568 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
569 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
570 priority, flowRef, 0, 0,
571 COOKIE_VM_FIB_TABLE, matches, instructions);
573 if (addOrRemove == NwConstants.ADD_FLOW) {
574 /* We need to call sync API to install flow so that 2 DS operations on the same object do not
575 * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
576 * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
577 * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
578 * wait indefinitely. */
579 mdsalManager.syncInstallFlow(flowEntity, 1);
581 mdsalManager.syncRemoveFlow(flowEntity, 1);
585 private void makeLFibTableEntry(BigInteger dpId, long label, long groupId,
586 String nextHop, int addOrRemove) {
587 List<MatchInfo> matches = new ArrayList<MatchInfo>();
588 matches.add(new MatchInfo(MatchFieldType.eth_type,
589 new long[] { 0x8847L }));
590 matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
592 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
593 List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
594 actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
595 actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
596 instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
598 // Install the flow entry in L3_LFIB_TABLE
599 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, nextHop);
601 FlowEntity flowEntity;
602 flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef,
603 DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
604 COOKIE_VM_LFIB_TABLE, matches, instructions);
606 if (addOrRemove == NwConstants.ADD_FLOW) {
607 /* We need to call sync API to install flow so that 2 DS operations on the same object do not
608 * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
609 * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
610 * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
611 * wait indefinitely. */
613 mdsalManager.syncInstallFlow(flowEntity, 1);
615 mdsalManager.syncRemoveFlow(flowEntity, 1);
617 LOG.debug("LFIB Entry for dpID {} : label : {} group {} modified successfully {}",dpId, label, groupId );
620 private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
621 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
623 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
624 } catch (NullPointerException e) {
629 public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) {
630 LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
631 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
632 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
633 synchronized (lockOnDpnVpn.intern()) {
634 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
635 if (vrfTable.isPresent()) {
636 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
637 // Passing null as we don't know the dpn
638 // to which prefix is attached at this point
639 createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
645 public void populateFibOnDpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
646 LOG.trace("dpn {} for vpn {}, nexthopIp {} : populateFibOnDpn", dpnId, rd, nexthopIp);
647 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
648 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
649 synchronized (lockOnDpnVpn.intern()) {
650 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
651 if (vrfTable.isPresent()) {
652 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
653 // Passing null as we don't know the dpn
654 // to which prefix is attached at this point
655 if (nexthopIp == vrfEntry.getNextHopAddress()) {
656 createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
663 public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) {
664 LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
665 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
666 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
667 synchronized (lockOnDpnVpn.intern()) {
668 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
669 if (vrfTable.isPresent()) {
670 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
671 // Passing null as we don't know the dpn
672 // to which prefix is attached at this point
673 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
679 public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
680 LOG.trace("dpn {} for vpn {}, nexthopIp {} : cleanUpDpnForVpn", dpnId, rd, nexthopIp);
681 InstanceIdentifier<VrfTables> id = buildVrfId(rd);
682 String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
683 synchronized (lockOnDpnVpn.intern()) {
684 Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
685 if (vrfTable.isPresent()) {
686 for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
687 // Passing null as we don't know the dpn
688 // to which prefix is attached at this point
689 if (nexthopIp == vrfEntry.getNextHopAddress()) {
690 deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
697 public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
698 InstanceIdentifierBuilder<VrfTables> idBuilder =
699 InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
700 InstanceIdentifier<VrfTables> id = idBuilder.build();
704 private String getFlowRef(BigInteger dpnId, short tableId, long label, String nextHop) {
705 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
706 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
707 .append(label).append(NwConstants.FLOWID_SEPARATOR)
708 .append(nextHop).toString();
711 private String getFlowRef(BigInteger dpnId, short tableId, String rd, InetAddress destPrefix) {
712 return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
713 .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
714 .append(rd).append(NwConstants.FLOWID_SEPARATOR)
715 .append(destPrefix.getHostAddress()).toString();
718 protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId,
719 final long vpnId, final VrfEntry vrfEntry, String rd) {
720 String adjacency = null;
721 boolean staticRoute = false;
722 LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry);
724 Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
725 if(extra_route != null) {
730 nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId,
731 vrfEntry.getDestPrefix(),
732 (staticRoute == true) ? extra_route.getNexthopIp() : vrfEntry.getNextHopAddress());
733 } catch (NullPointerException e) {
739 protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
740 InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.create(VpnInstanceOpData.class).child(
741 VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
742 Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
743 if(vpnInstanceOpData.isPresent()) {
744 return vpnInstanceOpData.get();
749 public void processNodeAdd(BigInteger dpnId) {
750 LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
751 makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
752 makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
755 private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
756 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
757 // Instruction to goto L3 InterfaceTable
758 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
759 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE }));
760 List<MatchInfo> matches = new ArrayList<MatchInfo>();
761 FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE,
762 getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW),
763 NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
765 FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE, getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, NwConstants.TABLE_MISS_FLOW),
766 NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow", 0, 0, COOKIE_VM_FIB_TABLE,
767 matches, instructions);
769 if (addOrRemove == NwConstants.ADD_FLOW) {
770 LOG.debug("Invoking MDSAL to install Table Miss Entries");
771 mdsalManager.installFlow(flowEntityLfib);
772 mdsalManager.installFlow(flowEntityFib);
774 mdsalManager.removeFlow(flowEntityLfib);
775 mdsalManager.removeFlow(flowEntityFib);
780 private String getFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
781 return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
782 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
783 .append(FLOWID_PREFIX).toString();
787 * Install flow entry in protocol table to forward mpls
788 * coming through gre tunnel to LFIB table.
790 private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
791 final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
792 // Instruction to goto L3 InterfaceTable
793 List<InstructionInfo> instructions = new ArrayList<>();
794 instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
795 List<MatchInfo> matches = new ArrayList<MatchInfo>();
796 matches.add(new MatchInfo(MatchFieldType.eth_type,
797 new long[] { 0x8847L }));
798 FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_PROTOCOL_TABLE,
799 getFlowRef(dpnId, NwConstants.L3_PROTOCOL_TABLE,
800 NwConstants.L3_LFIB_TABLE),
801 DEFAULT_FIB_FLOW_PRIORITY,
802 "Protocol Table For LFIB",
804 COOKIE_PROTOCOL_TABLE,
805 matches, instructions);
807 if (addOrRemove == NwConstants.ADD_FLOW) {
808 LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
809 mdsalManager.installFlow(flowEntityToLfib);
811 mdsalManager.removeFlow(flowEntityToLfib);
815 public List<String> printFibEntries() {
816 List<String> result = new ArrayList<String>();
817 result.add(String.format(" %-7s %-20s %-20s %-7s", "RD", "Prefix", "Nexthop", "Label"));
818 result.add("-------------------------------------------------------------------");
819 InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
820 Optional<FibEntries> fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
821 if (fibEntries.isPresent()) {
822 List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
823 for (VrfTables vrfTable : vrfTables) {
824 for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
825 result.add(String.format(" %-7s %-20s %-20s %-7s", vrfTable.getRouteDistinguisher(),
826 vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress(), vrfEntry.getLabel()));
833 private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) {
834 List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
835 List<MatchInfo> matches = new ArrayList<MatchInfo>();
836 final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
837 // Instruction to clear metadata except SI and LportTag bits
838 instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] {
839 CLEAR_METADATA, METADATA_MASK_CLEAR }));
840 // Instruction to clear action
841 instructions.add(new InstructionInfo(InstructionType.clear_actions));
842 // Instruction to goto L3 InterfaceTable
844 List <ActionInfo> actionsInfos = new ArrayList <ActionInfo> ();
845 actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{
846 Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)}));
847 instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
848 //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE }));
850 FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE,
851 getFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW),
852 NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
853 if (addOrRemove == NwConstants.ADD_FLOW) {
854 LOG.info("Invoking MDSAL to install L3 interface Table Miss Entries");
855 mdsalManager.installFlow(flowEntityL3Intf);
857 mdsalManager.removeFlow(flowEntityL3Intf);