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