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