Merge "Bug 5267 - Setting vlan id for termination end point not working"
[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<OpState> opStateData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL,
464                                                    FibUtil.getVpnInterfaceOpStateIdentifier(ifName));
465       if(opStateData.isPresent() && !opStateData.get().isStateUp()) {
466         Optional<Adjacencies>
467             optAdjacencies =
468             FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getAdjListPath(ifName));
469         int numAdj = 0;
470         if (optAdjacencies.isPresent()) {
471           numAdj = optAdjacencies.get().getAdjacency().size();
472         }
473         LOG.trace("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId,
474                   vrfEntry.getDestPrefix());
475         //remove adjacency corr to prefix
476         FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
477                        FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
478
479         if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
480           //clean up the vpn interface from DpnToVpn list
481           delIntfFromDpnToVpnList(vpnId, prefixInfo.getDpnId(), ifName, rd);
482           LOG.trace("cleanUpOpDataForFib: Delete prefix to interface and vpnInterface ");
483           FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
484                          FibUtil.getPrefixToInterfaceIdentifier(
485                              vpnId,
486                              (extra_route) ? vrfEntry.getNextHopAddress() + "/32"
487                                            : vrfEntry.getDestPrefix()));
488           FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
489                          FibUtil.getVpnInterfaceIdentifier(ifName));
490         }
491       }
492   }
493
494   private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier,
495                                 final VrfEntry vrfEntry) {
496     final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
497     Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
498     Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
499
500     VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
501     Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
502     Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
503     BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(),
504               vrfTableKey.getRouteDistinguisher(), vrfEntry);
505     if (vpnToDpnList != null) {
506       for (VpnToDpnList curDpn : vpnToDpnList) {
507         if (!curDpn.getDpnId().equals(localDpnId)) {
508           deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry);
509         }
510       }
511     }
512     //The flow/group entry has been deleted from config DS; need to clean up associated operational
513     //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
514     cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
515   }
516
517   public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
518                                 final long vpnId, final VrfTablesKey vrfTableKey,
519                                 final VrfEntry vrfEntry) {
520     LOG.debug("deleting route "+ vrfEntry.getDestPrefix() + " "+vpnId);
521     String rd = vrfTableKey.getRouteDistinguisher();
522     boolean isRemoteRoute = true;
523     if (localDpnId == null) {
524       // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
525       VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
526       if(localNextHopInfo == null) {
527         //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
528         Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
529         if (extra_route != null) {
530           localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp());
531         }
532       }
533       isRemoteRoute = ((localNextHopInfo != null) && (!remoteDpnId.equals(localNextHopInfo.getDpnId())));
534     }
535     if (isRemoteRoute) {
536       makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
537       LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId);
538     } else{
539       LOG.debug("Did not delete fib entry rd: {} =, prefix: {} as it is local to dpn {}", rd, vrfEntry.getDestPrefix(), remoteDpnId);
540     }
541   }
542
543   private long getIpAddress(byte[] rawIpAddress) {
544     return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
545             + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
546   }
547
548   private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
549                                   List<ActionInfo> actionInfos, int addOrRemove) {
550     LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
551     String values[] = vrfEntry.getDestPrefix().split("/");
552     String ipAddress = values[0];
553     int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
554     LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength);
555     InetAddress destPrefix = null;
556     try {
557       destPrefix = InetAddress.getByName(ipAddress);
558     } catch (UnknownHostException e) {
559       LOG.error("UnknowHostException in addRoute. Failed  to add Route for ipPrefix {}", vrfEntry.getDestPrefix());
560       return;
561     }
562
563     List<MatchInfo> matches = new ArrayList<MatchInfo>();
564
565     matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
566         BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
567
568     matches.add(new MatchInfo(MatchFieldType.eth_type,
569                               new long[] { 0x0800L }));
570
571     if(prefixLength != 0) {
572       matches.add(new MatchInfo(MatchFieldType.ipv4_dst, new long[] {
573           getIpAddress(destPrefix.getAddress()), prefixLength }));
574     }
575
576     List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
577     if(addOrRemove == NwConstants.ADD_FLOW) {
578       instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
579     }
580
581     String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, destPrefix);
582
583     FlowEntity flowEntity;
584
585     int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
586     flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
587                                            priority, flowRef, 0, 0,
588                                            COOKIE_VM_FIB_TABLE, matches, instructions);
589
590     if (addOrRemove == NwConstants.ADD_FLOW) {
591       /* We need to call sync API to install flow so that 2 DS operations on the same object do not
592       * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
593       * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
594       * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
595       * wait indefinitely. */
596       mdsalManager.syncInstallFlow(flowEntity, 1);
597     } else {
598       mdsalManager.syncRemoveFlow(flowEntity, 1);
599     }
600   }
601
602   private void makeLFibTableEntry(BigInteger dpId, long label, long groupId,
603                                   String nextHop, int addOrRemove) {
604     List<MatchInfo> matches = new ArrayList<MatchInfo>();
605     matches.add(new MatchInfo(MatchFieldType.eth_type,
606                               new long[] { 0x8847L }));
607     matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
608
609     List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
610     List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
611     actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
612     actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
613     instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
614
615     // Install the flow entry in L3_LFIB_TABLE
616     String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, nextHop);
617
618     FlowEntity flowEntity;
619     flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef,
620                                            DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
621                                            COOKIE_VM_LFIB_TABLE, matches, instructions);
622
623     if (addOrRemove == NwConstants.ADD_FLOW) {
624       /* We need to call sync API to install flow so that 2 DS operations on the same object do not
625       * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
626       * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
627       * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
628       * wait indefinitely. */
629
630       mdsalManager.syncInstallFlow(flowEntity, 1);
631     } else {
632       mdsalManager.syncRemoveFlow(flowEntity, 1);
633     }
634     LOG.debug("LFIB Entry for dpID {} : label : {} group {} modified successfully {}",dpId, label, groupId );
635   }
636
637   private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
638     LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
639     try {
640       nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
641     } catch (NullPointerException e) {
642       LOG.trace("", e);
643     }
644   }
645
646   public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) {
647     LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
648     InstanceIdentifier<VrfTables> id = buildVrfId(rd);
649     Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
650     if(vrfTable.isPresent()) {
651       for(VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
652         // Passing null as we don't know the dpn
653         // to which prefix is attached at this point
654         createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
655       }
656     }
657   }
658
659   public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) {
660     LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
661     InstanceIdentifier<VrfTables> id = buildVrfId(rd);
662     Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
663     if(vrfTable.isPresent()) {
664       for(VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
665         // Passing null as we don't know the dpn
666         // to which prefix is attached at this point
667         deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
668       }
669     }
670   }
671
672   public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
673     InstanceIdentifierBuilder<VrfTables> idBuilder =
674         InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
675     InstanceIdentifier<VrfTables> id = idBuilder.build();
676     return id;
677   }
678
679   private String getFlowRef(BigInteger dpnId, short tableId, long label, String nextHop) {
680     return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
681         .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
682         .append(label).append(NwConstants.FLOWID_SEPARATOR)
683         .append(nextHop).toString();
684   }
685
686   private String getFlowRef(BigInteger dpnId, short tableId, String rd, InetAddress destPrefix) {
687     return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
688         .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
689         .append(rd).append(NwConstants.FLOWID_SEPARATOR)
690         .append(destPrefix.getHostAddress()).toString();
691   }
692
693   protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId,
694                                               final long vpnId, final VrfEntry vrfEntry, String rd) {
695     String adjacency = null;
696     boolean staticRoute = false;
697     LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry);
698     try {
699         Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
700         if(extra_route != null) {
701             staticRoute = true;
702         }
703
704         adjacency =
705           nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId,
706                                                  vrfEntry.getDestPrefix(),
707                   (staticRoute == true) ? extra_route.getNexthopIp() : vrfEntry.getNextHopAddress());
708     } catch (NullPointerException e) {
709       LOG.trace("", e);
710     }
711     return adjacency;
712   }
713
714   protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
715     InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.create(VpnInstanceOpData.class).child(
716         VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
717     Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
718     if(vpnInstanceOpData.isPresent()) {
719       return vpnInstanceOpData.get();
720     }
721     return null;
722   }
723
724     public void processNodeAdd(BigInteger dpnId) {
725         LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
726         makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
727         makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
728     }
729
730     private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
731         final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
732         // Instruction to goto L3 InterfaceTable
733         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
734         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE }));
735         List<MatchInfo> matches = new ArrayList<MatchInfo>();
736         FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE,
737                 getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW),
738                 NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
739
740         FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE, getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, NwConstants.TABLE_MISS_FLOW),
741                 NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow", 0, 0, COOKIE_VM_FIB_TABLE,
742                 matches, instructions);
743
744         if (addOrRemove == NwConstants.ADD_FLOW) {
745             LOG.debug("Invoking MDSAL to install Table Miss Entries");
746             mdsalManager.installFlow(flowEntityLfib);
747             mdsalManager.installFlow(flowEntityFib);
748         } else {
749             mdsalManager.removeFlow(flowEntityLfib);
750             mdsalManager.removeFlow(flowEntityFib);
751
752         }
753     }
754
755     private String getFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
756         return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
757                 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
758                 .append(FLOWID_PREFIX).toString();
759     }
760
761   /*
762    * Install flow entry in protocol table to forward mpls
763    * coming through gre tunnel to LFIB table.
764    */
765   private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
766     final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
767     // Instruction to goto L3 InterfaceTable
768     List<InstructionInfo> instructions = new ArrayList<>();
769     instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
770     List<MatchInfo> matches = new ArrayList<MatchInfo>();
771     matches.add(new MatchInfo(MatchFieldType.eth_type,
772                               new long[] { 0x8847L }));
773     FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_PROTOCOL_TABLE,
774                                                           getFlowRef(dpnId, NwConstants.L3_PROTOCOL_TABLE,
775                                                                   NwConstants.L3_LFIB_TABLE),
776                                                           DEFAULT_FIB_FLOW_PRIORITY,
777                                                           "Protocol Table For LFIB",
778                                                           0, 0,
779                                                           COOKIE_PROTOCOL_TABLE,
780                                                           matches, instructions);
781
782     if (addOrRemove == NwConstants.ADD_FLOW) {
783       LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
784       mdsalManager.installFlow(flowEntityToLfib);
785     } else {
786       mdsalManager.removeFlow(flowEntityToLfib);
787     }
788   }
789
790   public List<String> printFibEntries() {
791     List<String> result = new ArrayList<String>();
792     result.add(String.format("   %-7s  %-20s  %-20s  %-7s", "RD", "Prefix", "Nexthop", "Label"));
793     result.add("-------------------------------------------------------------------");
794     InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
795     Optional<FibEntries> fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
796     if (fibEntries.isPresent()) {
797       List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
798       for (VrfTables vrfTable : vrfTables) {
799         for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
800           result.add(String.format("   %-7s  %-20s  %-20s  %-7s", vrfTable.getRouteDistinguisher(),
801                   vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress(), vrfEntry.getLabel()));
802         }
803       }
804     }
805     return result;
806   }
807
808   private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) {
809     List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
810     List<MatchInfo> matches = new ArrayList<MatchInfo>();
811     final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
812     // Instruction to clear metadata except SI and LportTag bits
813     instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] {
814                     CLEAR_METADATA, METADATA_MASK_CLEAR }));
815     // Instruction to clear action
816     instructions.add(new InstructionInfo(InstructionType.clear_actions));
817     // Instruction to goto L3 InterfaceTable
818
819     instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE }));
820
821     FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE,
822             getFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW),
823             NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
824     if (addOrRemove == NwConstants.ADD_FLOW) {
825       LOG.info("Invoking MDSAL to install L3 interface Table Miss Entries");
826       mdsalManager.installFlow(flowEntityL3Intf);
827     } else {
828       mdsalManager.removeFlow(flowEntityL3Intf);
829     }
830   }
831
832 }