83c6feb93a176d51d3c757b9496ab8ea9632e893
[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
87     private static final FutureCallback<Void> DEFAULT_CALLBACK =
88         new FutureCallback<Void>() {
89             public void onSuccess(Void result) {
90                 LOG.debug("Success in Datastore write operation");
91             }
92             public void onFailure(Throwable error) {
93                 LOG.error("Error in Datastore write operation", error);
94             };
95         };
96
97     /**
98     * Provides nexthop functions
99     * Creates group ID pool
100     *
101     * @param db - dataBroker reference
102     */
103     public NexthopManager(final DataBroker db) {
104         broker = db;
105     }
106
107     @Override
108     public void close() throws Exception {
109         LOG.info("NextHop Manager Closed");
110     }
111
112     public void setInterfaceManager(OdlInterfaceRpcService ifManager) {
113         this.interfaceManager = ifManager;
114     }
115
116     public void setMdsalManager(IMdsalApiManager mdsalManager) {
117         this.mdsalManager = mdsalManager;
118     }
119
120     public void setIdManager(IdManagerService idManager) {
121         this.idManager = idManager;
122         createNexthopPointerPool();
123     }
124
125     public void setITMRpcService(ItmRpcService itmManager) {
126         this.itmManager = itmManager;
127     }
128
129     protected void createNexthopPointerPool() {
130         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
131             .setPoolName(NEXTHOP_ID_POOL_NAME)
132             .setLow(150000L)
133             .setHigh(175000L)
134             .build();
135         //TODO: Error handling
136         Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
137         LOG.trace("NextHopPointerPool result : {}", result);
138     }
139
140     private BigInteger getDpnId(String ofPortId) {
141         String[] fields = ofPortId.split(":");
142         BigInteger dpn = new BigInteger(fields[1]);
143         LOG.debug("DpnId: {}", dpn);
144         return dpn;
145     }
146
147     private String getNextHopKey(long vpnId, String ipAddress){
148         String nhKey = new String("nexthop." + vpnId + ipAddress);
149         return nhKey;
150     }
151
152     private String getNextHopKey(String ifName, String ipAddress){
153         String nhKey = new String("nexthop." + ifName + ipAddress);
154         return nhKey;
155     }
156
157     protected long createNextHopPointer(String nexthopKey) {
158         AllocateIdInput getIdInput = new AllocateIdInputBuilder()
159             .setPoolName(NEXTHOP_ID_POOL_NAME).setIdKey(nexthopKey)
160             .build();
161         //TODO: Proper error handling once IdManager code is complete
162         try {
163             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
164             RpcResult<AllocateIdOutput> rpcResult = result.get();
165             return rpcResult.getResult().getIdValue();
166         } catch (NullPointerException | InterruptedException | ExecutionException e) {
167             LOG.trace("",e);
168         }
169         return 0;
170     }
171
172     protected void removeNextHopPointer(String nexthopKey) {
173         ReleaseIdInput idInput = new ReleaseIdInputBuilder().
174                                        setPoolName(NEXTHOP_ID_POOL_NAME)
175                                        .setIdKey(nexthopKey).build();
176         try {
177             Future<RpcResult<Void>> result = idManager.releaseId(idInput);
178             RpcResult<Void> rpcResult = result.get();
179             if(!rpcResult.isSuccessful()) {
180                 LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
181             }
182         } catch (InterruptedException | ExecutionException e) {
183             LOG.warn("Exception when getting Unique Id for key {}", nexthopKey, e);
184         }
185     }
186
187     protected List<ActionInfo> getEgressActionsForInterface(String ifName) {
188         List<ActionInfo> listActionInfo = new ArrayList<ActionInfo>();
189         try {
190             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
191                 interfaceManager.getEgressActionsForInterface(
192                     new GetEgressActionsForInterfaceInputBuilder().setIntfName(ifName).build());
193             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
194             if(!rpcResult.isSuccessful()) {
195                 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", ifName, rpcResult.getErrors());
196             } else {
197                 List<org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action> actions =
198                     rpcResult.getResult().getAction();
199                 for (Action action : actions) {
200                     org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action actionClass = action.getAction();
201                     if (actionClass instanceof OutputActionCase) {
202                         listActionInfo.add(new ActionInfo(ActionType.output,
203                                                           new String[] {((OutputActionCase)actionClass).getOutputAction()
204                                                                             .getOutputNodeConnector().getValue()}));
205                     } else if (actionClass instanceof PushVlanActionCase) {
206                         listActionInfo.add(new ActionInfo(ActionType.push_vlan, new String[] {}));
207                     } else if (actionClass instanceof SetFieldCase) {
208                         if (((SetFieldCase)actionClass).getSetField().getVlanMatch() != null) {
209                             int vlanVid = ((SetFieldCase)actionClass).getSetField().getVlanMatch().getVlanId().getVlanId().getValue();
210                             listActionInfo.add(new ActionInfo(ActionType.set_field_vlan_vid,
211                                                               new String[] { Long.toString(vlanVid) }));
212                         }
213                     }
214                 }
215             }
216         } catch (InterruptedException | ExecutionException e) {
217             LOG.warn("Exception when egress actions for interface {}", ifName, e);
218         }
219         return listActionInfo;
220     }
221
222     protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
223         try {
224             Future<RpcResult<GetTunnelInterfaceNameOutput>> result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
225                                                                                  .setSourceDpid(srcDpId)
226                                                                                  .setDestinationDpid(dstDpId).build());
227             RpcResult<GetTunnelInterfaceNameOutput> rpcResult = result.get();
228             if(!rpcResult.isSuccessful()) {
229                 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
230             } else {
231                 return rpcResult.getResult().getInterfaceName();
232             }
233         } catch (InterruptedException | ExecutionException e) {
234             LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and  {}", srcDpId, dstDpId, e);
235         }
236         
237         return null;
238     }
239
240     protected String getTunnelInterfaceName(BigInteger srcDpId, IpAddress dstIp) {
241         try {
242             Future<RpcResult<GetInternalOrExternalInterfaceNameOutput>> result = itmManager.getInternalOrExternalInterfaceName(new GetInternalOrExternalInterfaceNameInputBuilder()
243                                                                                  .setSourceDpid(srcDpId)
244                                                                                  .setDestinationIp(dstIp).build());
245             RpcResult<GetInternalOrExternalInterfaceNameOutput> rpcResult = result.get();
246             if(!rpcResult.isSuccessful()) {
247                 LOG.warn("RPC Call to getTunnelInterfaceName returned with Errors {}", rpcResult.getErrors());
248             } else {
249                 return rpcResult.getResult().getInterfaceName();
250             }
251         } catch (InterruptedException | ExecutionException e) {
252             LOG.warn("Exception when getting tunnel interface Id for tunnel between {} and  {}", srcDpId, dstIp, e);
253         }
254         
255         return null;
256     }
257
258     public long createLocalNextHop(long vpnId, BigInteger dpnId,
259                                    String ifName, String ipAddress) {
260         long groupId = createNextHopPointer(getNextHopKey(vpnId, ipAddress));
261         String nextHopLockStr = new String(vpnId + ipAddress);
262         synchronized (nextHopLockStr.intern()) {
263             VpnNexthop nexthop = getVpnNexthop(vpnId, ipAddress);
264             LOG.trace("nexthop: {}", nexthop);
265             if (nexthop == null) {
266                 Optional<Adjacency> adjacencyData =
267                         read(LogicalDatastoreType.OPERATIONAL, getAdjacencyIdentifier(ifName, ipAddress));
268                 String macAddress = adjacencyData.isPresent() ? adjacencyData.get().getMacAddress() : null;
269                 List<BucketInfo> listBucketInfo = new ArrayList<BucketInfo>();
270                 List<ActionInfo> listActionInfo = getEgressActionsForInterface(ifName);
271                 BucketInfo bucket = new BucketInfo(listActionInfo);
272                 // MAC re-write
273                 if (macAddress != null) {
274                     listActionInfo.add(0, new ActionInfo(ActionType.set_field_eth_dest, new String[]{macAddress}));
275                     //listActionInfo.add(0, new ActionInfo(ActionType.pop_mpls, new String[]{}));
276                 } else {
277                     //FIXME: Log message here.
278                     LOG.debug("mac address for new local nexthop is null");
279                 }
280                 listBucketInfo.add(bucket);
281                 GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
282                         dpnId, groupId, ipAddress, GroupTypes.GroupIndirect, listBucketInfo);
283
284                 //update MD-SAL DS
285                 addVpnNexthopToDS(dpnId, vpnId, ipAddress, groupId);
286
287                 // install Group
288                 // FIXME: mdsalManager.syncInstallGroup(groupEntity);
289                 mdsalManager.installGroup(groupEntity);
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         try{
366             // here use the config for tunnel type param
367             tunnelIfName = getTunnelInterfaceName(remoteDpnId, IpAddressBuilder.getDefaultInstance(nextHopIp));
368         }catch(Exception ex){
369             LOG.error("Error while retrieving nexthop pointer for DC Gateway : ", ex.getMessage());
370         }
371         return tunnelIfName;
372     }
373
374     public BigInteger getDpnForPrefix(long vpnId, String prefixIp) {
375         VpnNexthop vpnNexthop = getVpnNexthop(vpnId, prefixIp);
376         BigInteger localDpnId = (vpnNexthop == null) ? null : vpnNexthop.getDpnId();
377         return localDpnId;
378     }
379
380
381     private void removeVpnNexthopFromDS(long vpnId, String ipPrefix) {
382
383         InstanceIdentifierBuilder<VpnNexthop> idBuilder = InstanceIdentifier.builder(L3nexthop.class)
384                 .child(VpnNexthops.class, new VpnNexthopsKey(vpnId))
385                 .child(VpnNexthop.class, new VpnNexthopKey(ipPrefix));
386         InstanceIdentifier<VpnNexthop> id = idBuilder.build();
387         // remove from DS
388         LOG.trace("Removing vpn next hop from datastore : {}", id);
389         delete(LogicalDatastoreType.OPERATIONAL, id);
390     }
391
392  
393     public void removeLocalNextHop(BigInteger dpnId, Long vpnId, String ipAddress) {
394
395         String nextHopLockStr = new String(vpnId + ipAddress);
396         synchronized (nextHopLockStr.intern()) {
397             VpnNexthop nh = getVpnNexthop(vpnId, ipAddress);
398             if (nh != null) {
399                 int newFlowrefCnt = nh.getFlowrefCount() - 1;
400                 if (newFlowrefCnt == 0) { //remove the group only if there are no more flows using this group
401                     GroupEntity groupEntity = MDSALUtil.buildGroupEntity(
402                             dpnId, nh.getEgressPointer(), ipAddress, GroupTypes.GroupIndirect, null);
403                     // remove Group ...
404                     // FIXME: mdsalManager.syncRemoveGroup(groupEntity);
405                     mdsalManager.removeGroup(groupEntity);
406                     //update MD-SAL DS
407                     removeVpnNexthopFromDS(vpnId, ipAddress);
408                     //release groupId
409                     removeNextHopPointer(getNextHopKey(vpnId, ipAddress));
410                     LOG.debug("Local Next hop for {} on dpn {} successfully deleted", ipAddress, dpnId);
411                 } else {
412                     //just update the flowrefCount of the vpnNexthop
413                     VpnNexthop currNh = new VpnNexthopBuilder().setKey(new VpnNexthopKey(ipAddress)).setFlowrefCount(newFlowrefCnt).build();
414                     LOG.trace("Updating vpnnextHop {} for refCount {} to Operational DS", currNh, newFlowrefCnt);
415                     syncWrite(LogicalDatastoreType.OPERATIONAL, getVpnNextHopIdentifier(vpnId, ipAddress), currNh, DEFAULT_CALLBACK);
416                 }
417             } else {
418                 //throw error
419                 LOG.error("Local Next hop for {} on dpn {} not deleted", ipAddress, dpnId);
420             }
421         }
422
423     }
424
425
426     private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
427             InstanceIdentifier<T> path) {
428
429         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
430
431         Optional<T> result = Optional.absent();
432         try {
433             result = tx.read(datastoreType, path).get();
434         } catch (Exception e) {
435             throw new RuntimeException(e);
436         }
437
438         return result;
439     }
440
441     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
442             InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
443         WriteTransaction tx = broker.newWriteOnlyTransaction();
444         tx.merge(datastoreType, path, data, true);
445         Futures.addCallback(tx.submit(), callback);
446     }
447
448     private <T extends DataObject> void syncWrite(LogicalDatastoreType datastoreType,
449             InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
450         WriteTransaction tx = broker.newWriteOnlyTransaction();
451         tx.merge(datastoreType, path, data, true);
452         tx.submit();
453     }
454
455     private <T extends DataObject> void delete(LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
456         WriteTransaction tx = broker.newWriteOnlyTransaction();
457         tx.delete(datastoreType, path);
458         Futures.addCallback(tx.submit(), DEFAULT_CALLBACK);
459     }
460
461     private InstanceIdentifier<Adjacency> getAdjacencyIdentifier(String vpnInterfaceName, String ipAddress) {
462         return InstanceIdentifier.builder(VpnInterfaces.class)
463             .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).augmentation(
464                 Adjacencies.class).child(Adjacency.class, new AdjacencyKey(ipAddress)).build();
465     }
466 }