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