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