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