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