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