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