Terminaing service table fix in fibmanager
[vpnservice.git] / fibmanager / fibmanager-impl / src / main / java / org / opendaylight / vpnservice / 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.vpnservice.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.vpnservice.mdsalutil.ActionInfo;
19 import org.opendaylight.vpnservice.mdsalutil.ActionType;
20 import org.opendaylight.vpnservice.mdsalutil.BucketInfo;
21 import org.opendaylight.vpnservice.mdsalutil.GroupEntity;
22 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
23 import org.opendaylight.vpnservice.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.l3vpn.rev130911.Adjacencies;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.Adjacency;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.l3vpn.rev130911.adjacency.list.AdjacencyKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameInputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetExternalTunnelInterfaceNameOutput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameInputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.GetTunnelInterfaceNameOutput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.ItmRpcService;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInputBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInput;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInputBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInput;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInputBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.L3nexthop;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.VpnNexthops;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.VpnNexthopsKey;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthopBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthopKey;
59 import org.opendaylight.yangtools.yang.binding.DataObject;
60 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
61 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
62 import org.opendaylight.yangtools.yang.common.RpcResult;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66 import java.math.BigInteger;
67 import java.util.ArrayList;
68 import java.util.List;
69 import java.util.concurrent.ExecutionException;
70 import java.util.concurrent.Future;
71
72 public class NexthopManager implements AutoCloseable {
73     private static final Logger LOG = LoggerFactory.getLogger(NexthopManager.class);
74     private final DataBroker broker;
75     private IMdsalApiManager mdsalManager;
76     private OdlInterfaceRpcService interfaceManager;
77     private ItmRpcService itmManager;
78     private IdManagerService idManager;
79     private static final short LPORT_INGRESS_TABLE = 0;
80     private static final short LFIB_TABLE = 20;
81     private static final short FIB_TABLE = 21;
82     private static final short DEFAULT_FLOW_PRIORITY = 10;
83     private static final String NEXTHOP_ID_POOL_NAME = "nextHopPointerPool";
84
85     private static final FutureCallback<Void> DEFAULT_CALLBACK =
86         new FutureCallback<Void>() {
87             public void onSuccess(Void result) {
88                 LOG.debug("Success in Datastore write operation");
89             }
90             public void onFailure(Throwable error) {
91                 LOG.error("Error in Datastore write operation", error);
92             };
93         };
94
95     /**
96     * Provides nexthop functions
97     * Creates group ID pool
98     *
99     * @param db - dataBroker reference
100     */
101     public NexthopManager(final DataBroker db) {
102         broker = db;
103     }
104
105     @Override
106     public void close() throws Exception {
107         LOG.info("NextHop Manager Closed");
108     }
109
110     public void setInterfaceManager(OdlInterfaceRpcService ifManager) {
111         this.interfaceManager = ifManager;
112     }
113
114     public void setMdsalManager(IMdsalApiManager mdsalManager) {
115         this.mdsalManager = mdsalManager;
116     }
117
118     public void setIdManager(IdManagerService idManager) {
119         this.idManager = idManager;
120         createNexthopPointerPool();
121     }
122
123     public void setITMRpcService(ItmRpcService itmManager) {
124         this.itmManager = itmManager;
125     }
126
127     protected void createNexthopPointerPool() {
128         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
129             .setPoolName(NEXTHOP_ID_POOL_NAME)
130             .setLow(150000L)
131             .setHigh(175000L)
132             .build();
133         //TODO: Error handling
134         Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
135         LOG.trace("NextHopPointerPool result : {}", result);
136     }
137
138     private BigInteger getDpnId(String ofPortId) {
139         String[] fields = ofPortId.split(":");
140         BigInteger dpn = new BigInteger(fields[1]);
141         LOG.debug("DpnId: {}", dpn);
142         return dpn;
143     }
144
145     private String getNextHopKey(long vpnId, String ipAddress){
146         String nhKey = new String("nexthop." + vpnId + ipAddress);
147         return nhKey;
148     }
149
150     private String getNextHopKey(String ifName, String ipAddress){
151         String nhKey = new String("nexthop." + ifName + ipAddress);
152         return nhKey;
153     }
154
155     protected long createNextHopPointer(String nexthopKey) {
156         AllocateIdInput getIdInput = new AllocateIdInputBuilder()
157             .setPoolName(NEXTHOP_ID_POOL_NAME).setIdKey(nexthopKey)
158             .build();
159         //TODO: Proper error handling once IdManager code is complete
160         try {
161             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
162             RpcResult<AllocateIdOutput> rpcResult = result.get();
163             return rpcResult.getResult().getIdValue();
164         } catch (NullPointerException | InterruptedException | ExecutionException e) {
165             LOG.trace("",e);
166         }
167         return 0;
168     }
169
170     protected void removeNextHopPointer(String nexthopKey) {
171         ReleaseIdInput idInput = new ReleaseIdInputBuilder().
172                                        setPoolName(NEXTHOP_ID_POOL_NAME)
173                                        .setIdKey(nexthopKey).build();
174         try {
175             Future<RpcResult<Void>> result = idManager.releaseId(idInput);
176             RpcResult<Void> rpcResult = result.get();
177             if(!rpcResult.isSuccessful()) {
178                 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
179             }
180         } catch (InterruptedException | ExecutionException e) {
181             LOG.warn("Exception when getting Unique Id for key {}", nexthopKey, e);
182         }
183     }
184
185     protected List<ActionInfo> getEgressActionsForInterface(String ifName) {
186         List<ActionInfo> listActionInfo = new ArrayList<ActionInfo>();
187         try {
188             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
189                 interfaceManager.getEgressActionsForInterface(
190                     new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).build());
191             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
192             if(!rpcResult.isSuccessful()) {
193                 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, rpcResult.getErrors());
194             } else {
195                 List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actions =
196                     rpcResult.getResult().getAction();
197                 for (Action action : actions) {
198                     org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = action.getAction();
199                     if (actionClass instanceof OutputActionCase) {
200                         listActionInfo.add(new ActionInfo(ActionType.output,
201                                                           new String[] {((OutputActionCase)actionClass).getOutputAction()
202                                                                             .getOutputNodeConnector().getValue()}));
203                     } else if (actionClass instanceof PushVlanActionCase) {
204                         listActionInfo.add(new ActionInfo(ActionType.push_vlan, new String[] {}));
205                     } else if (actionClass instanceof SetFieldCase) {
206                         if (((SetFieldCase)actionClass).getSetField().getVlanMatch() != null) {
207                             int vlanVid = ((SetFieldCase)actionClass).getSetField().getVlanMatch().getVlanId().getVlanId().getValue();
208                             listActionInfo.add(new ActionInfo(ActionType.set_field_vlan_vid,
209                                                               new String[] { Long.toString(vlanVid) }));
210                         }
211                     }
212                 }
213             }
214         } catch (InterruptedException | ExecutionException e) {
215             LOG.warn("Exception when egress actions for interface {}", ifName, e);
216         }
217         return listActionInfo;
218     }
219
220     protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
221         try {
222             Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
223                                                                                  .setSourceDpid(srcDpId)
224                                                                                  .setDestinationDpid(dstDpId).build());
225             RpcResult<GetTunnelInterfaceNameOutput> rpcResult = result.get();
226             if(!rpcResult.isSuccessful()) {
227                 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
228             } else {
229                 return rpcResult.getResult().getInterfaceName();
230             }
231         } catch (InterruptedException | ExecutionException e) {
232             LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and  {}", srcDpId, dstDpId, e);
233         }
234         
235         return null;
236     }
237
238     protected String getExternalTunnelInterfaceName(BigInteger srcDpId, IpAddress dstIp) {
239         try {
240             Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> result = itmManager.getExternalTunnelInterfaceName(new GetExternalTunnelInterfaceNameInputBuilder()
241                                                                                  .setSourceDpid(srcDpId)
242                                                                                  .setDestinationIp(dstIp).build());
243             RpcResult<GetExternalTunnelInterfaceNameOutput> rpcResult = result.get();
244             if(!rpcResult.isSuccessful()) {
245                 LOG.warn("RPC Call to getExternalTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
246             } else {
247                 return rpcResult.getResult().getInterfaceName();
248             }
249         } catch (InterruptedException | ExecutionException e) {
250             LOG.warn("Exception when getting external tunnel interface Id for tunnel between {} and  {}", srcDpId, dstIp, e);
251         }
252         
253         return null;
254     }
255
256     public long createLocalNextHop(long vpnId, BigInteger dpnId,
257                                    String ifName, String ipAddress) {
258         long groupId = createNextHopPointer(getNextHopKey(vpnId, ipAddress));
259         String nextHopLockStr = new String(vpnId + ipAddress);
260         synchronized (nextHopLockStr.intern()) {
261             VpnNexthop nexthop = getVpnNexthop(vpnId, ipAddress);
262             LOG.trace("nexthop: {}", nexthop);
263             if (nexthop == null) {
264                 Optional<Adjacency> adjacencyData =
265                         read(LogicalDatastoreType.OPERATIONAL, getAdjacencyIdentifier(ifName, ipAddress));
266                 String macAddress = adjacencyData.isPresent() ? adjacencyData.get().getMacAddress() : null;
267                 List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
268                 List<ActionInfo> listActionInfo = getEgressActionsForInterface(ifName);
269                 BucketInfo bucket = new BucketInfo(listActionInfo);
270                 // MAC re-write
271                 if (macAddress != null) {
272                     listActionInfo.add(0, new ActionInfo(ActionType.set_field_eth_dest, new String[]{macAddress}));
273                     //listActionInfo.add(0, new ActionInfo(ActionType.pop_mpls, new String[]{}));
274                 } else {
275                     //FIXME: Log message here.
276                     LOG.debug("mac address for new local nexthop is null");
277                 }
278                 listBucketInfo.add(bucket);
279                 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
280                         dpnId, groupId, ipAddress, GroupTypes.GroupIndirect, listBucketInfo);
281
282                 //update MD-SAL DS
283                 addVpnNexthopToDS(dpnId, vpnId, ipAddress, groupId);
284
285                 // install Group
286                 // FIXME: mdsalManager.syncInstallGroup(groupEntity);
287                 mdsalManager.installGroup(groupEntity);
288
289             } else {
290                 //nexthop exists already; a new flow is going to point to it, increment the flowrefCount by 1
291                 int flowrefCnt = nexthop.getFlowrefCount() + 1;
292                 VpnNexthop nh = new VpnNexthopBuilder().setKey(new VpnNexthopKey(ipAddress)).setFlowrefCount(flowrefCnt).build();
293                 LOG.trace("Updating vpnnextHop {} for refCount {} to Operational DS", nh, flowrefCnt);
294                 syncWrite(LogicalDatastoreType.OPERATIONAL, getVpnNextHopIdentifier(vpnId, ipAddress), nh, DEFAULT_CALLBACK);
295
296             }
297         }
298         return groupId;
299     }
300
301
302     protected void addVpnNexthopToDS(BigInteger dpnId, long vpnId, String ipPrefix, long egressPointer) {
303
304         InstanceIdentifierBuilder<VpnNexthops> idBuilder = InstanceIdentifier.builder(
305             L3nexthop.class)
306                 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId));
307
308         // Add nexthop to vpn node
309         VpnNexthop nh = new VpnNexthopBuilder().
310                 setKey(new VpnNexthopKey(ipPrefix)).
311                 setDpnId(dpnId).
312                 setIpAddress(ipPrefix).
313                 setFlowrefCount(1).
314                 setEgressPointer(egressPointer).build();
315
316         InstanceIdentifier<VpnNexthop> id1 = idBuilder
317                 .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix)).build();
318         LOG.trace("Adding vpnnextHop {} to Operational DS", nh);
319         syncWrite(LogicalDatastoreType.OPERATIONAL, id1, nh, DEFAULT_CALLBACK);
320
321     }
322
323
324
325     protected InstanceIdentifier<VpnNexthop> getVpnNextHopIdentifier(long vpnId, String ipAddress) {
326         InstanceIdentifier<VpnNexthop> id = InstanceIdentifier.builder(
327                 L3nexthop.class)
328                 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId)).child(VpnNexthop.class, new VpnNexthopKey(ipAddress)).build();
329         return id;
330     }
331
332     protected VpnNexthop getVpnNexthop(long vpnId, String ipAddress) {
333
334         // check if vpn node is there
335         InstanceIdentifierBuilder<VpnNexthops> idBuilder =
336             InstanceIdentifier.builder(L3nexthop.class).child(VpnNexthops.class,
337                                                               new VpnNexthopsKey(vpnId));
338         InstanceIdentifier<VpnNexthops> id = idBuilder.build();
339         Optional<VpnNexthops> vpnNexthops = read(LogicalDatastoreType.OPERATIONAL, id);
340         if (vpnNexthops.isPresent()) {
341             // get nexthops list for vpn
342             List<VpnNexthop> nexthops = vpnNexthops.get().getVpnNexthop();
343             for (VpnNexthop nexthop : nexthops) {
344                 if (nexthop.getIpAddress().equals(ipAddress)) {
345                     // return nexthop
346                     LOG.trace("VpnNextHop : {}", nexthop);
347                     return nexthop;
348                 }
349             }
350             // return null if not found
351         }
352         return null;
353     }
354
355
356     public String getRemoteNextHopPointer(BigInteger localDpnId, BigInteger remoteDpnId,
357                                                     long vpnId, String prefixIp, String nextHopIp) {
358         String tunnelIfName = null;
359         LOG.trace("getRemoteNextHopPointer: input [localDpnId {} remoteDpnId {}, vpnId {}, prefixIp {}, nextHopIp {} ]",
360                   localDpnId, remoteDpnId, vpnId, prefixIp, nextHopIp);
361
362         // check if the incoming VM is within the same DC. If so, retrieve the local tunnel group pointer.
363         // Else retrieve the tunnel to DC gateway group pointer.
364
365         if (localDpnId == null  || BigInteger.ZERO.equals(localDpnId)) {
366             VpnNexthop vpnNexthop = getVpnNexthop(vpnId, prefixIp);
367             //If the vrf entry is a static/extra route, the nexthop of the entry would be a adjacency in the vpn
368             if(vpnNexthop == null) {
369                 vpnNexthop = getVpnNexthop(vpnId, nextHopIp + "/32");
370             }
371             localDpnId = (vpnNexthop == null) ? null : vpnNexthop.getDpnId();
372         }
373         LOG.trace("getRemoteNextHopPointer: Calling ITM with localDpnId {} ", localDpnId);
374         try{
375             // here use the config for tunnel type param
376             if(localDpnId != null){
377                 //internal tunnel
378                 tunnelIfName =  getTunnelInterfaceName(remoteDpnId, localDpnId);
379             } else {
380                 //external tunnel
381                 tunnelIfName = getExternalTunnelInterfaceName(remoteDpnId,
382                                                                    IpAddressBuilder.getDefaultInstance(nextHopIp));
383             }
384         }catch(Exception ex){
385             LOG.error("Error while retrieving nexthop pointer for DC Gateway : ", ex.getMessage());
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                     // FIXME: mdsalManager.syncRemoveGroup(groupEntity);
421                     mdsalManager.removeGroup(groupEntity);
422                     //update MD-SAL DS
423                     removeVpnNexthopFromDS(vpnId, ipAddress);
424                     //release groupId
425                     removeNextHopPointer(getNextHopKey(vpnId, ipAddress));
426                     LOG.debug("Local Next hop for {} on dpn {} successfully deleted", ipAddress, dpnId);
427                 } else {
428                     //just update the flowrefCount of the vpnNexthop
429                     VpnNexthop currNh = new VpnNexthopBuilder().setKey(new VpnNexthopKey(ipAddress)).setFlowrefCount(newFlowrefCnt).build();
430                     LOG.trace("Updating vpnnextHop {} for refCount {} to Operational DS", currNh, newFlowrefCnt);
431                     syncWrite(LogicalDatastoreType.OPERATIONAL, getVpnNextHopIdentifier(vpnId, ipAddress), currNh, DEFAULT_CALLBACK);
432                 }
433             } else {
434                 //throw error
435                 LOG.error("Local Next hop for {} on dpn {} not deleted", ipAddress, dpnId);
436             }
437         }
438
439     }
440
441
442     private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
443             InstanceIdentifier<T> path) {
444
445         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
446
447         Optional<T> result = Optional.absent();
448         try {
449             result = tx.read(datastoreType, path).get();
450         } catch (Exception e) {
451             throw new RuntimeException(e);
452         }
453
454         return result;
455     }
456
457     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
458             InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
459         WriteTransaction tx = broker.newWriteOnlyTransaction();
460         tx.merge(datastoreType, path, data, true);
461         Futures.addCallback(tx.submit(), callback);
462     }
463
464     private <T extends DataObject> void syncWrite(LogicalDatastoreType datastoreType,
465             InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
466         WriteTransaction tx = broker.newWriteOnlyTransaction();
467         tx.merge(datastoreType, path, data, true);
468         tx.submit();
469     }
470
471     private <T extends DataObject> void delete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
472         WriteTransaction tx = broker.newWriteOnlyTransaction();
473         tx.delete(datastoreType, path);
474         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
475     }
476
477     private InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
478         return InstanceIdentifier.builder(VpnInterfaces.class)
479             .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).augmentation(
480                 Adjacencies.class).child(Adjacency.class, new AdjacencyKey(ipAddress)).build();
481     }
482 }