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