Merge "itm and mdsal porting"
[vpnservice.git] / itm / itm-impl / src / main / java / org / opendaylight / vpnservice / itm / rpc / ItmManagerRpcService.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.itm.rpc;
9
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.concurrent.Future;
14
15 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
16 import org.opendaylight.vpnservice.mdsalutil.*;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.TransportZones;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZone;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.TransportZoneKey;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.Subnets;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.SubnetsKey;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.DeviceVteps;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.DeviceVtepsBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rev150701.transport.zones.transport.zone.subnets.DeviceVtepsKey;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.rpcs.rev151217.*;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
31 import org.opendaylight.vpnservice.itm.confighelpers.ItmExternalTunnelAddWorker;
32 import org.opendaylight.vpnservice.itm.confighelpers.ItmExternalTunnelDeleteWorker;
33 import org.opendaylight.vpnservice.itm.globals.ITMConstants;
34 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
35 import org.opendaylight.vpnservice.itm.impl.ItmUtils;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.ExternalTunnelList;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelList;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.DPNTEPsInfo;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnelKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnelKey;
45 import org.opendaylight.yangtools.yang.common.RpcResult;
46 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
47
48 import org.opendaylight.yangtools.yang.common.RpcError;
49 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
50
51 import com.google.common.base.Optional;
52 import com.google.common.util.concurrent.Futures;
53 import com.google.common.util.concurrent.FutureCallback;
54 import com.google.common.util.concurrent.ListenableFuture;
55 import com.google.common.util.concurrent.SettableFuture;
56
57 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
58
59 public class ItmManagerRpcService implements ItmRpcService {
60
61     private static final Logger LOG = LoggerFactory.getLogger(ItmManagerRpcService.class);
62     DataBroker dataBroker;
63     private IMdsalApiManager mdsalManager;
64
65
66     public void setMdsalManager(IMdsalApiManager mdsalManager) {
67         this.mdsalManager = mdsalManager;
68     }
69
70     IdManagerService idManagerService;
71
72     public ItmManagerRpcService(DataBroker dataBroker, IdManagerService idManagerService) {
73         this.dataBroker = dataBroker;
74         this.idManagerService = idManagerService;
75     }
76
77     @Override
78     public Future<RpcResult<GetTunnelInterfaceNameOutput>> getTunnelInterfaceName(GetTunnelInterfaceNameInput input) {
79         RpcResultBuilder<GetTunnelInterfaceNameOutput> resultBld = null;
80         BigInteger sourceDpn = input.getSourceDpid() ;
81         BigInteger destinationDpn = input.getDestinationDpid() ;
82         InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(
83                 TunnelList.class)
84                 .child(InternalTunnel.class, new InternalTunnelKey( destinationDpn,sourceDpn));
85
86         Optional<InternalTunnel> tnl = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, dataBroker);
87
88         if( tnl != null && tnl.isPresent())
89         {
90             InternalTunnel tunnel = tnl.get();
91             GetTunnelInterfaceNameOutputBuilder output = new GetTunnelInterfaceNameOutputBuilder() ;
92             output.setInterfaceName(tunnel.getTunnelInterfaceName()) ;
93             resultBld = RpcResultBuilder.success();
94             resultBld.withResult(output.build()) ;
95         }else {
96             resultBld = RpcResultBuilder.failed();
97         }
98
99         return Futures.immediateFuture(resultBld.build());
100     }
101
102
103     @Override
104     public Future<RpcResult<Void>> removeExternalTunnelEndpoint(
105             RemoveExternalTunnelEndpointInput input) {
106         //Ignore the Futures for now
107         final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
108         List<DPNTEPsInfo> meshedDpnList = ItmUtils.getTunnelMeshInfo(dataBroker) ;
109         ItmExternalTunnelDeleteWorker.deleteTunnels(dataBroker, idManagerService,meshedDpnList , input.getDestinationIp(), input.getTunnelType());
110         result.set(RpcResultBuilder.<Void>success().build());
111         return result;
112     }
113
114     @Override
115     public Future<RpcResult<Void>> removeExternalTunnelFromDpns(
116             RemoveExternalTunnelFromDpnsInput input) {
117         //Ignore the Futures for now
118         final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
119         List<DPNTEPsInfo> cfgDpnList = ItmUtils.getDPNTEPListFromDPNId(dataBroker, input.getDpnId()) ;
120         ItmExternalTunnelDeleteWorker.deleteTunnels(dataBroker, idManagerService, cfgDpnList, input.getDestinationIp(), input.getTunnelType());
121         result.set(RpcResultBuilder.<Void>success().build());
122         return result;
123     }
124
125     @Override
126     public Future<RpcResult<Void>> buildExternalTunnelFromDpns(
127             BuildExternalTunnelFromDpnsInput input) {
128         //Ignore the Futures for now
129         final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
130         List<ListenableFuture<Void>> extTunnelResultList = ItmExternalTunnelAddWorker.buildTunnelsFromDpnToExternalEndPoint(dataBroker, idManagerService,input.getDpnId(), input.getDestinationIp(), input.getTunnelType());
131         for (ListenableFuture<Void> extTunnelResult : extTunnelResultList) {
132             Futures.addCallback(extTunnelResult, new FutureCallback<Void>(){
133
134                 @Override
135                 public void onSuccess(Void aVoid) {
136                     result.set(RpcResultBuilder.<Void>success().build());
137                 }
138
139                 @Override
140                 public void onFailure(Throwable error) {
141                     String msg = String.format("Unable to create ext tunnel");
142                     LOG.error("create ext tunnel failed. {}. {}", msg, error);
143                     result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, msg, error).build());
144                 }
145             });
146         }
147         result.set(RpcResultBuilder.<Void>success().build());
148         return result;
149     }
150
151     @Override
152     public Future<RpcResult<Void>> addExternalTunnelEndpoint(
153             AddExternalTunnelEndpointInput input) {
154         // TODO Auto-generated method stub
155
156         //Ignore the Futures for now
157         final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
158         List<DPNTEPsInfo> meshedDpnList = ItmUtils.getTunnelMeshInfo(dataBroker) ;
159         ItmExternalTunnelAddWorker.buildTunnelsToExternalEndPoint(dataBroker, idManagerService,meshedDpnList, input.getDestinationIp(), input.getTunnelType()) ;
160         result.set(RpcResultBuilder.<Void>success().build());
161         return result;
162     }
163
164     @Override
165     public Future<RpcResult<GetExternalTunnelInterfaceNameOutput>> getExternalTunnelInterfaceName(
166             GetExternalTunnelInterfaceNameInput input) {
167         final SettableFuture<RpcResult<GetExternalTunnelInterfaceNameOutput>> result = SettableFuture.create() ;
168         RpcResultBuilder<GetExternalTunnelInterfaceNameOutput> resultBld;
169         String sourceNode = input.getSourceNode();
170         String dstNode = input.getDestinationNode();
171         InstanceIdentifier<ExternalTunnel> path = InstanceIdentifier.create(
172                 ExternalTunnelList.class)
173                 .child(ExternalTunnel.class, new ExternalTunnelKey(dstNode, sourceNode));
174
175         Optional<ExternalTunnel> ext = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, dataBroker);
176
177         if( ext != null && ext.isPresent())
178         {
179             ExternalTunnel exTunnel = ext.get();
180             GetExternalTunnelInterfaceNameOutputBuilder output = new GetExternalTunnelInterfaceNameOutputBuilder() ;
181             output.setInterfaceName(exTunnel.getTunnelInterfaceName()) ;
182             resultBld = RpcResultBuilder.success();
183             resultBld.withResult(output.build()) ;
184         }else {
185             resultBld = RpcResultBuilder.failed();
186         }
187
188         return Futures.immediateFuture(resultBld.build());
189     }
190
191     @Override
192     public Future<RpcResult<java.lang.Void>> createTerminatingServiceActions(final CreateTerminatingServiceActionsInput input) {
193         LOG.info("create terminatingServiceAction on DpnId = {} for service id {} and instructions {}", input.getDpnId() , input.getServiceId(), input.getInstruction());
194         final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
195         int serviceId = input.getServiceId() ;
196         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
197         byte[] vxLANHeader = new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
198         // Flags Byte
199         byte Flags = (byte) 0x08;
200         vxLANHeader[0] = Flags;
201
202         // Extract the serviceId details and imprint on the VxLAN Header
203         vxLANHeader[4] = (byte) (serviceId >> 16);
204         vxLANHeader[5] = (byte) (serviceId >> 8);
205         vxLANHeader[6] = (byte) (serviceId >> 0);
206
207         // Matching metadata
208         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {
209                 new BigInteger(1, vxLANHeader),
210                 MetaDataUtil.METADA_MASK_VALID_TUNNEL_ID_BIT_AND_TUNNEL_ID }));
211
212         Flow terminatingServiceTableFlow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
213                 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE,serviceId), 5, String.format("%s:%d","ITM Flow Entry ",serviceId),
214                 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(serviceId)),mkMatches, input.getInstruction());
215
216         ListenableFuture<Void> installFlowResult = mdsalManager.installFlow(input.getDpnId(), terminatingServiceTableFlow);
217         Futures.addCallback(installFlowResult, new FutureCallback<Void>(){
218
219             @Override
220             public void onSuccess(Void aVoid) {
221                 result.set(RpcResultBuilder.<Void>success().build());
222             }
223
224             @Override
225             public void onFailure(Throwable error) {
226                 String msg = String.format("Unable to install terminating service flow for %s", input.getDpnId());
227                 LOG.error("create terminating service actions failed. {}. {}", msg, error);
228                 result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, msg, error).build());
229             }
230         });
231        // result.set(RpcResultBuilder.<Void>success().build());
232         return result;
233     }
234
235     @Override
236     public Future<RpcResult<java.lang.Void>> removeTerminatingServiceActions(final RemoveTerminatingServiceActionsInput input) {
237         LOG.info("remove terminatingServiceActions called with DpnId = {} and serviceId = {}", input.getDpnId(), input.getServiceId());
238         final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
239         Flow terminatingServiceTableFlow = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
240                 getFlowRef(NwConstants.INTERNAL_TUNNEL_TABLE,input.getServiceId()), 5, String.format("%s:%d","ITM Flow Entry ",input.getServiceId()),
241                 0, 0, ITMConstants.COOKIE_ITM.add(BigInteger.valueOf(input.getServiceId())),getTunnelMatchesForServiceId(input.getServiceId()), null );
242
243         ListenableFuture<Void> installFlowResult = mdsalManager.removeFlow(input.getDpnId(), terminatingServiceTableFlow);
244         Futures.addCallback(installFlowResult, new FutureCallback<Void>(){
245
246             @Override
247             public void onSuccess(Void aVoid) {
248                 result.set(RpcResultBuilder.<Void>success().build());
249             }
250
251             @Override
252             public void onFailure(Throwable error) {
253                 String msg = String.format("Unable to remove terminating service flow for %s", input.getDpnId());
254                 LOG.error("remove terminating service actions failed. {}. {}", msg, error);
255                 result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, msg, error).build());
256             }
257         });
258         //result.set(RpcResultBuilder.<Void>success().build());
259
260         return result ;
261     }
262
263
264     public List<MatchInfo> getTunnelMatchesForServiceId(int serviceId) {
265         List<MatchInfo> mkMatches = new ArrayList<MatchInfo>();
266         byte[] vxLANHeader = new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
267
268         // Flags Byte
269         byte Flags = (byte) 0x08;
270         vxLANHeader[0] = Flags;
271
272         // Extract the serviceId details and imprint on the VxLAN Header
273         vxLANHeader[4] = (byte) (serviceId >> 16);
274         vxLANHeader[5] = (byte) (serviceId >> 8);
275         vxLANHeader[6] = (byte) (serviceId >> 0);
276
277         // Matching metadata
278         mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[]{
279                 BigInteger.valueOf(serviceId)}));
280
281         return mkMatches;
282     }
283
284     private String getFlowRef(long termSvcTable, int svcId) {
285         return new StringBuffer().append(termSvcTable).append(svcId).toString();
286     }
287
288     @Override
289     public Future<RpcResult<GetInternalOrExternalInterfaceNameOutput>> getInternalOrExternalInterfaceName(
290             GetInternalOrExternalInterfaceNameInput input) {
291         RpcResultBuilder<GetInternalOrExternalInterfaceNameOutput> resultBld = RpcResultBuilder.failed();
292         BigInteger srcDpn = input.getSourceDpid() ;
293         String srcNode = srcDpn.toString();
294         IpAddress dstIp = input.getDestinationIp() ;
295         InstanceIdentifier<ExternalTunnel> path1 = InstanceIdentifier.create(
296                 ExternalTunnelList.class)
297                 .child(ExternalTunnel.class, new ExternalTunnelKey(String.valueOf(dstIp), srcDpn.toString()));
298
299         Optional<ExternalTunnel> ext = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path1, dataBroker);
300
301         if( ext != null && ext.isPresent())
302         {
303             ExternalTunnel extTunnel = ext.get();
304             GetInternalOrExternalInterfaceNameOutputBuilder output = new GetInternalOrExternalInterfaceNameOutputBuilder().setInterfaceName(extTunnel.getTunnelInterfaceName() );
305             resultBld = RpcResultBuilder.success();
306             resultBld.withResult(output.build()) ;
307         } else {
308             List<DPNTEPsInfo> meshedDpnList = ItmUtils.getTunnelMeshInfo(dataBroker);
309             // Look for external tunnels if not look for internal tunnel
310             for (DPNTEPsInfo teps : meshedDpnList) {
311                 TunnelEndPoints firstEndPt = teps.getTunnelEndPoints().get(0);
312                 if (dstIp.equals(firstEndPt.getIpAddress())) {
313                     InstanceIdentifier<InternalTunnel> path = InstanceIdentifier.create(
314                             TunnelList.class)
315                             .child(InternalTunnel.class, new InternalTunnelKey(teps.getDPNID(),srcDpn));
316
317                     Optional<InternalTunnel>
318                             tnl =
319                             ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, dataBroker);
320                     if (tnl != null && tnl.isPresent()) {
321                         InternalTunnel tunnel = tnl.get();
322                         GetInternalOrExternalInterfaceNameOutputBuilder
323                                 output =
324                                 new GetInternalOrExternalInterfaceNameOutputBuilder()
325                                         .setInterfaceName(tunnel.getTunnelInterfaceName());
326                         resultBld = RpcResultBuilder.success();
327                         resultBld.withResult(output.build());
328                         break;
329                     }
330                 }
331             }
332         }
333         return Futures.immediateFuture(resultBld.build());
334     }
335
336     @Override
337     public Future<RpcResult<java.lang.Void>> deleteL2GwDevice(DeleteL2GwDeviceInput input) {
338         final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
339         try {
340             final IpAddress hwIp = input.getIpAddress();
341             final String node_id = input.getNodeId();
342             InstanceIdentifier<TransportZones> containerPath = InstanceIdentifier.create(TransportZones.class);
343             Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, containerPath, dataBroker);
344             if (tZonesOptional.isPresent()) {
345                 TransportZones tZones = tZonesOptional.get();
346                 if (tZones.getTransportZone() == null || tZones.getTransportZone().isEmpty()) {
347                     LOG.error("No teps configured");
348                     result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, "No teps Configured").build());
349                     return result;
350                 }
351                 String transportZone = tZones.getTransportZone().get(0).getZoneName();
352                 if (tZones.getTransportZone().get(0).getSubnets() == null || tZones.getTransportZone().get(0).getSubnets().isEmpty()) {
353                     result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, "No subnets Configured").build());
354                     return result;
355                 }
356                 SubnetsKey subnetsKey = tZones.getTransportZone().get(0).getSubnets().get(0).getKey();
357                 DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, node_id);
358                 InstanceIdentifier<DeviceVteps> path =
359                                 InstanceIdentifier.builder(TransportZones.class)
360                                                 .child(TransportZone.class, new TransportZoneKey(transportZone))
361                                                 .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey).build();
362                 WriteTransaction t = dataBroker.newWriteOnlyTransaction();
363                 //TO DO: add retry if it fails
364                 t.delete(LogicalDatastoreType.CONFIGURATION, path);
365
366                 ListenableFuture<Void> futureCheck = t.submit();
367                 Futures.addCallback(futureCheck, new FutureCallback<Void>() {
368
369                     @Override
370                     public void onSuccess(Void aVoid) {
371                         result.set(RpcResultBuilder.<Void>success().build());
372                     }
373
374                     @Override
375                     public void onFailure(Throwable error) {
376                         String msg = String.format("Unable to write HwVtep {} to datastore", node_id);
377                         LOG.error("Unable to write HwVtep {}, {} to datastore", node_id , hwIp);
378                         result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, msg, error).build());
379                     }
380                 });
381             }
382             return result;
383         } catch (Exception e) {
384             RpcResultBuilder<java.lang.Void> resultBuilder = RpcResultBuilder.<Void>failed().
385                             withError(RpcError.ErrorType.APPLICATION, "Deleting l2 Gateway to DS Failed", e);
386             return Futures.immediateFuture(resultBuilder.build());
387         }
388     }
389
390     @Override
391     public Future<RpcResult<java.lang.Void>> addL2GwDevice(AddL2GwDeviceInput input) {
392
393         final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
394         try {
395             final IpAddress hwIp = input.getIpAddress();
396             final String node_id = input.getNodeId();
397             InstanceIdentifier<TransportZones> containerPath = InstanceIdentifier.create(TransportZones.class);
398             Optional<TransportZones> tZonesOptional = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, containerPath, dataBroker);
399             if (tZonesOptional.isPresent()) {
400                 TransportZones tZones = tZonesOptional.get();
401                 if (tZones.getTransportZone() == null || tZones.getTransportZone().isEmpty()) {
402                     LOG.error("No teps configured");
403                     result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, "No teps Configured").build());
404                     return result;
405                 }
406                 String transportZone = tZones.getTransportZone().get(0).getZoneName();
407                 if (tZones.getTransportZone().get(0).getSubnets() == null || tZones.getTransportZone().get(0).getSubnets().isEmpty()) {
408                     result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, "No subnets Configured").build());
409                     return result;
410                 }
411                 SubnetsKey subnetsKey = tZones.getTransportZone().get(0).getSubnets().get(0).getKey();
412                 DeviceVtepsKey deviceVtepKey = new DeviceVtepsKey(hwIp, node_id);
413                 InstanceIdentifier<DeviceVteps> path =
414                         InstanceIdentifier.builder(TransportZones.class)
415                                 .child(TransportZone.class, new TransportZoneKey(transportZone))
416                                 .child(Subnets.class, subnetsKey).child(DeviceVteps.class, deviceVtepKey).build();
417                 DeviceVteps deviceVtep = new DeviceVtepsBuilder().setKey(deviceVtepKey).setIpAddress(hwIp).setNodeId(
418                                 node_id).setTopologyId(input.getTopologyId()).build();
419                 WriteTransaction t = dataBroker.newWriteOnlyTransaction();
420                 //TO DO: add retry if it fails
421                 t.put(LogicalDatastoreType.CONFIGURATION, path, deviceVtep, true);
422
423                 ListenableFuture<Void> futureCheck = t.submit();
424                 Futures.addCallback(futureCheck, new FutureCallback<Void>() {
425
426                     @Override
427                     public void onSuccess(Void aVoid) {
428                         result.set(RpcResultBuilder.<Void>success().build());
429                     }
430
431                     @Override
432                     public void onFailure(Throwable error) {
433                         String msg = String.format("Unable to write HwVtep {} to datastore", node_id);
434                         LOG.error("Unable to write HwVtep {}, {} to datastore", node_id , hwIp);
435                         result.set(RpcResultBuilder.<Void>failed().withError(RpcError.ErrorType.APPLICATION, msg, error).build());
436                     }
437                 });
438             }
439             return result;
440         } catch (Exception e) {
441             RpcResultBuilder<java.lang.Void> resultBuilder = RpcResultBuilder.<Void>failed().
442                     withError(RpcError.ErrorType.APPLICATION, "Adding l2 Gateway to DS Failed", e);
443             return Futures.immediateFuture(resultBuilder.build());
444         }
445     }
446
447 }