Merge "Bug: 5009"
[vpnservice.git] / fibmanager / fibmanager-impl / src / main / java / org / opendaylight / vpnservice / fibmanager / FibManager.java
1 /*
2  * Copyright (c) 2015 - 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.vpnservice.fibmanager;
9
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;
14
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;
23
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.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency;
76 import org.opendaylight.yangtools.concepts.ListenerRegistration;
77 import org.opendaylight.yangtools.yang.binding.DataObject;
78 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
79 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
80 import org.opendaylight.yangtools.yang.common.RpcResult;
81 import org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
83
84 public class FibManager extends AbstractDataChangeListener<VrfEntry> implements AutoCloseable{
85   private static final Logger LOG = LoggerFactory.getLogger(FibManager.class);
86   private static final String FLOWID_PREFIX = "L3.";
87   private ListenerRegistration<DataChangeListener> listenerRegistration;
88   private final DataBroker broker;
89   private IMdsalApiManager mdsalManager;
90   private IVpnManager vpnmanager;
91   private NexthopManager nextHopManager;
92   private ItmRpcService itmManager;
93   private OdlInterfaceRpcService interfaceManager;
94   private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
95   private static final BigInteger COOKIE_VM_FIB_TABLE =  new BigInteger("8000003", 16);
96   private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
97   private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16);
98   private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0);
99   public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
100
101
102   public FibManager(final DataBroker db) {
103     super(VrfEntry.class);
104     broker = db;
105     registerListener(db);
106   }
107
108   @Override
109   public void close() throws Exception {
110     if (listenerRegistration != null) {
111       try {
112         listenerRegistration.close();
113       } catch (final Exception e) {
114         LOG.error("Error when cleaning up DataChangeListener.", e);
115       }
116       listenerRegistration = null;
117     }
118     LOG.info("Fib Manager Closed");
119   }
120
121   public void setNextHopManager(NexthopManager nextHopManager) {
122     this.nextHopManager = nextHopManager;
123   }
124
125   public void setMdsalManager(IMdsalApiManager mdsalManager) {
126     this.mdsalManager = mdsalManager;
127   }
128
129   public void setVpnmanager(IVpnManager vpnmanager) {
130     this.vpnmanager = vpnmanager;
131   }
132
133   public void setITMRpcService(ItmRpcService itmManager) {
134       this.itmManager = itmManager;
135   }
136   
137   public void setInterfaceManager(OdlInterfaceRpcService ifManager) {
138       this.interfaceManager = ifManager;
139   }
140
141   private void registerListener(final DataBroker db) {
142     try {
143       listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
144                                                            getWildCardPath(), FibManager.this, DataChangeScope.SUBTREE);
145     } catch (final Exception e) {
146       LOG.error("FibManager DataChange listener registration fail!", e);
147       throw new IllegalStateException("FibManager registration Listener failed.", e);
148     }
149   }
150
151
152   private InstanceIdentifier<VrfEntry> getWildCardPath() {
153     return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
154   }
155
156
157   @Override
158   protected void add(final InstanceIdentifier<VrfEntry> identifier,
159                      final VrfEntry vrfEntry) {
160     LOG.trace("key: " + identifier + ", value=" + vrfEntry );
161     createFibEntries(identifier, vrfEntry);
162   }
163
164   @Override
165   protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
166     LOG.trace("key: " + identifier + ", value=" + vrfEntry);
167     deleteFibEntries(identifier, vrfEntry);
168   }
169
170   @Override
171   protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
172     LOG.trace("key: " + identifier + ", original=" + original + ", update=" + update );
173     createFibEntries(identifier, update);
174   }
175
176   private void createFibEntries(final InstanceIdentifier<VrfEntry> identifier,
177                                 final VrfEntry vrfEntry) {
178     final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
179     Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
180     Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
181
182     VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
183     Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
184     Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + "has null vpnId!");
185
186     Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
187     BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(),
188               vrfTableKey.getRouteDistinguisher(), vrfEntry);
189     if (vpnToDpnList != null) {
190       for (VpnToDpnList curDpn : vpnToDpnList) {
191         if (!curDpn.getDpnId().equals(localDpnId)) {
192           createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(),
193                                vrfTableKey, vrfEntry);
194         }
195       }
196     }
197   }
198
199   public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
200     BigInteger localDpnId = BigInteger.ZERO;
201     Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
202     String localNextHopIP = vrfEntry.getDestPrefix();
203
204     if(localNextHopInfo == null) {
205         //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
206         Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
207         if (extra_route != null) {
208             localNextHopInfo = getPrefixToInterface(vpnId, extra_route.getNexthopIp() + "/32");
209             localNextHopIP = extra_route.getNexthopIp() + "/32";
210         }
211     }
212
213     if(localNextHopInfo != null) {
214       localDpnId = localNextHopInfo.getDpnId();
215       long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
216       List<ActionInfo> actionInfos = new ArrayList<ActionInfo>();
217
218       actionInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
219
220       makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW);
221       makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), groupId, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW);
222
223       LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}", 
224                       localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
225       makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId);
226
227     }
228     return localDpnId;
229   }
230
231   private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/) {
232       List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
233       actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
234
235
236       createTerminatingServiceActions(dpId, (int)label, actionsInfos);
237
238       LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully {}",
239               dpId, label, groupId);
240   }
241
242   public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos) {
243       List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
244
245       LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
246
247       // Matching metadata
248       // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
249       mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
250
251       List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
252       mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
253
254       FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
255                       getFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
256                       0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
257
258       mdsalManager.installFlow(terminatingServiceTableFlowEntity);
259  }
260
261   private void removeTunnelTableEntry(BigInteger dpId, long label) {
262     FlowEntity flowEntity;
263     LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
264     List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
265     // Matching metadata
266     mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
267     flowEntity = MDSALUtil.buildFlowEntity(dpId,
268                                            NwConstants.INTERNAL_TUNNEL_TABLE,
269                                            getFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
270                                            5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
271                                            COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
272     mdsalManager.removeFlow(flowEntity);
273     LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpId, label);
274   }
275
276   public BigInteger deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
277     BigInteger localDpnId = BigInteger.ZERO;
278     VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
279     String localNextHopIP = vrfEntry.getDestPrefix();
280
281     if(localNextHopInfo == null) {
282         //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
283         Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
284         if (extra_route != null) {
285             localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp());
286             localNextHopIP = extra_route.getNexthopIp() + "/32";
287         }
288     }
289
290
291     if(localNextHopInfo != null) {
292       localDpnId = localNextHopInfo.getDpnId();
293       //if (getPrefixToInterface(vpnId, (staticRoute == true) ? extra_route.getNextHopAddress() + "/32" : vrfEntry.getDestPrefix()) == null)
294       {
295         makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */,
296                            NwConstants.DEL_FLOW);
297         makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), 0 /* invalid */,
298                            vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW);
299         removeTunnelTableEntry(localDpnId, vrfEntry.getLabel());
300         deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP);
301       }
302     }
303     return localDpnId;
304   }
305
306   private InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) {
307     return InstanceIdentifier.builder(PrefixToInterface.class)
308         .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
309   }
310
311   private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
312     Optional<Prefixes> localNextHopInfoData =
313         FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
314     return  localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
315   }
316
317     private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
318         return InstanceIdentifier.builder(VpnToExtraroute.class)
319                 .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class,
320                         new ExtrarouteKey(ipPrefix)).build();
321     }
322
323     private Extraroute getVpnToExtraroute(String rd, String ipPrefix) {
324         Optional<Extraroute> extraRouteInfo =
325                 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix));
326         return  extraRouteInfo.isPresent() ? extraRouteInfo.get() : null;
327
328     }
329
330   private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
331         try {
332             Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
333                           new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
334           RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
335           if(!rpcResult.isSuccessful()) {
336               LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
337           } else {
338               return rpcResult.getResult().getTunnelType();
339           }
340           
341       } catch (InterruptedException | ExecutionException e) {
342           LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e);
343       }
344   
345   return null;
346
347   }
348   private void createRemoteFibEntry(final BigInteger localDpnId, final BigInteger remoteDpnId,
349                                     final long vpnId, final VrfTablesKey vrfTableKey,
350                                     final VrfEntry vrfEntry) {
351     String rd = vrfTableKey.getRouteDistinguisher();
352     LOG.debug("adding route " + vrfEntry.getDestPrefix() + " " + rd);
353     /********************************************/
354     String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd);
355     if(tunnelInterface == null) {
356       LOG.error("Could not get interface for nexthop: {} in vpn {}",
357                                    vrfEntry.getNextHopAddress(), rd);
358       LOG.warn("Failed to add Route: {} in vpn: {}",
359                              vrfEntry.getDestPrefix(), rd);
360       return;
361     }
362       List<ActionInfo> actionInfos = new ArrayList<>();
363         Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
364     if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
365         LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
366         actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
367         actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
368     } else {
369         int label = vrfEntry.getLabel().intValue();
370         BigInteger tunnelId;
371         // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
372         if(tunnel_type.equals(TunnelTypeVxlan.class)) {
373                 tunnelId = BigInteger.valueOf(label);
374         } else {
375                 tunnelId = BigInteger.valueOf(label);
376         }
377         LOG.debug("adding set tunnel id action for label {}", label);
378         actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{
379                 tunnelId}));
380     }
381     actionInfos.addAll(nextHopManager.getEgressActionsForInterface(tunnelInterface));
382 /*
383     List<ActionInfo> actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry);
384     if(actionInfos == null) {
385       LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}",
386                                    vrfEntry.getNextHopAddress(), rd);
387       LOG.warn("Failed to add Route: {} in vpn: {}",
388                              vrfEntry.getDestPrefix(), rd);
389       return;
390     }
391     BigInteger dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getDestPrefix());
392     if(dpnId == null) {
393         //This route may be extra route... try to query with nexthop Ip
394         LOG.debug("Checking for extra route to install remote fib entry {}", vrfEntry.getDestPrefix());
395         dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getNextHopAddress() + "/32");
396     }
397     if(dpnId == null) {
398         LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
399         actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
400         actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
401     } else {
402         int label = vrfEntry.getLabel().intValue();
403         LOG.debug("adding set tunnel id action for label {}", label);
404         actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
405                 MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label),
406                 MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
407     }
408 **/
409       makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, actionInfos, NwConstants.ADD_FLOW);
410     LOG.debug(
411         "Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId);
412   }
413
414     private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
415         InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
416         Optional<VpnToDpnList> dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
417         if (dpnInVpn.isPresent()) {
418             List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
419                     .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
420             org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
421                     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();
422
423             if (vpnInterfaces.remove(currVpnInterface)) {
424                 if (vpnInterfaces.isEmpty()) {
425                     //FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id);
426                     cleanUpDpnForVpn(dpnId, vpnId, rd);
427                 } else {
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)));
432                 }
433             }
434         }
435     }
436
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
445      */
446       Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
447       boolean extra_route = false;
448       if (prefixInfo == null) {
449           prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getNextHopAddress() + "/32");
450           extra_route = true;
451       }
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));
456       int numAdj = 0;
457       if (optAdjacencies.isPresent()) {
458           numAdj = optAdjacencies.get().getAdjacency().size();
459       }
460       //remove adjacency corr to prefix
461       FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
462
463       if((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
464         //clean up the vpn interface from DpnToVpn list
465           delIntfFromDpnToVpnList(vpnId, prefixInfo.getDpnId(), ifName, rd);
466           FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
467                   FibUtil.getPrefixToInterfaceIdentifier(
468                           vpnId,
469                           (extra_route) ? vrfEntry.getNextHopAddress() + "/32" : vrfEntry.getDestPrefix()));
470           FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
471                   FibUtil.getVpnInterfaceIdentifier(ifName));
472       }
473   }
474
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!");
480
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);
490         }
491       }
492     }
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);
496   }
497
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     String egressInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd);
504     if(egressInterface == null) {
505       LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}",
506                 vrfEntry.getNextHopAddress(), rd);
507       LOG.warn("Failed to delete Route: {} in vpn: {}",
508                vrfEntry.getDestPrefix(), rd);
509       return;
510     }
511
512     makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
513     LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId);
514   }
515
516   private long getIpAddress(byte[] rawIpAddress) {
517     return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
518             + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
519   }
520
521   private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
522                                   List<ActionInfo> actionInfos, int addOrRemove) {
523     LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
524     String values[] = vrfEntry.getDestPrefix().split("/");
525     String ipAddress = values[0];
526     int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
527     LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength);
528     InetAddress destPrefix = null;
529     try {
530       destPrefix = InetAddress.getByName(ipAddress);
531     } catch (UnknownHostException e) {
532       LOG.error("UnknowHostException in addRoute. Failed  to add Route for ipPrefix {}", vrfEntry.getDestPrefix());
533       return;
534     }
535
536     List<MatchInfo> matches = new ArrayList<MatchInfo>();
537
538     matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
539         BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
540
541     matches.add(new MatchInfo(MatchFieldType.eth_type,
542                               new long[] { 0x0800L }));
543
544     if(prefixLength != 0) {
545       matches.add(new MatchInfo(MatchFieldType.ipv4_dst, new long[] {
546           getIpAddress(destPrefix.getAddress()), prefixLength }));
547     }
548
549     List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
550     if(addOrRemove == NwConstants.ADD_FLOW) {
551       instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
552     }
553
554     String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, destPrefix);
555
556     FlowEntity flowEntity;
557
558     int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
559     flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
560                                            priority, flowRef, 0, 0,
561                                            COOKIE_VM_FIB_TABLE, matches, instructions);
562
563     if (addOrRemove == NwConstants.ADD_FLOW) {
564       /* We need to call sync API to install flow so that 2 DS operations on the same object do not
565       * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
566       * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
567       * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
568       * wait indefinitely. */
569       mdsalManager.syncInstallFlow(flowEntity, 1);
570     } else {
571       mdsalManager.syncRemoveFlow(flowEntity, 1);
572     }
573   }
574
575   private void makeLFibTableEntry(BigInteger dpId, long label, long groupId,
576                                   String nextHop, int addOrRemove) {
577     List<MatchInfo> matches = new ArrayList<MatchInfo>();
578     matches.add(new MatchInfo(MatchFieldType.eth_type,
579                               new long[] { 0x8847L }));
580     matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
581
582     List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
583     List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
584     actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
585     actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
586     instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
587
588     // Install the flow entry in L3_LFIB_TABLE
589     String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, nextHop);
590
591     FlowEntity flowEntity;
592     flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef,
593                                            DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
594                                            COOKIE_VM_LFIB_TABLE, matches, instructions);
595
596     if (addOrRemove == NwConstants.ADD_FLOW) {
597       /* We need to call sync API to install flow so that 2 DS operations on the same object do not
598       * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
599       * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
600       * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
601       * wait indefinitely. */
602
603       mdsalManager.syncInstallFlow(flowEntity, 1);
604     } else {
605       mdsalManager.syncRemoveFlow(flowEntity, 1);
606     }
607     LOG.debug("LFIB Entry for dpID {} : label : {} group {} modified successfully {}",dpId, label, groupId );
608   }
609
610   private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
611     LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
612     try {
613       nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
614     } catch (NullPointerException e) {
615       LOG.trace("", e);
616     }
617   }
618
619   public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) {
620     LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
621     InstanceIdentifier<VrfTables> id = buildVrfId(rd);
622     Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
623     if(vrfTable.isPresent()) {
624       for(VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
625         // Passing null as we don't know the dpn
626         // to which prefix is attached at this point
627         createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
628       }
629     }
630   }
631
632   public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) {
633     LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
634     InstanceIdentifier<VrfTables> id = buildVrfId(rd);
635     Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
636     if(vrfTable.isPresent()) {
637       for(VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
638         // Passing null as we don't know the dpn
639         // to which prefix is attached at this point
640         deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
641       }
642     }
643   }
644
645   public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
646     InstanceIdentifierBuilder<VrfTables> idBuilder =
647         InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
648     InstanceIdentifier<VrfTables> id = idBuilder.build();
649     return id;
650   }
651
652   private String getFlowRef(BigInteger dpnId, short tableId, long label, String nextHop) {
653     return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
654         .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
655         .append(label).append(NwConstants.FLOWID_SEPARATOR)
656         .append(nextHop).toString();
657   }
658
659   private String getFlowRef(BigInteger dpnId, short tableId, String rd, InetAddress destPrefix) {
660     return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
661         .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
662         .append(rd).append(NwConstants.FLOWID_SEPARATOR)
663         .append(destPrefix.getHostAddress()).toString();
664   }
665
666   protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId,
667                                               final long vpnId, final VrfEntry vrfEntry, String rd) {
668     String adjacency = null;
669     boolean staticRoute = false;
670     LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry);
671     try {
672         Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
673         if(extra_route != null) {
674             staticRoute = true;
675         }
676
677         adjacency =
678           nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId,
679                                                  vrfEntry.getDestPrefix(),
680                   (staticRoute == true) ? extra_route.getNexthopIp() : vrfEntry.getNextHopAddress());
681     } catch (NullPointerException e) {
682       LOG.trace("", e);
683     }
684     return adjacency;
685   }
686
687   protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
688     InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.create(VpnInstanceOpData.class).child(
689         VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
690     Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
691     if(vpnInstanceOpData.isPresent()) {
692       return vpnInstanceOpData.get();
693     }
694     return null;
695   }
696
697     public void processNodeAdd(BigInteger dpnId) {
698         LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
699         makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
700         makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
701     }
702
703     private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
704         final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
705         // Instruction to goto L3 InterfaceTable
706         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
707         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE }));
708         List<MatchInfo> matches = new ArrayList<MatchInfo>();
709         FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE,
710                 getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW),
711                 NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
712
713         FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE, getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, NwConstants.TABLE_MISS_FLOW),
714                 NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow", 0, 0, COOKIE_VM_FIB_TABLE,
715                 matches, instructions);
716
717         if (addOrRemove == NwConstants.ADD_FLOW) {
718             LOG.debug("Invoking MDSAL to install Table Miss Entries");
719             mdsalManager.installFlow(flowEntityLfib);
720             mdsalManager.installFlow(flowEntityFib);
721         } else {
722             mdsalManager.removeFlow(flowEntityLfib);
723             mdsalManager.removeFlow(flowEntityFib);
724
725         }
726     }
727
728     private String getFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
729         return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
730                 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
731                 .append(FLOWID_PREFIX).toString();
732     }
733
734   /*
735    * Install flow entry in protocol table to forward mpls
736    * coming through gre tunnel to LFIB table.
737    */
738   private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
739     final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
740     // Instruction to goto L3 InterfaceTable
741     List<InstructionInfo> instructions = new ArrayList<>();
742     instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
743     List<MatchInfo> matches = new ArrayList<MatchInfo>();
744     matches.add(new MatchInfo(MatchFieldType.eth_type,
745                               new long[] { 0x8847L }));
746     FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_PROTOCOL_TABLE,
747                                                           getFlowRef(dpnId, NwConstants.L3_PROTOCOL_TABLE,
748                                                                   NwConstants.L3_LFIB_TABLE),
749                                                           DEFAULT_FIB_FLOW_PRIORITY,
750                                                           "Protocol Table For LFIB",
751                                                           0, 0,
752                                                           COOKIE_PROTOCOL_TABLE,
753                                                           matches, instructions);
754
755     if (addOrRemove == NwConstants.ADD_FLOW) {
756       LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
757       mdsalManager.installFlow(flowEntityToLfib);
758     } else {
759       mdsalManager.removeFlow(flowEntityToLfib);
760     }
761   }
762
763   public List<String> printFibEntries() {
764     List<String> result = new ArrayList<String>();
765     result.add(String.format("   %-7s  %-20s  %-20s  %-7s", "RD", "Prefix", "Nexthop", "Label"));
766     result.add("-------------------------------------------------------------------");
767     InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
768     Optional<FibEntries> fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
769     if (fibEntries.isPresent()) {
770       List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
771       for (VrfTables vrfTable : vrfTables) {
772         for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
773           result.add(String.format("   %-7s  %-20s  %-20s  %-7s", vrfTable.getRouteDistinguisher(),
774                   vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress(), vrfEntry.getLabel()));
775         }
776       }
777     }
778     return result;
779   }
780
781   private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) {
782     List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
783     List<MatchInfo> matches = new ArrayList<MatchInfo>();
784     final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
785     // Instruction to clear metadata except SI and LportTag bits
786     instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] {
787                     CLEAR_METADATA, METADATA_MASK_CLEAR }));
788     // Instruction to clear action
789     instructions.add(new InstructionInfo(InstructionType.clear_actions));
790     // Instruction to goto L3 InterfaceTable
791
792     instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE }));
793
794     FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE,
795             getFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW),
796             NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
797     if (addOrRemove == NwConstants.ADD_FLOW) {
798       LOG.info("Invoking MDSAL to install L3 interface Table Miss Entries");
799       mdsalManager.installFlow(flowEntityL3Intf);
800     } else {
801       mdsalManager.removeFlow(flowEntityL3Intf);
802     }
803   }
804
805 }