2 * Copyright (c) 2015, 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.vpnservice.itm.rpc;
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.concurrent.Future;
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;
48 import org.opendaylight.yangtools.yang.common.RpcError;
49 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
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;
57 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
59 public class ItmManagerRpcService implements ItmRpcService {
61 private static final Logger LOG = LoggerFactory.getLogger(ItmManagerRpcService.class);
62 DataBroker dataBroker;
63 private IMdsalApiManager mdsalManager;
66 public void setMdsalManager(IMdsalApiManager mdsalManager) {
67 this.mdsalManager = mdsalManager;
70 IdManagerService idManagerService;
72 public ItmManagerRpcService(DataBroker dataBroker, IdManagerService idManagerService) {
73 this.dataBroker = dataBroker;
74 this.idManagerService = idManagerService;
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(
84 .child(InternalTunnel.class, new InternalTunnelKey( destinationDpn,sourceDpn));
86 Optional<InternalTunnel> tnl = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, dataBroker);
88 if( tnl != null && tnl.isPresent())
90 InternalTunnel tunnel = tnl.get();
91 GetTunnelInterfaceNameOutputBuilder output = new GetTunnelInterfaceNameOutputBuilder() ;
92 output.setInterfaceName(tunnel.getTunnelInterfaceName()) ;
93 resultBld = RpcResultBuilder.success();
94 resultBld.withResult(output.build()) ;
96 resultBld = RpcResultBuilder.failed();
99 return Futures.immediateFuture(resultBld.build());
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());
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());
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>(){
135 public void onSuccess(Void aVoid) {
136 result.set(RpcResultBuilder.<Void>success().build());
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());
147 result.set(RpcResultBuilder.<Void>success().build());
152 public Future<RpcResult<Void>> addExternalTunnelEndpoint(
153 AddExternalTunnelEndpointInput input) {
154 // TODO Auto-generated method stub
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());
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));
175 Optional<ExternalTunnel> ext = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, dataBroker);
177 if( ext != null && ext.isPresent())
179 ExternalTunnel exTunnel = ext.get();
180 GetExternalTunnelInterfaceNameOutputBuilder output = new GetExternalTunnelInterfaceNameOutputBuilder() ;
181 output.setInterfaceName(exTunnel.getTunnelInterfaceName()) ;
182 resultBld = RpcResultBuilder.success();
183 resultBld.withResult(output.build()) ;
185 resultBld = RpcResultBuilder.failed();
188 return Futures.immediateFuture(resultBld.build());
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};
199 byte Flags = (byte) 0x08;
200 vxLANHeader[0] = Flags;
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);
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 }));
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());
216 ListenableFuture<Void> installFlowResult = mdsalManager.installFlow(input.getDpnId(), terminatingServiceTableFlow);
217 Futures.addCallback(installFlowResult, new FutureCallback<Void>(){
220 public void onSuccess(Void aVoid) {
221 result.set(RpcResultBuilder.<Void>success().build());
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());
231 // result.set(RpcResultBuilder.<Void>success().build());
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 );
243 ListenableFuture<Void> installFlowResult = mdsalManager.removeFlow(input.getDpnId(), terminatingServiceTableFlow);
244 Futures.addCallback(installFlowResult, new FutureCallback<Void>(){
247 public void onSuccess(Void aVoid) {
248 result.set(RpcResultBuilder.<Void>success().build());
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());
258 //result.set(RpcResultBuilder.<Void>success().build());
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};
269 byte Flags = (byte) 0x08;
270 vxLANHeader[0] = Flags;
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);
278 mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[]{
279 BigInteger.valueOf(serviceId)}));
284 private String getFlowRef(long termSvcTable, int svcId) {
285 return new StringBuffer().append(termSvcTable).append(svcId).toString();
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()));
299 Optional<ExternalTunnel> ext = ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path1, dataBroker);
301 if( ext != null && ext.isPresent())
303 ExternalTunnel extTunnel = ext.get();
304 GetInternalOrExternalInterfaceNameOutputBuilder output = new GetInternalOrExternalInterfaceNameOutputBuilder().setInterfaceName(extTunnel.getTunnelInterfaceName() );
305 resultBld = RpcResultBuilder.success();
306 resultBld.withResult(output.build()) ;
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(
315 .child(InternalTunnel.class, new InternalTunnelKey(teps.getDPNID(),srcDpn));
317 Optional<InternalTunnel>
319 ItmUtils.read(LogicalDatastoreType.CONFIGURATION, path, dataBroker);
320 if (tnl != null && tnl.isPresent()) {
321 InternalTunnel tunnel = tnl.get();
322 GetInternalOrExternalInterfaceNameOutputBuilder
324 new GetInternalOrExternalInterfaceNameOutputBuilder()
325 .setInterfaceName(tunnel.getTunnelInterfaceName());
326 resultBld = RpcResultBuilder.success();
327 resultBld.withResult(output.build());
333 return Futures.immediateFuture(resultBld.build());
337 public Future<RpcResult<java.lang.Void>> deleteL2GwDevice(DeleteL2GwDeviceInput input) {
338 final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
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());
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());
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);
366 ListenableFuture<Void> futureCheck = t.submit();
367 Futures.addCallback(futureCheck, new FutureCallback<Void>() {
370 public void onSuccess(Void aVoid) {
371 result.set(RpcResultBuilder.<Void>success().build());
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());
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());
391 public Future<RpcResult<java.lang.Void>> addL2GwDevice(AddL2GwDeviceInput input) {
393 final SettableFuture<RpcResult<Void>> result = SettableFuture.create();
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());
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());
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);
423 ListenableFuture<Void> futureCheck = t.submit();
424 Futures.addCallback(futureCheck, new FutureCallback<Void>() {
427 public void onSuccess(Void aVoid) {
428 result.set(RpcResultBuilder.<Void>success().build());
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());
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());