LLDP monitor interval update 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.HashSet;
21 import java.util.List;
22 import java.util.concurrent.ExecutionException;
23 import java.util.concurrent.Future;
24
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
27 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
28 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
29 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.vpnmanager.api.IVpnManager;
32 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
33 import org.opendaylight.vpnservice.itm.globals.ITMConstants;
34 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
35 import org.opendaylight.vpnservice.mdsalutil.ActionType;
36 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
37 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
38 import org.opendaylight.vpnservice.mdsalutil.InstructionType;
39 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
40 import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
41 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
42 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
43 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
44 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.PrefixToInterface;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnInstanceOpData;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.RdToElanOp;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntry;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.rd.to.elan.op.RdToElanOpEntryKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.VpnToExtraroute;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIds;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.VpnIdsKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.prefix.to._interface.vpn.ids.PrefixesKey;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.Vpn;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.VpnKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.Extraroute;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.to.extraroute.vpn.ExtrarouteKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.FibEntries;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTables;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.fibentries.VrfTablesKey;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fibmanager.rev150330.vrfentries.VrfEntry;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeBase;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.TunnelTypeMplsOverGre;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeInputBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetTunnelTypeOutput;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.Adjacencies;
78 import org.opendaylight.yangtools.concepts.ListenerRegistration;
79 import org.opendaylight.yangtools.yang.binding.DataObject;
80 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
81 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
82 import org.opendaylight.yangtools.yang.common.RpcResult;
83 import org.slf4j.Logger;
84 import org.slf4j.LoggerFactory;
85
86 public class FibManager extends AbstractDataChangeListener<VrfEntry> implements AutoCloseable{
87   private static final Logger LOG = LoggerFactory.getLogger(FibManager.class);
88   private static final String FLOWID_PREFIX = "L3.";
89   private ListenerRegistration<DataChangeListener> listenerRegistration;
90   private final DataBroker broker;
91   private IMdsalApiManager mdsalManager;
92   private IVpnManager vpnmanager;
93   private NexthopManager nextHopManager;
94   private ItmRpcService itmManager;
95   private OdlInterfaceRpcService interfaceManager;
96   private static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000002", 16);
97   private static final BigInteger COOKIE_VM_FIB_TABLE =  new BigInteger("8000003", 16);
98   private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
99   private static final BigInteger METADATA_MASK_CLEAR = new BigInteger("000000FFFFFFFFFF", 16);
100   private static final BigInteger CLEAR_METADATA = BigInteger.valueOf(0);
101   public static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
102
103
104   public FibManager(final DataBroker db) {
105     super(VrfEntry.class);
106     broker = db;
107     registerListener(db);
108   }
109
110   @Override
111   public void close() throws Exception {
112     if (listenerRegistration != null) {
113       try {
114         listenerRegistration.close();
115       } catch (final Exception e) {
116         LOG.error("Error when cleaning up DataChangeListener.", e);
117       }
118       listenerRegistration = null;
119     }
120     LOG.info("Fib Manager Closed");
121   }
122
123   public void setNextHopManager(NexthopManager nextHopManager) {
124     this.nextHopManager = nextHopManager;
125   }
126
127   public void setMdsalManager(IMdsalApiManager mdsalManager) {
128     this.mdsalManager = mdsalManager;
129   }
130
131   public void setVpnmanager(IVpnManager vpnmanager) {
132     this.vpnmanager = vpnmanager;
133   }
134
135   public void setITMRpcService(ItmRpcService itmManager) {
136       this.itmManager = itmManager;
137   }
138   
139   public void setInterfaceManager(OdlInterfaceRpcService ifManager) {
140       this.interfaceManager = ifManager;
141   }
142
143   private void registerListener(final DataBroker db) {
144     try {
145       listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
146                                                            getWildCardPath(), FibManager.this, DataChangeScope.SUBTREE);
147     } catch (final Exception e) {
148       LOG.error("FibManager DataChange listener registration fail!", e);
149       throw new IllegalStateException("FibManager registration Listener failed.", e);
150     }
151   }
152
153
154   private InstanceIdentifier<VrfEntry> getWildCardPath() {
155     return InstanceIdentifier.create(FibEntries.class).child(VrfTables.class).child(VrfEntry.class);
156   }
157
158
159   @Override
160   protected void add(final InstanceIdentifier<VrfEntry> identifier,
161                      final VrfEntry vrfEntry) {
162     LOG.trace("key: " + identifier + ", value=" + vrfEntry );
163     createFibEntries(identifier, vrfEntry);
164   }
165
166   @Override
167   protected void remove(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry) {
168     LOG.trace("key: " + identifier + ", value=" + vrfEntry);
169     deleteFibEntries(identifier, vrfEntry);
170   }
171
172   @Override
173   protected void update(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update) {
174     LOG.trace("key: " + identifier + ", original=" + original + ", update=" + update );
175     createFibEntries(identifier, update);
176   }
177
178   private void createFibEntries(final InstanceIdentifier<VrfEntry> identifier,
179                                 final VrfEntry vrfEntry) {
180     final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
181     Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
182     Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
183
184     VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
185     Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
186     Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + "has null vpnId!");
187
188     Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
189     Long vpnId = vpnInstance.getVpnId();
190     RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, vrfTableKey.getRouteDistinguisher(),
191             vrfEntry.getDestPrefix());
192     if (rdToElanOpEntry!=null) {
193         if (vpnToDpnList!=null) {
194             for (VpnToDpnList curDpn :  vpnToDpnList) {
195                 installSubnetRouteInFib(curDpn.getDpnId(), rdToElanOpEntry, vpnId.longValue(), vrfEntry);
196             }
197         }
198         return;
199     }
200     BigInteger localDpnId = createLocalFibEntry(vpnInstance.getVpnId(),
201               vrfTableKey.getRouteDistinguisher(), vrfEntry);
202     if (vpnToDpnList != null) {
203       for (VpnToDpnList curDpn : vpnToDpnList) {
204         if (!curDpn.getDpnId().equals(localDpnId)) {
205           createRemoteFibEntry(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(),
206                                vrfTableKey, vrfEntry);
207         }
208       }
209     }
210   }
211
212   private void installSubnetRouteInFib(BigInteger dpnId, RdToElanOpEntry rdToElanOpEntry,
213                                        long vpnId, VrfEntry vrfEntry){
214       makeSubnetRouteFlow(dpnId);
215       List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
216       List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
217       Long elanTag = rdToElanOpEntry.getElanTag();
218       instructions.add(new InstructionInfo(InstructionType.write_metadata,  new BigInteger[] { (BigInteger.valueOf(elanTag)).shiftLeft(24), MetaDataUtil.METADATA_MASK_SERVICE }));
219       instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_SUBNET_ROUTE_TABLE }));
220       makeConnectedRoute(dpnId,vpnId,vrfEntry,rdToElanOpEntry.getRd(),
221               instructions,NwConstants.ADD_FLOW);
222       makeLFibTableEntry(dpnId,vrfEntry.getLabel(),instructions,
223               vrfEntry.getNextHopAddress(),NwConstants.ADD_FLOW);
224       // TODO makeTunnelTableEntry();
225   }
226
227   private RdToElanOpEntry getRdToElanOpEntry(DataBroker broker, String rd, String subnetIp) {
228       InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(rd,subnetIp);
229       Optional<RdToElanOpEntry> sn = read(broker, LogicalDatastoreType.OPERATIONAL, id);
230       if(sn.isPresent()) {
231           return sn.get();
232       }
233       return null;
234   }
235
236   private InstanceIdentifier<RdToElanOpEntry> getRdToElanOpEntryDataPath(String rd, String subnetIp) {
237       return InstanceIdentifier.builder(RdToElanOp.class).child(RdToElanOpEntry.class,
238               new RdToElanOpEntryKey(rd,subnetIp)).build();
239   }
240   private  <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
241                                                   InstanceIdentifier<T> path) {
242
243       ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
244
245       Optional<T> result = Optional.absent();
246       try {
247           result = tx.read(datastoreType, path).get();
248       } catch (Exception e) {
249           throw new RuntimeException(e);
250       }
251
252       return result;
253   }
254
255   private void makeSubnetRouteFlow(BigInteger dpnId) {
256       //Ask Vivek cookie
257       final BigInteger COOKIE_TABLE_MISS = new BigInteger("8000004", 16);
258       List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
259       List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
260       actionsInfos.add(new ActionInfo(ActionType.punt_to_controller, new String[]{}));
261       instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
262       List<MatchInfo> matches = new ArrayList<MatchInfo>();
263       String flowRef = getFlowRef(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, NwConstants.TABLE_MISS_FLOW);
264       FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_SUBNET_ROUTE_TABLE, flowRef,
265               NwConstants.TABLE_MISS_PRIORITY, "Subnet Route Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
266
267       LOG.debug("Invoking MDSAL to install Table Miss Entries");
268       mdsalManager.syncInstallFlow(flowEntity,1);
269   }
270
271   private Collection<BigInteger> getDpnsForVpn(VpnInstanceOpDataEntry vpnInstance) {
272       Collection<BigInteger> dpns = new HashSet<>();
273       for(VpnToDpnList dpn : vpnInstance.getVpnToDpnList()) {
274           dpns.add(dpn.getDpnId());
275       }
276
277       return dpns;
278   }
279
280   public BigInteger createLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
281     BigInteger localDpnId = BigInteger.ZERO;
282     Prefixes localNextHopInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
283     String localNextHopIP = vrfEntry.getDestPrefix();
284
285     if(localNextHopInfo == null) {
286         //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
287         Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
288         if (extra_route != null) {
289             localNextHopInfo = getPrefixToInterface(vpnId, extra_route.getNexthopIp() + "/32");
290             localNextHopIP = extra_route.getNexthopIp() + "/32";
291         }
292     }
293
294     if(localNextHopInfo != null) {
295         localDpnId = localNextHopInfo.getDpnId();
296         long groupId = nextHopManager.createLocalNextHop(vpnId, localDpnId, localNextHopInfo.getVpnInterfaceName(), localNextHopIP);
297
298         List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
299         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
300
301         actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId)}));
302         instructions.add(new InstructionInfo(InstructionType.write_actions,actionsInfos));
303         makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
304
305         actionsInfos=new ArrayList<ActionInfo>();;
306         instructions=new ArrayList<InstructionInfo>();
307         actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
308         actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
309         instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
310         makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), instructions, vrfEntry.getNextHopAddress(), NwConstants.ADD_FLOW);
311
312         LOG.debug("Installing tunnel table entry on dpn {} for interface {} with label {}",
313                 localDpnId, localNextHopInfo.getVpnInterfaceName(), vrfEntry.getLabel());
314         makeTunnelTableEntry(localDpnId, vrfEntry.getLabel(), groupId);
315
316     }
317     return localDpnId;
318   }
319
320   private void makeTunnelTableEntry(BigInteger dpId, long label, long groupId/*String egressInterfaceName*/) {
321       List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
322       actionsInfos.add(new ActionInfo(ActionType.group, new String[] { String.valueOf(groupId) }));
323
324
325       createTerminatingServiceActions(dpId, (int)label, actionsInfos);
326
327       LOG.debug("Terminating service Entry for dpID {} : label : {} egress : {} installed successfully {}",
328               dpId, label, groupId);
329   }
330
331   public void createTerminatingServiceActions( BigInteger destDpId, int label, List<ActionInfo> actionsInfos) {
332       List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
333
334       LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", destDpId , label,actionsInfos);
335
336       // Matching metadata
337       // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
338       mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
339
340       List<InstructionInfo> mkInstructions = new ArrayList<InstructionInfo>();
341       mkInstructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
342
343       FlowEntity terminatingServiceTableFlowEntity = MDSALUtil.buildFlowEntity(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,
344                       getFlowRef(destDpId, NwConstants.INTERNAL_TUNNEL_TABLE,label), 5, String.format("%s:%d","TST Flow Entry ",label),
345                       0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(label)),mkMatches, mkInstructions);
346
347       mdsalManager.installFlow(terminatingServiceTableFlowEntity);
348  }
349
350   private void removeTunnelTableEntry(BigInteger dpId, long label) {
351     FlowEntity flowEntity;
352     LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId , label);
353     List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
354     // Matching metadata
355     mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(label)}));
356     flowEntity = MDSALUtil.buildFlowEntity(dpId,
357                                            NwConstants.INTERNAL_TUNNEL_TABLE,
358                                            getFlowRef(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, (int)label),
359                                            5, String.format("%s:%d","TST Flow Entry ",label), 0, 0,
360                                            COOKIE_TUNNEL.add(BigInteger.valueOf(label)), mkMatches, null);
361     mdsalManager.removeFlow(flowEntity);
362     LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpId, label);
363   }
364
365   public BigInteger deleteLocalFibEntry(Long vpnId, String rd, VrfEntry vrfEntry) {
366     BigInteger localDpnId = BigInteger.ZERO;
367     boolean isExtraRoute = false;
368     VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
369     String localNextHopIP = vrfEntry.getDestPrefix();
370
371     if(localNextHopInfo == null) {
372         //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
373         Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
374         if (extra_route != null) {
375             localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp() + "/32");
376             localNextHopIP = extra_route.getNexthopIp() + "/32";
377             isExtraRoute = true;
378         }
379     }
380
381
382     if(localNextHopInfo != null) {
383       localDpnId = localNextHopInfo.getDpnId();
384       Prefixes prefix = getPrefixToInterface(vpnId, isExtraRoute ? localNextHopIP : vrfEntry.getDestPrefix());
385         makeConnectedRoute(localDpnId, vpnId, vrfEntry, rd, null /* invalid */,
386                            NwConstants.DEL_FLOW);
387         makeLFibTableEntry(localDpnId, vrfEntry.getLabel(), null /* invalid */,
388                            vrfEntry.getNextHopAddress(), NwConstants.DEL_FLOW);
389         removeTunnelTableEntry(localDpnId, vrfEntry.getLabel());
390         deleteLocalAdjacency(localDpnId, vpnId, localNextHopIP);
391     }
392     return localDpnId;
393   }
394
395   private InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(Long vpnId, String ipPrefix) {
396     return InstanceIdentifier.builder(PrefixToInterface.class)
397         .child(VpnIds.class, new VpnIdsKey(vpnId)).child(Prefixes.class, new PrefixesKey(ipPrefix)).build();
398   }
399
400   private Prefixes getPrefixToInterface(Long vpnId, String ipPrefix) {
401     Optional<Prefixes> localNextHopInfoData =
402         FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getPrefixToInterfaceIdentifier(vpnId, ipPrefix));
403     return  localNextHopInfoData.isPresent() ? localNextHopInfoData.get() : null;
404   }
405
406     private InstanceIdentifier<Extraroute> getVpnToExtrarouteIdentifier(String vrfId, String ipPrefix) {
407         return InstanceIdentifier.builder(VpnToExtraroute.class)
408                 .child(Vpn.class, new VpnKey(vrfId)).child(Extraroute.class,
409                         new ExtrarouteKey(ipPrefix)).build();
410     }
411
412     private Extraroute getVpnToExtraroute(String rd, String ipPrefix) {
413         Optional<Extraroute> extraRouteInfo =
414                 FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, getVpnToExtrarouteIdentifier(rd, ipPrefix));
415         return  extraRouteInfo.isPresent() ? extraRouteInfo.get() : null;
416
417     }
418
419   private Class<? extends TunnelTypeBase> getTunnelType(String ifName) {
420         try {
421             Future<RpcResult<GetTunnelTypeOutput>> result = interfaceManager.getTunnelType(
422                           new GetTunnelTypeInputBuilder().setIntfName(ifName).build());
423           RpcResult<GetTunnelTypeOutput> rpcResult = result.get();
424           if(!rpcResult.isSuccessful()) {
425               LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
426           } else {
427               return rpcResult.getResult().getTunnelType();
428           }
429           
430       } catch (InterruptedException | ExecutionException e) {
431           LOG.warn("Exception when getting tunnel interface Id for tunnel type {}", e);
432       }
433   
434   return null;
435
436   }
437   private void createRemoteFibEntry(final BigInteger localDpnId, final BigInteger remoteDpnId,
438                                     final long vpnId, final VrfTablesKey vrfTableKey,
439                                     final VrfEntry vrfEntry) {
440     String rd = vrfTableKey.getRouteDistinguisher();
441     LOG.debug("adding route " + vrfEntry.getDestPrefix() + " " + rd);
442     /********************************************/
443     String tunnelInterface = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry, rd);
444     if(tunnelInterface == null) {
445       LOG.error("Could not get interface for nexthop: {} in vpn {}",
446                                    vrfEntry.getNextHopAddress(), rd);
447       LOG.warn("Failed to add Route: {} in vpn: {}",
448                              vrfEntry.getDestPrefix(), rd);
449       return;
450     }
451       List<ActionInfo> actionInfos = new ArrayList<>();
452         Class<? extends TunnelTypeBase> tunnel_type = getTunnelType(tunnelInterface);
453     if (tunnel_type.equals(TunnelTypeMplsOverGre.class)) {
454         LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
455         actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
456         actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
457     } else {
458         int label = vrfEntry.getLabel().intValue();
459         BigInteger tunnelId;
460         // FIXME vxlan vni bit set is not working properly with OVS.need to revisit
461         if(tunnel_type.equals(TunnelTypeVxlan.class)) {
462                 tunnelId = BigInteger.valueOf(label);
463         } else {
464                 tunnelId = BigInteger.valueOf(label);
465         }
466         LOG.debug("adding set tunnel id action for label {}", label);
467         actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[]{
468                 tunnelId}));
469     }
470     actionInfos.addAll(nextHopManager.getEgressActionsForInterface(tunnelInterface));
471     List<InstructionInfo> instructions= new ArrayList<InstructionInfo>();
472     instructions.add(new InstructionInfo(InstructionType.write_actions, actionInfos));
473 /*
474     List<ActionInfo> actionInfos = resolveAdjacency(localDpnId, remoteDpnId, vpnId, vrfEntry);
475     if(actionInfos == null) {
476       LOG.error("Could not get nexthop group id for nexthop: {} in vpn {}",
477                                    vrfEntry.getNextHopAddress(), rd);
478       LOG.warn("Failed to add Route: {} in vpn: {}",
479                              vrfEntry.getDestPrefix(), rd);
480       return;
481     }
482     BigInteger dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getDestPrefix());
483     if(dpnId == null) {
484         //This route may be extra route... try to query with nexthop Ip
485         LOG.debug("Checking for extra route to install remote fib entry {}", vrfEntry.getDestPrefix());
486         dpnId = nextHopManager.getDpnForPrefix(vpnId, vrfEntry.getNextHopAddress() + "/32");
487     }
488     if(dpnId == null) {
489         LOG.debug("Push label action for prefix {}", vrfEntry.getDestPrefix());
490         actionInfos.add(new ActionInfo(ActionType.push_mpls, new String[] { null }));
491         actionInfos.add(new ActionInfo(ActionType.set_field_mpls_label, new String[] { Long.toString(vrfEntry.getLabel())}));
492     } else {
493         int label = vrfEntry.getLabel().intValue();
494         LOG.debug("adding set tunnel id action for label {}", label);
495         actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
496                 MetaDataUtil.getTunnelIdWithValidVniBitAndVniSet(label),
497                 MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
498     }
499 **/
500       makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW);
501       LOG.debug("Successfully added fib entry for " + vrfEntry.getDestPrefix() + " vpnId " + vpnId);
502   }
503
504   private void delIntfFromDpnToVpnList(long vpnId, BigInteger dpnId, String intfName, String rd) {
505       InstanceIdentifier<VpnToDpnList> id = FibUtil.getVpnToDpnListIdentifier(rd, dpnId);
506       Optional<VpnToDpnList> dpnInVpn = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
507       if (dpnInVpn.isPresent()) {
508           List<org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
509                   .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
510           org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces
511                   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();
512
513           if (vpnInterfaces.remove(currVpnInterface)) {
514               if (vpnInterfaces.isEmpty()) {
515                   LOG.trace("Last vpn interface {} on dpn {} for vpn {}. Clean up fib in dpn", intfName, dpnId, rd);
516                   FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id);
517                   cleanUpDpnForVpn(dpnId, vpnId, rd);
518               } else {
519                   LOG.trace("Delete vpn interface {} from dpn {} to vpn {} list.", intfName, dpnId, rd);
520                   FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, id.child(
521                           org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.vpn.instance.op.data
522                                   .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces.class,
523                           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)));
524               }
525           }
526       }
527   }
528
529   private void cleanUpOpDataForFib(Long vpnId, String rd, final VrfEntry vrfEntry) {
530     /* Get interface info from prefix to interface mapping;
531         Use the interface info to get the corresponding vpn interface op DS entry,
532         remove the adjacency corresponding to this fib entry.
533         If adjacency removed is the last adjacency, clean up the following:
534          - vpn interface from dpntovpn list, dpn if last vpn interface on dpn
535          - prefix to interface entry
536          - vpn interface op DS
537      */
538       Prefixes prefixInfo = getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
539       Extraroute extraRoute = null;
540       if (prefixInfo == null) {
541           extraRoute = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
542           if(extraRoute != null) {
543               prefixInfo = getPrefixToInterface(vpnId, extraRoute.getNexthopIp() + "/32");
544               //clean up the vpn to extra route entry in DS
545               FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getVpnToExtrarouteIdentifier(rd, vrfEntry.getDestPrefix()));
546           }
547       }
548       if (prefixInfo == null) {
549           LOG.debug("Cleanup VPN Data Failed as unable to find prefix Info for " + vrfEntry.getDestPrefix());
550           return; //Don't have any info for this prefix (shouldn't happen); need to return
551       }
552       String ifName = prefixInfo.getVpnInterfaceName();
553       Optional<Adjacencies> optAdjacencies = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, FibUtil.getAdjListPath(ifName));
554       int numAdj = 0;
555       if (optAdjacencies.isPresent()) {
556           numAdj = optAdjacencies.get().getAdjacency().size();
557       }
558       LOG.trace("cleanUpOpDataForFib: remove adjacency for prefix: {} {}", vpnId, vrfEntry.getDestPrefix());
559       //remove adjacency corr to prefix
560       if (numAdj > 1) {
561         FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
562                          FibUtil.getAdjacencyIdentifier(ifName, vrfEntry.getDestPrefix()));
563       }
564
565       if ((numAdj - 1) == 0) { //there are no adjacencies left for this vpn interface, clean up
566           //clean up the vpn interface from DpnToVpn list
567           LOG.trace("Clean up vpn interface {} from dpn {} to vpn {} list.", ifName, prefixInfo.getDpnId(), rd);
568           FibUtil.delete(broker, LogicalDatastoreType.OPERATIONAL,
569                          FibUtil.getVpnInterfaceIdentifier(ifName));
570        }
571   }
572
573   private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier,
574                                 final VrfEntry vrfEntry) {
575     final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class, VrfTablesKey.class);
576     Preconditions.checkNotNull(vrfTableKey, "VrfTablesKey cannot be null or empty!");
577     Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
578
579     VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
580     Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available!");
581     Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
582     RdToElanOpEntry rdToElanOpEntry= getRdToElanOpEntry(broker,vrfTableKey.getRouteDistinguisher(),
583             vrfEntry.getDestPrefix());
584     if (rdToElanOpEntry != null) {
585         if (vpnToDpnList!=null) {
586             for(VpnToDpnList curDpn :  vpnToDpnList) {
587                 makeConnectedRoute(curDpn.getDpnId(),vpnInstance.getVpnId(),vrfEntry,vrfTableKey
588                         .getRouteDistinguisher(), null,NwConstants.DEL_FLOW);
589                 makeLFibTableEntry(curDpn.getDpnId(),vrfEntry.getLabel(),null,
590                         vrfEntry.getNextHopAddress(),NwConstants.DEL_FLOW);
591                 // TODO DeleteTunnelTableEntry();
592             }
593         }
594         //Delete rd-to-elan-op-entry
595         InstanceIdentifier<RdToElanOpEntry> id = getRdToElanOpEntryDataPath(vrfTableKey.getRouteDistinguisher(),
596                 vrfEntry.getDestPrefix());
597         MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL,id);
598         return;
599     }
600     BigInteger localDpnId = deleteLocalFibEntry(vpnInstance.getVpnId(),
601               vrfTableKey.getRouteDistinguisher(), vrfEntry);
602     if (vpnToDpnList != null) {
603       for (VpnToDpnList curDpn : vpnToDpnList) {
604         if (!curDpn.getDpnId().equals(localDpnId)) {
605           deleteRemoteRoute(localDpnId, curDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry);
606         }
607       }
608     }
609     //The flow/group entry has been deleted from config DS; need to clean up associated operational
610     //DS entries in VPN Op DS, VpnInstanceOpData and PrefixToInterface to complete deletion
611     cleanUpOpDataForFib(vpnInstance.getVpnId(), vrfTableKey.getRouteDistinguisher(), vrfEntry);
612   }
613
614   public void deleteRemoteRoute(final BigInteger localDpnId, final BigInteger remoteDpnId,
615                                 final long vpnId, final VrfTablesKey vrfTableKey,
616                                 final VrfEntry vrfEntry) {
617     LOG.debug("deleting route "+ vrfEntry.getDestPrefix() + " "+vpnId);
618     String rd = vrfTableKey.getRouteDistinguisher();
619     boolean isRemoteRoute = true;
620     if (localDpnId == null) {
621       // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
622       VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
623       if(localNextHopInfo == null) {
624         //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
625         Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
626         if (extra_route != null) {
627           localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, extra_route.getNexthopIp());
628         }
629       }
630       if (localNextHopInfo != null) {
631         isRemoteRoute = (!remoteDpnId.equals(localNextHopInfo.getDpnId()));
632       }
633     }
634     if (isRemoteRoute) {
635       makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW);
636       LOG.debug("Successfully delete fib entry for "+ vrfEntry.getDestPrefix() + " vpnId "+vpnId);
637     } else{
638       LOG.debug("Did not delete fib entry rd: {} =, prefix: {} as it is local to dpn {}", rd, vrfEntry.getDestPrefix(), remoteDpnId);
639     }
640   }
641
642   private long getIpAddress(byte[] rawIpAddress) {
643     return (((rawIpAddress[0] & 0xFF) << (3 * 8)) + ((rawIpAddress[1] & 0xFF) << (2 * 8))
644             + ((rawIpAddress[2] & 0xFF) << (1 * 8)) + (rawIpAddress[3] & 0xFF)) & 0xffffffffL;
645   }
646
647   private void makeConnectedRoute(BigInteger dpId, long vpnId, VrfEntry vrfEntry, String rd,
648                                   List<InstructionInfo> instructions, int addOrRemove) {    LOG.trace("makeConnectedRoute: vrfEntry {}",vrfEntry);
649     String values[] = vrfEntry.getDestPrefix().split("/");
650     String ipAddress = values[0];
651     int prefixLength = (values.length == 1) ? 0 : Integer.parseInt(values[1]);
652     LOG.debug("Adding route to DPN. ip {} masklen {}", ipAddress, prefixLength);
653     InetAddress destPrefix = null;
654     try {
655       destPrefix = InetAddress.getByName(ipAddress);
656     } catch (UnknownHostException e) {
657       LOG.error("UnknowHostException in addRoute. Failed  to add Route for ipPrefix {}", vrfEntry.getDestPrefix());
658       return;
659     }
660
661     List<MatchInfo> matches = new ArrayList<MatchInfo>();
662
663     matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
664         BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
665
666     matches.add(new MatchInfo(MatchFieldType.eth_type,
667                               new long[] { 0x0800L }));
668
669     if(prefixLength != 0) {
670         matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
671                 destPrefix.getHostAddress(), Integer.toString(prefixLength)}));
672     }
673
674     String flowRef = getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, destPrefix);
675
676     FlowEntity flowEntity;
677
678     int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
679     flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef,
680                                            priority, flowRef, 0, 0,
681                                            COOKIE_VM_FIB_TABLE, matches, instructions);
682
683     if (addOrRemove == NwConstants.ADD_FLOW) {
684       /* We need to call sync API to install flow so that 2 DS operations on the same object do not
685       * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
686       * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
687       * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
688       * wait indefinitely. */
689       mdsalManager.syncInstallFlow(flowEntity, 1);
690     } else {
691       mdsalManager.syncRemoveFlow(flowEntity, 1);
692     }
693   }
694
695   private void makeLFibTableEntry(BigInteger dpId, long label, List<InstructionInfo> instructions,
696                                   String nextHop, int addOrRemove) {
697     List<MatchInfo> matches = new ArrayList<MatchInfo>();
698     matches.add(new MatchInfo(MatchFieldType.eth_type,
699                               new long[] { 0x8847L }));
700     matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(label)}));
701
702     // Install the flow entry in L3_LFIB_TABLE
703     String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, label, nextHop);
704
705     FlowEntity flowEntity;
706     flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_LFIB_TABLE, flowRef,
707                                            DEFAULT_FIB_FLOW_PRIORITY, flowRef, 0, 0,
708                                            COOKIE_VM_LFIB_TABLE, matches, instructions);
709
710     if (addOrRemove == NwConstants.ADD_FLOW) {
711       /* We need to call sync API to install flow so that 2 DS operations on the same object do not
712       * happen at same time. However, MDSALManager's syncInstallFlow takes a delay time (or uses a default one) to wait
713       * for or for notification that operational DS write for flows is done. We do not turn on the stats writing for flows,
714       * so that notification never comes, so we do not need that wait. Sending the lowest value of wait "1 ms" since 0 wait means
715       * wait indefinitely. */
716
717       mdsalManager.syncInstallFlow(flowEntity, 1);
718     } else {
719       mdsalManager.syncRemoveFlow(flowEntity, 1);
720     }
721       LOG.debug("LFIB Entry for dpID {} : label : {} instructions {} modified successfully {}",dpId, label, instructions );
722   }
723
724   private void deleteLocalAdjacency(final BigInteger dpId, final long vpnId, final String ipAddress) {
725     LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, ipAddress {}",dpId, vpnId, ipAddress);
726     try {
727       nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress);
728     } catch (NullPointerException e) {
729       LOG.trace("", e);
730     }
731   }
732
733   public void populateFibOnNewDpn(BigInteger dpnId, long vpnId, String rd) {
734     LOG.trace("New dpn {} for vpn {} : populateFibOnNewDpn", dpnId, rd);
735     InstanceIdentifier<VrfTables> id = buildVrfId(rd);
736     String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
737     synchronized (lockOnDpnVpn.intern()) {
738       Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
739       if (vrfTable.isPresent()) {
740         for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
741             RdToElanOpEntry rdToElanOpEntry = getRdToElanOpEntry(broker, rd,
742                     vrfEntry.getDestPrefix());
743             if (rdToElanOpEntry!= null) {
744                 installSubnetRouteInFib(dpnId, rdToElanOpEntry, vpnId, vrfEntry);
745                 continue;
746             }
747           // Passing null as we don't know the dpn
748           // to which prefix is attached at this point
749           createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
750         }
751       }
752     }
753   }
754
755   public void populateFibOnDpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
756     LOG.trace("dpn {} for vpn {}, nexthopIp {} : populateFibOnDpn", dpnId, rd, nexthopIp);
757     InstanceIdentifier<VrfTables> id = buildVrfId(rd);
758     String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
759     synchronized (lockOnDpnVpn.intern()) {
760       Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
761       if (vrfTable.isPresent()) {
762         for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
763           // Passing null as we don't know the dpn
764           // to which prefix is attached at this point
765           if (nexthopIp == vrfEntry.getNextHopAddress()) {
766             createRemoteFibEntry(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
767           }
768         }
769       }
770     }
771   }
772
773   public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd) {
774     LOG.trace("Remove dpn {} for vpn {} : cleanUpDpnForVpn", dpnId, rd);
775     InstanceIdentifier<VrfTables> id = buildVrfId(rd);
776     String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
777     synchronized (lockOnDpnVpn.intern()) {
778       Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
779       if (vrfTable.isPresent()) {
780         for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
781           // Passing null as we don't know the dpn
782           // to which prefix is attached at this point
783           deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
784         }
785       }
786     }
787   }
788
789   public void cleanUpDpnForVpn(BigInteger dpnId, long vpnId, String rd, String nexthopIp) {
790     LOG.trace("dpn {} for vpn {}, nexthopIp {} : cleanUpDpnForVpn", dpnId, rd, nexthopIp);
791     InstanceIdentifier<VrfTables> id = buildVrfId(rd);
792     String lockOnDpnVpn = new String(dpnId.toString()+ vpnId);
793     synchronized (lockOnDpnVpn.intern()) {
794       Optional<VrfTables> vrfTable = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
795       if (vrfTable.isPresent()) {
796         for (VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) {
797           // Passing null as we don't know the dpn
798           // to which prefix is attached at this point
799           if (nexthopIp == vrfEntry.getNextHopAddress()) {
800             deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().getKey(), vrfEntry);
801           }
802         }
803       }
804     }
805   }
806
807   public static InstanceIdentifier<VrfTables> buildVrfId(String rd) {
808     InstanceIdentifierBuilder<VrfTables> idBuilder =
809         InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(rd));
810     InstanceIdentifier<VrfTables> id = idBuilder.build();
811     return id;
812   }
813
814   private String getFlowRef(BigInteger dpnId, short tableId, long label, String nextHop) {
815     return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
816         .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
817         .append(label).append(NwConstants.FLOWID_SEPARATOR)
818         .append(nextHop).toString();
819   }
820
821   private String getFlowRef(BigInteger dpnId, short tableId, String rd, InetAddress destPrefix) {
822     return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
823         .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
824         .append(rd).append(NwConstants.FLOWID_SEPARATOR)
825         .append(destPrefix.getHostAddress()).toString();
826   }
827
828   protected String resolveAdjacency(final BigInteger localDpnId, final BigInteger remoteDpnId,
829                                               final long vpnId, final VrfEntry vrfEntry, String rd) {
830     String adjacency = null;
831     boolean staticRoute = false;
832     LOG.trace("resolveAdjacency called with localdpid{} remotedpid {}, vpnId{}, VrfEntry {}", localDpnId, remoteDpnId, vpnId, vrfEntry);
833     try {
834         Extraroute extra_route = getVpnToExtraroute(rd, vrfEntry.getDestPrefix());
835         if(extra_route != null) {
836             staticRoute = true;
837         }
838
839         adjacency =
840           nextHopManager.getRemoteNextHopPointer(localDpnId, remoteDpnId, vpnId,
841                   (staticRoute == true) ? extra_route.getNexthopIp() + "/32" : vrfEntry.getDestPrefix(),
842                                                 vrfEntry.getNextHopAddress());
843     } catch (NullPointerException e) {
844       LOG.trace("", e);
845     }
846     return adjacency;
847   }
848
849   protected VpnInstanceOpDataEntry getVpnInstance(String rd) {
850     InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.create(VpnInstanceOpData.class).child(
851         VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd));
852     Optional<VpnInstanceOpDataEntry> vpnInstanceOpData = FibUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
853     if(vpnInstanceOpData.isPresent()) {
854       return vpnInstanceOpData.get();
855     }
856     return null;
857   }
858
859     public void processNodeAdd(BigInteger dpnId) {
860         LOG.debug("Received notification to install TableMiss entries for dpn {} ", dpnId);
861         makeTableMissFlow(dpnId, NwConstants.ADD_FLOW);
862         makeL3IntfTblMissFlow(dpnId, NwConstants.ADD_FLOW);
863     }
864
865     private void makeTableMissFlow(BigInteger dpnId, int addOrRemove) {
866         final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
867         // Instruction to goto L3 InterfaceTable
868         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
869         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.L3_INTERFACE_TABLE }));
870         List<MatchInfo> matches = new ArrayList<MatchInfo>();
871         FlowEntity flowEntityLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_LFIB_TABLE,
872                 getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, NwConstants.TABLE_MISS_FLOW),
873                 NwConstants.TABLE_MISS_PRIORITY, "Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
874
875         FlowEntity flowEntityFib = MDSALUtil.buildFlowEntity(dpnId,NwConstants.L3_FIB_TABLE, getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, NwConstants.TABLE_MISS_FLOW),
876                 NwConstants.TABLE_MISS_PRIORITY, "FIB Table Miss Flow", 0, 0, COOKIE_VM_FIB_TABLE,
877                 matches, instructions);
878
879         if (addOrRemove == NwConstants.ADD_FLOW) {
880             LOG.debug("Invoking MDSAL to install Table Miss Entries");
881             mdsalManager.installFlow(flowEntityLfib);
882             mdsalManager.installFlow(flowEntityFib);
883         } else {
884             mdsalManager.removeFlow(flowEntityLfib);
885             mdsalManager.removeFlow(flowEntityFib);
886
887         }
888     }
889
890     private String getFlowRef(BigInteger dpnId, short tableId, int tableMiss) {
891         return new StringBuffer().append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
892                 .append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(tableMiss)
893                 .append(FLOWID_PREFIX).toString();
894     }
895
896   /*
897    * Install flow entry in protocol table to forward mpls
898    * coming through gre tunnel to LFIB table.
899    */
900   private void makeProtocolTableFlow(BigInteger dpnId, int addOrRemove) {
901     final BigInteger COOKIE_PROTOCOL_TABLE = new BigInteger("1070000", 16);
902     // Instruction to goto L3 InterfaceTable
903     List<InstructionInfo> instructions = new ArrayList<>();
904     instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] {NwConstants.L3_LFIB_TABLE}));
905     List<MatchInfo> matches = new ArrayList<MatchInfo>();
906     matches.add(new MatchInfo(MatchFieldType.eth_type,
907                               new long[] { 0x8847L }));
908     FlowEntity flowEntityToLfib = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_PROTOCOL_TABLE,
909                                                           getFlowRef(dpnId, NwConstants.L3_PROTOCOL_TABLE,
910                                                                   NwConstants.L3_LFIB_TABLE),
911                                                           DEFAULT_FIB_FLOW_PRIORITY,
912                                                           "Protocol Table For LFIB",
913                                                           0, 0,
914                                                           COOKIE_PROTOCOL_TABLE,
915                                                           matches, instructions);
916
917     if (addOrRemove == NwConstants.ADD_FLOW) {
918       LOG.debug("Invoking MDSAL to install Protocol Entries for dpn {}", dpnId);
919       mdsalManager.installFlow(flowEntityToLfib);
920     } else {
921       mdsalManager.removeFlow(flowEntityToLfib);
922     }
923   }
924
925   public List<String> printFibEntries() {
926     List<String> result = new ArrayList<String>();
927     result.add(String.format("   %-7s  %-20s  %-20s  %-7s", "RD", "Prefix", "Nexthop", "Label"));
928     result.add("-------------------------------------------------------------------");
929     InstanceIdentifier<FibEntries> id = InstanceIdentifier.create(FibEntries.class);
930     Optional<FibEntries> fibEntries = FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, id);
931     if (fibEntries.isPresent()) {
932       List<VrfTables> vrfTables = fibEntries.get().getVrfTables();
933       for (VrfTables vrfTable : vrfTables) {
934         for (VrfEntry vrfEntry : vrfTable.getVrfEntry()) {
935           result.add(String.format("   %-7s  %-20s  %-20s  %-7s", vrfTable.getRouteDistinguisher(),
936                   vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddress(), vrfEntry.getLabel()));
937         }
938       }
939     }
940     return result;
941   }
942
943   private void makeL3IntfTblMissFlow(BigInteger dpnId, int addOrRemove) {
944     List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
945     List<MatchInfo> matches = new ArrayList<MatchInfo>();
946     final BigInteger COOKIE_TABLE_MISS = new BigInteger("1030000", 16);
947     // Instruction to clear metadata except SI and LportTag bits
948     instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] {
949                     CLEAR_METADATA, METADATA_MASK_CLEAR }));
950     // Instruction to clear action
951     instructions.add(new InstructionInfo(InstructionType.clear_actions));
952     // Instruction to goto L3 InterfaceTable
953
954     List <ActionInfo> actionsInfos = new ArrayList <ActionInfo> ();
955     actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[]{
956         Short.toString(NwConstants.LPORT_DISPATCHER_TABLE)}));
957     instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
958     //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.LPORT_DISPATCHER_TABLE }));
959
960     FlowEntity flowEntityL3Intf = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_INTERFACE_TABLE,
961             getFlowRef(dpnId, NwConstants.L3_INTERFACE_TABLE, NwConstants.TABLE_MISS_FLOW),
962             NwConstants.TABLE_MISS_PRIORITY, "L3 Interface Table Miss", 0, 0, COOKIE_TABLE_MISS, matches, instructions);
963     if (addOrRemove == NwConstants.ADD_FLOW) {
964       LOG.info("Invoking MDSAL to install L3 interface Table Miss Entries");
965       mdsalManager.installFlow(flowEntityL3Intf);
966     } else {
967       mdsalManager.removeFlow(flowEntityL3Intf);
968     }
969   }
970
971 }