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