FibManager module sync up
[netvirt.git] / vpnservice / fibmanager / fibmanager-impl / src / main / java / org / opendaylight / netvirt / fibmanager / NexthopManager.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.util.concurrent.FutureCallback;
12 import com.google.common.util.concurrent.Futures;
13
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
16 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.genius.mdsalutil.ActionInfo;
19 import org.opendaylight.genius.mdsalutil.ActionType;
20 import org.opendaylight.genius.mdsalutil.BucketInfo;
21 import org.opendaylight.genius.mdsalutil.GroupEntity;
22 import org.opendaylight.genius.mdsalutil.MDSALUtil;
23 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
24 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
25 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
26 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCase;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCase;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameInputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetExternalTunnelInterfaceNameOutput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetInternalOrExternalInterfaceNameInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetInternalOrExternalInterfaceNameOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceInputBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetEgressActionsForInterfaceOutput;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.L3nexthop;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.VpnNexthops;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.VpnNexthopsKey;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthopBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthopKey;
61 import org.opendaylight.yangtools.yang.binding.DataObject;
62 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
63 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
64 import org.opendaylight.yangtools.yang.common.RpcResult;
65 import org.slf4j.Logger;
66 import org.slf4j.LoggerFactory;
67 import org.opendaylight.genius.itm.globals.ITMConstants;
68 import org.opendaylight.genius.mdsalutil.*;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.ConfTransportTypeL3vpn;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.ConfTransportTypeL3vpnBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.*;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
76
77 import java.math.BigInteger;
78 import java.util.ArrayList;
79 import java.util.List;
80 import java.util.concurrent.ExecutionException;
81 import java.util.concurrent.Future;
82
83 public class NexthopManager implements AutoCloseable {
84     private static final Logger LOG = LoggerFactory.getLogger(NexthopManager.class);
85     private final DataBroker broker;
86     private IMdsalApiManager mdsalManager;
87     private OdlInterfaceRpcService interfaceManager;
88     private ItmRpcService itmManager;
89     private IdManagerService idManager;
90     private static final short LPORT_INGRESS_TABLE = 0;
91     private static final short LFIB_TABLE = 20;
92     private static final short FIB_TABLE = 21;
93     private static final short DEFAULT_FLOW_PRIORITY = 10;
94     private static final String NEXTHOP_ID_POOL_NAME = "nextHopPointerPool";
95     private static final long FIXED_DELAY_IN_MILLISECONDS = 4000;
96     private L3VPNTransportTypes configuredTransportTypeL3VPN = L3VPNTransportTypes.Invalid;
97     private Long waitTimeForSyncInstall;
98
99     private static final FutureCallback<Void> DEFAULT_CALLBACK =
100             new FutureCallback<Void>() {
101                 @Override
102                 public void onSuccess(Void result) {
103                     LOG.debug("Success in Datastore write operation");
104                 }
105                 @Override
106                 public void onFailure(Throwable error) {
107                     LOG.error("Error in Datastore write operation", error);
108                 };
109             };
110
111     /**
112      * Provides nexthop functions
113      * Creates group ID pool
114      *
115      * @param db - dataBroker reference
116      */
117     public NexthopManager(final DataBroker db) {
118         broker = db;
119         waitTimeForSyncInstall = Long.getLong("wait.time.sync.install");
120         if (waitTimeForSyncInstall == null)
121             waitTimeForSyncInstall = 1000L;
122     }
123
124     @Override
125     public void close() throws Exception {
126         LOG.info("NextHop Manager Closed");
127     }
128
129     public void setInterfaceManager(OdlInterfaceRpcService ifManager) {
130         this.interfaceManager = ifManager;
131     }
132
133     public void setMdsalManager(IMdsalApiManager mdsalManager) {
134         this.mdsalManager = mdsalManager;
135     }
136
137     public void setIdManager(IdManagerService idManager) {
138         this.idManager = idManager;
139         createNexthopPointerPool();
140     }
141
142     public void setITMRpcService(ItmRpcService itmManager) {
143         this.itmManager = itmManager;
144     }
145
146     protected void createNexthopPointerPool() {
147         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
148                 .setPoolName(NEXTHOP_ID_POOL_NAME)
149                 .setLow(150000L)
150                 .setHigh(175000L)
151                 .build();
152         //TODO: Error handling
153         Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
154         LOG.trace("NextHopPointerPool result : {}", result);
155     }
156
157     private BigInteger getDpnId(String ofPortId) {
158         String[] fields = ofPortId.split(":");
159         BigInteger dpn = new BigInteger(fields[1]);
160         LOG.debug("DpnId: {}", dpn);
161         return dpn;
162     }
163
164     private String getNextHopKey(long vpnId, String ipAddress){
165         String nhKey = new String("nexthop." + vpnId + ipAddress);
166         return nhKey;
167     }
168
169     private String getNextHopKey(String ifName, String ipAddress){
170         String nhKey = new String("nexthop." + ifName + ipAddress);
171         return nhKey;
172     }
173
174     protected long createNextHopPointer(String nexthopKey) {
175         AllocateIdInput getIdInput = new AllocateIdInputBuilder()
176                 .setPoolName(NEXTHOP_ID_POOL_NAME).setIdKey(nexthopKey)
177                 .build();
178         //TODO: Proper error handling once IdManager code is complete
179         try {
180             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
181             RpcResult<AllocateIdOutput> rpcResult = result.get();
182             return rpcResult.getResult().getIdValue();
183         } catch (NullPointerException | InterruptedException | ExecutionException e) {
184             LOG.trace("",e);
185         }
186         return 0;
187     }
188
189     protected void removeNextHopPointer(String nexthopKey) {
190         ReleaseIdInput idInput = new ReleaseIdInputBuilder().
191                 setPoolName(NEXTHOP_ID_POOL_NAME)
192                 .setIdKey(nexthopKey).build();
193         try {
194             Future<RpcResult<Void>> result = idManager.releaseId(idInput);
195             RpcResult<Void> rpcResult = result.get();
196             if(!rpcResult.isSuccessful()) {
197                 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
198             }
199         } catch (InterruptedException | ExecutionException e) {
200             LOG.warn("Exception when getting Unique Id for key {}", nexthopKey, e);
201         }
202     }
203
204     protected List<ActionInfo> getEgressActionsForInterface(String ifName) {
205         List<ActionInfo> listActionInfo = new ArrayList<ActionInfo>();
206         try {
207             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
208                     interfaceManager.getEgressActionsForInterface(
209                             new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).build());
210             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
211             if(!rpcResult.isSuccessful()) {
212                 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, rpcResult.getErrors());
213             } else {
214                 List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actions =
215                         rpcResult.getResult().getAction();
216                 for (Action action : actions) {
217                     org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = action.getAction();
218                     if (actionClass instanceof OutputActionCase) {
219                         listActionInfo.add(new ActionInfo(ActionType.output,
220                                 new String[] {((OutputActionCase)actionClass).getOutputAction()
221                                         .getOutputNodeConnector().getValue()}));
222                     } else if (actionClass instanceof PushVlanActionCase) {
223                         listActionInfo.add(new ActionInfo(ActionType.push_vlan, new String[] {}));
224                     } else if (actionClass instanceof SetFieldCase) {
225                         if (((SetFieldCase)actionClass).getSetField().getVlanMatch() != null) {
226                             int vlanVid = ((SetFieldCase)actionClass).getSetField().getVlanMatch().getVlanId().getVlanId().getValue();
227                             listActionInfo.add(new ActionInfo(ActionType.set_field_vlan_vid,
228                                     new String[] { Long.toString(vlanVid) }));
229                         }
230                     }
231                 }
232             }
233         } catch (InterruptedException | ExecutionException e) {
234             LOG.warn("Exception when egress actions for interface {}", ifName, e);
235         }
236         return listActionInfo;
237     }
238
239     protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
240         Class<? extends TunnelTypeBase> tunType = getReqTunType(getReqTransType().toUpperCase());
241         Future<RpcResult<GetTunnelInterfaceNameOutput>> result;
242         try {
243             result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
244                     .setSourceDpid(srcDpId)
245                     .setDestinationDpid(dstDpId)
246                     .setTunnelType(tunType)
247                     .build());
248             RpcResult<GetTunnelInterfaceNameOutput> rpcResult = result.get();
249             if(!rpcResult.isSuccessful()) {
250                 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
251             } else {
252                 return rpcResult.getResult().getInterfaceName();
253             }
254         } catch (InterruptedException | ExecutionException e) {
255             LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and  {}", srcDpId, dstDpId, e);
256         }
257         return null;
258     }
259
260
261
262     protected String getTunnelInterfaceName(BigInteger srcDpId, org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress dstIp) {
263         Class<? extends TunnelTypeBase> tunType = getReqTunType(getReqTransType().toUpperCase());
264         Future<RpcResult<GetInternalOrExternalInterfaceNameOutput>> result;
265         try {
266             result = itmManager.getInternalOrExternalInterfaceName(new GetInternalOrExternalInterfaceNameInputBuilder()
267                     .setSourceDpid(srcDpId)
268                     .setDestinationIp(dstIp)
269                     .setTunnelType(tunType)
270                     .build());
271             RpcResult<GetInternalOrExternalInterfaceNameOutput> rpcResult = result.get();
272             if(!rpcResult.isSuccessful()) {
273                 LOG.warn("RPC Call to getTunnelInterfaceName returned with Errors {}", rpcResult.getErrors());
274             } else {
275                 return rpcResult.getResult().getInterfaceName();
276             }
277         } catch (InterruptedException | ExecutionException e) {
278             LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and  {}", srcDpId, dstIp, e);
279         }
280         return null;
281     }
282
283     public long createLocalNextHop(long vpnId, BigInteger dpnId,
284                                    String ifName, String ipAddress) {
285         long groupId = createNextHopPointer(getNextHopKey(vpnId, ipAddress));
286         String nextHopLockStr = new String(vpnId + ipAddress);
287         synchronized (nextHopLockStr.intern()) {
288             VpnNexthop nexthop = getVpnNexthop(vpnId, ipAddress);
289             LOG.trace("nexthop: {} retrieved for vpnId {}, prefix {}, ifName {} on dpn {}", nexthop,
290                     vpnId, ipAddress, ifName, dpnId);
291             if (nexthop == null) {
292                 Optional<Adjacency> adjacencyData =
293                         read(LogicalDatastoreType.OPERATIONAL, getAdjacencyIdentifier(ifName, ipAddress));
294                 String macAddress = adjacencyData.isPresent() ? adjacencyData.get().getMacAddress() : null;
295                 List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
296                 List<ActionInfo> listActionInfo = getEgressActionsForInterface(ifName);
297                 BucketInfo bucket = new BucketInfo(listActionInfo);
298                 // MAC re-write
299                 if (macAddress != null) {
300                     listActionInfo.add(0, new ActionInfo(ActionType.set_field_eth_dest, new String[]{macAddress}));
301                     //listActionInfo.add(0, new ActionInfo(ActionType.pop_mpls, new String[]{}));
302                 } else {
303                     //FIXME: Log message here.
304                     LOG.debug("mac address for new local nexthop is null");
305                 }
306                 listBucketInfo.add(bucket);
307                 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
308                         dpnId, groupId, ipAddress, GroupTypes.GroupAll, listBucketInfo);
309                 LOG.trace("Install LNH Group: id {}, mac address {}, interface {} for prefix {}", groupId, macAddress, ifName, ipAddress);
310
311                 // install Group
312                 mdsalManager.syncInstallGroup(groupEntity, FIXED_DELAY_IN_MILLISECONDS);
313                 try{
314                     LOG.info("Sleeping for {} to wait for the groups to get programmed.", waitTimeForSyncInstall);
315                     Thread.sleep(waitTimeForSyncInstall);
316                 }catch(InterruptedException error){
317                     LOG.warn("Error while waiting for group {} to install.", groupId);
318                     LOG.debug("{}", error);
319                 }
320                 //update MD-SAL DS
321                 addVpnNexthopToDS(dpnId, vpnId, ipAddress, groupId);
322
323             } else {
324                 //nexthop exists already; a new flow is going to point to it, increment the flowrefCount by 1
325                 int flowrefCnt = nexthop.getFlowrefCount() + 1;
326                 VpnNexthop nh = new VpnNexthopBuilder().setKey(new VpnNexthopKey(ipAddress)).setFlowrefCount(flowrefCnt).build();
327                 LOG.trace("Updating vpnnextHop {} for refCount {} to Operational DS", nh, flowrefCnt);
328                 syncWrite(LogicalDatastoreType.OPERATIONAL, getVpnNextHopIdentifier(vpnId, ipAddress), nh, DEFAULT_CALLBACK);
329
330             }
331         }
332         return groupId;
333     }
334
335
336     protected void addVpnNexthopToDS(BigInteger dpnId, long vpnId, String ipPrefix, long egressPointer) {
337
338         InstanceIdentifierBuilder<VpnNexthops> idBuilder = InstanceIdentifier.builder(
339                 L3nexthop.class)
340                 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId));
341
342         // Add nexthop to vpn node
343         VpnNexthop nh = new VpnNexthopBuilder().
344                 setKey(new VpnNexthopKey(ipPrefix)).
345                 setDpnId(dpnId).
346                 setIpAddress(ipPrefix).
347                 setFlowrefCount(1).
348                 setEgressPointer(egressPointer).build();
349
350         InstanceIdentifier<VpnNexthop> id1 = idBuilder
351                 .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix)).build();
352         LOG.trace("Adding vpnnextHop {} to Operational DS", nh);
353         syncWrite(LogicalDatastoreType.OPERATIONAL, id1, nh, DEFAULT_CALLBACK);
354
355     }
356
357
358
359     protected InstanceIdentifier<VpnNexthop> getVpnNextHopIdentifier(long vpnId, String ipAddress) {
360         InstanceIdentifier<VpnNexthop> id = InstanceIdentifier.builder(
361                 L3nexthop.class)
362                 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId)).child(VpnNexthop.class, new VpnNexthopKey(ipAddress)).build();
363         return id;
364     }
365
366     protected VpnNexthop getVpnNexthop(long vpnId, String ipAddress) {
367
368         // check if vpn node is there
369         InstanceIdentifierBuilder<VpnNexthops> idBuilder =
370                 InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class,
371                         new VpnNexthopsKey(vpnId));
372         InstanceIdentifier<VpnNexthops> id = idBuilder.build();
373         Optional<VpnNexthops> vpnNexthops = read(LogicalDatastoreType.OPERATIONAL, id);
374         if (vpnNexthops.isPresent()) {
375             // get nexthops list for vpn
376             List<VpnNexthop> nexthops = vpnNexthops.get().getVpnNexthop();
377             for (VpnNexthop nexthop : nexthops) {
378                 if (nexthop.getIpAddress().equals(ipAddress)) {
379                     // return nexthop
380                     LOG.trace("VpnNextHop : {}", nexthop);
381                     return nexthop;
382                 }
383             }
384             // return null if not found
385         }
386         return null;
387     }
388
389
390     public String getRemoteNextHopPointer(BigInteger remoteDpnId, long vpnId, String prefixIp, String nextHopIp) {
391         String tunnelIfName = null;
392         LOG.trace("getRemoteNextHopPointer: input [remoteDpnId {}, vpnId {}, prefixIp {}, nextHopIp {} ]",
393                 remoteDpnId, vpnId, prefixIp, nextHopIp);
394
395         if (nextHopIp != null && !nextHopIp.isEmpty()) {
396             try{
397                 // here use the config for tunnel type param
398                 tunnelIfName = getTunnelInterfaceName(remoteDpnId, org.opendaylight.yang.gen.v1.urn.ietf.params.xml
399                         .ns.yang.ietf.inet.types.rev130715.IpAddressBuilder.getDefaultInstance(nextHopIp));
400             } catch(Exception ex){
401                 LOG.error("Error while retrieving nexthop pointer for nexthop {} : ", nextHopIp, ex.getMessage());
402             }
403         }
404         return tunnelIfName;
405     }
406
407     public BigInteger getDpnForPrefix(long vpnId, String prefixIp) {
408         VpnNexthop vpnNexthop = getVpnNexthop(vpnId, prefixIp);
409         BigInteger localDpnId = (vpnNexthop == null) ? null : vpnNexthop.getDpnId();
410         return localDpnId;
411     }
412
413
414     private void removeVpnNexthopFromDS(long vpnId, String ipPrefix) {
415
416         InstanceIdentifierBuilder<VpnNexthop> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
417                 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId))
418                 .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix));
419         InstanceIdentifier<VpnNexthop> id = idBuilder.build();
420         // remove from DS
421         LOG.trace("Removing vpn next hop from datastore : {}", id);
422         delete(LogicalDatastoreType.OPERATIONAL, id);
423     }
424
425
426     public void removeLocalNextHop(BigInteger dpnId, Long vpnId, String ipAddress) {
427
428         String nextHopLockStr = new String(vpnId + ipAddress);
429         synchronized (nextHopLockStr.intern()) {
430             VpnNexthop nh = getVpnNexthop(vpnId, ipAddress);
431             if (nh != null) {
432                 int newFlowrefCnt = nh.getFlowrefCount() - 1;
433                 if (newFlowrefCnt == 0) { //remove the group only if there are no more flows using this group
434                     GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
435                             dpnId, nh.getEgressPointer(), ipAddress, GroupTypes.GroupAll, null);
436                     // remove Group ...
437                     mdsalManager.removeGroup(groupEntity);
438                     //update MD-SAL DS
439                     removeVpnNexthopFromDS(vpnId, ipAddress);
440                     //release groupId
441                     removeNextHopPointer(getNextHopKey(vpnId, ipAddress));
442                     LOG.debug("Local Next hop {} for {} {} on dpn {} successfully deleted", nh.getEgressPointer(), vpnId, ipAddress, dpnId);
443                 } else {
444                     //just update the flowrefCount of the vpnNexthop
445                     VpnNexthop currNh = new VpnNexthopBuilder().setKey(new VpnNexthopKey(ipAddress)).setFlowrefCount(newFlowrefCnt).build();
446                     LOG.trace("Updating vpnnextHop {} for refCount {} to Operational DS", currNh, newFlowrefCnt);
447                     syncWrite(LogicalDatastoreType.OPERATIONAL, getVpnNextHopIdentifier(vpnId, ipAddress), currNh, DEFAULT_CALLBACK);
448                 }
449             } else {
450                 //throw error
451                 LOG.error("Local Next hop for {} on dpn {} not deleted", ipAddress, dpnId);
452             }
453         }
454
455     }
456
457
458     private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
459                                                     InstanceIdentifier<T> path) {
460
461         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
462
463         Optional<T> result = Optional.absent();
464         try {
465             result = tx.read(datastoreType, path).get();
466         } catch (Exception e) {
467             throw new RuntimeException(e);
468         }
469
470         return result;
471     }
472
473     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
474                                                    InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
475         WriteTransaction tx = broker.newWriteOnlyTransaction();
476         tx.merge(datastoreType, path, data, true);
477         Futures.addCallback(tx.submit(), callback);
478     }
479
480     private <T extends DataObject> void syncWrite(LogicalDatastoreType datastoreType,
481                                                   InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
482         WriteTransaction tx = broker.newWriteOnlyTransaction();
483         tx.merge(datastoreType, path, data, true);
484         tx.submit();
485     }
486
487     private <T extends DataObject> void delete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
488         WriteTransaction tx = broker.newWriteOnlyTransaction();
489         tx.delete(datastoreType, path);
490         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
491     }
492
493     private InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
494         return InstanceIdentifier.builder(VpnInterfaces.class)
495                 .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).augmentation(
496                         Adjacencies.class).child(Adjacency.class, new AdjacencyKey(ipAddress)).build();
497     }
498
499     InstanceIdentifier<Adjacencies> getAdjListPath(String vpnInterfaceName) {
500         return InstanceIdentifier.builder(VpnInterfaces.class)
501                 .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).augmentation(
502                         Adjacencies.class).build();
503     }
504
505     public void setConfTransType(String service,String transportType) {
506
507         if (!service.toUpperCase().equals("L3VPN")) {
508             System.out.println("Please provide a valid service name. Available value(s): L3VPN");
509             LOG.error("Incorrect service {} provided for setting the transport type.", service);
510             return;
511         }
512
513         L3VPNTransportTypes transType = L3VPNTransportTypes.validateTransportType(transportType.toUpperCase());
514
515         if (transType != L3VPNTransportTypes.Invalid) {
516             configuredTransportTypeL3VPN = transType;
517         }
518     }
519
520     public void writeConfTransTypeConfigDS() {
521         FibUtil.syncWrite(  broker, LogicalDatastoreType.CONFIGURATION, getConfTransportTypeIdentifier(),
522                 createConfTransportType(configuredTransportTypeL3VPN.getTransportType()),
523                 FibUtil.DEFAULT_CALLBACK);
524     }
525
526     public L3VPNTransportTypes getConfiguredTransportTypeL3VPN() {
527         return this.configuredTransportTypeL3VPN;
528     }
529
530
531     public String getReqTransType() {
532         if (configuredTransportTypeL3VPN == L3VPNTransportTypes.Invalid) {
533                     /*
534                     * Restart scenario, Read from the ConfigDS.
535                     * if the value is Unset, cache value as VxLAN.
536                     */
537             LOG.trace("configureTransportType is not yet set.");
538             Optional<ConfTransportTypeL3vpn>  configuredTransTypeFromConfig =
539                     FibUtil.read(broker, LogicalDatastoreType.CONFIGURATION, getConfTransportTypeIdentifier());
540
541             if (configuredTransTypeFromConfig.isPresent()) {
542                 if (configuredTransTypeFromConfig.get().getTransportType().equals(TunnelTypeGre.class)) {
543                     configuredTransportTypeL3VPN.setL3VPNTransportTypes(ITMConstants.TUNNEL_TYPE_GRE);
544                 } else {
545                     configuredTransportTypeL3VPN.setL3VPNTransportTypes(ITMConstants.TUNNEL_TYPE_VXLAN);
546                 }
547                 LOG.trace("configuredTransportType set from config DS to " + getConfiguredTransportTypeL3VPN().getTransportType());
548             } else {
549                 setConfTransType("L3VPN", L3VPNTransportTypes.VxLAN.getTransportType());
550                 LOG.trace("configuredTransportType is not set in the Config DS. VxLAN as default will be used.");
551             }
552         } else {
553             LOG.trace("configuredTransportType is set as {}", getConfiguredTransportTypeL3VPN().getTransportType());
554         }
555         return getConfiguredTransportTypeL3VPN().getTransportType();
556     }
557     public InstanceIdentifier<ConfTransportTypeL3vpn> getConfTransportTypeIdentifier() {
558         return InstanceIdentifier.builder(ConfTransportTypeL3vpn.class).build();
559     }
560
561     private ConfTransportTypeL3vpn createConfTransportType (String type) {
562         ConfTransportTypeL3vpn confTransType;
563         if (type.equals(ITMConstants.TUNNEL_TYPE_GRE)) {
564             confTransType = new ConfTransportTypeL3vpnBuilder().setTransportType(TunnelTypeGre.class).build();
565             LOG.trace("Setting the confTransportType to GRE.");
566         } else if (type.equals(ITMConstants.TUNNEL_TYPE_VXLAN)) {
567             confTransType = new ConfTransportTypeL3vpnBuilder().setTransportType(TunnelTypeVxlan.class).build();
568             LOG.trace("Setting the confTransportType to VxLAN.");
569         } else {
570             LOG.trace("Invalid transport type {} passed to Config DS ", type);
571             confTransType = null;
572         }
573         return  confTransType;
574     }
575
576     public Class<? extends TunnelTypeBase> getReqTunType(String transportType) {
577         if (transportType.equals("VXLAN")) {
578             return TunnelTypeVxlan.class;
579         } else if (transportType.equals("GRE")) {
580             return TunnelTypeGre.class;
581         } else {
582             return TunnelTypeMplsOverGre.class;
583         }
584     }
585
586     public String getTransportTypeStr ( String tunType) {
587         if (tunType.equals(TunnelTypeVxlan.class.toString())) {
588             return ITMConstants.TUNNEL_TYPE_VXLAN;
589         } else if (tunType.equals(TunnelTypeGre.class.toString())) {
590             return ITMConstants.TUNNEL_TYPE_GRE;
591         } else if (tunType.equals(TunnelTypeMplsOverGre.class.toString())){
592             return ITMConstants.TUNNEL_TYPE_MPLS_OVER_GRE;
593         } else {
594             return ITMConstants.TUNNEL_TYPE_INVALID;
595         }
596     }
597 }