+/*\r
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.groupbasedpolicy.renderer.vpp.adapter;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.concurrent.Future;\r
+import java.util.stream.Collectors;\r
+\r
+import javax.annotation.Nonnull;\r
+\r
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;\r
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;\r
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.api.BridgeDomainManager;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.ConfigCommand;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.TapPortCommand;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.VhostUserCommand;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.VhostUserCommand.VhostUserCommandBuilder;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General.Operations;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;\r
+import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;\r
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.AddInterfaceToBridgeDomainInput;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.CreateInterfaceOnNodeInput;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.CreateVirtualBridgeDomainOnNodesInput;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.DelInterfaceFromBridgeDomainInput;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.DeleteInterfaceInput;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.DeleteVirtualBridgeDomainOnNodesInput;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.ExpandVirtualBridgeDomainOnNodesInput;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.bridge.domain.attributes.tunnel.type.Vlan;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.bridge.domain.attributes.tunnel.type.Vxlan;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes.InterfaceTypeChoice;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.TapCase;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.VhostUserCase;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VhostUserRole;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VxlanVni;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyTypesVbridgeAugment;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugment;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.TunnelTypeVlan;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.network.topology.topology.tunnel.parameters.VlanNetworkParameters;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vxlan.rev160429.TunnelTypeVxlan;\r
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vxlan.rev160429.network.topology.topology.tunnel.parameters.VxlanTunnelParameters;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;\r
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypes;\r
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;\r
+import org.opendaylight.yangtools.yang.common.RpcResult;\r
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
+\r
+import com.google.common.base.Optional;\r
+import com.google.common.util.concurrent.AsyncFunction;\r
+import com.google.common.util.concurrent.CheckedFuture;\r
+import com.google.common.util.concurrent.Futures;\r
+import com.google.common.util.concurrent.ListenableFuture;\r
+\r
+public class VppRpcServiceImpl {\r
+\r
+ private static final Logger LOG = LoggerFactory.getLogger(VppRpcServiceImpl.class);\r
+\r
+ private final DataBroker dataBroker;\r
+ private final BridgeDomainManager bridgeDomainManager;\r
+ private final InterfaceManager interfaceManager;\r
+ private final MountedDataBrokerProvider mountDataProvider;\r
+\r
+ public VppRpcServiceImpl(@Nonnull DataBroker dataBroker, @Nonnull MountedDataBrokerProvider mountDataProvider,\r
+ BridgeDomainManager bridgeDomainManager, InterfaceManager interfaceManager) {\r
+ this.dataBroker = dataBroker;\r
+ this.bridgeDomainManager = bridgeDomainManager;\r
+ this.interfaceManager = interfaceManager;\r
+ this.mountDataProvider = mountDataProvider;\r
+ }\r
+\r
+ public Future<RpcResult<Void>> createVirtualBridgeDomain(CreateVirtualBridgeDomainOnNodesInput input) {\r
+ if (input.getTunnelType() == null) {\r
+ return Futures.immediateFuture(RpcResultBuilder.<Void>failed()\r
+ .withError(ErrorType.RPC,\r
+ "Failed to create bridge domain" + input.getId() + "." + "Tunnel type not specified")\r
+ .build());\r
+ }\r
+ List<ListenableFuture<Void>> futures = new ArrayList<>();\r
+ List<NodeId> nodeIds = input.getPhysicalLocationRef()\r
+ .stream()\r
+ .map(locationRef -> locationRef.getNodeId())\r
+ .collect(Collectors.toList());\r
+ if (input.getTunnelType() instanceof Vxlan) {\r
+ Vxlan tunnelType = (Vxlan) input.getTunnelType();\r
+ VxlanVni vxlanVni = new VxlanVni(tunnelType.getVni().getValue());\r
+ nodeIds.forEach(nodeId -> {\r
+ futures.add(bridgeDomainManager.createVxlanBridgeDomainOnVppNode(input.getId(), vxlanVni, nodeId));\r
+ });\r
+ } else if (input.getTunnelType() instanceof Vlan) {\r
+ Vlan vlan = (Vlan) input.getTunnelType();\r
+ VlanId vlanId = new VlanId(vlan.getVlanId().getValue());\r
+ nodeIds.forEach(nodeId -> {\r
+ futures.add(bridgeDomainManager.createVlanBridgeDomainOnVppNode(input.getId(), vlanId, nodeId));\r
+ });\r
+ }\r
+ return Futures.transform(Futures.allAsList(futures), voidsToRpcResult());\r
+ }\r
+\r
+ public Future<RpcResult<Void>> deleteVirtualBridgeDomain(DeleteVirtualBridgeDomainOnNodesInput input) {\r
+ List<ListenableFuture<Void>> futures = new ArrayList<>();\r
+ input.getBridgeDomainNode().forEach(nodeId -> {\r
+ futures.add(bridgeDomainManager.removeBridgeDomainFromVppNode(input.getBridgeDomainId(), nodeId));\r
+ });\r
+ return Futures.transform(Futures.allAsList(futures), voidsToRpcResult());\r
+ }\r
+\r
+ public ListenableFuture<RpcResult<Void>> expandVirtualBridgeDomainOnNode(ExpandVirtualBridgeDomainOnNodesInput input) {\r
+ List<ListenableFuture<Void>> futures = new ArrayList<>();\r
+ ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();\r
+ InstanceIdentifier<Topology> topologyIid = VppIidFactory.getTopologyIid(new TopologyKey(new TopologyId(\r
+ input.getBridgeDomainId())));\r
+ return Futures.transform(rTx.read(LogicalDatastoreType.OPERATIONAL, topologyIid),\r
+ new AsyncFunction<Optional<Topology>, RpcResult<Void>>() {\r
+\r
+ @Override\r
+ public ListenableFuture<RpcResult<Void>> apply(Optional<Topology> optTopology) throws Exception {\r
+ if (!optTopology.isPresent()) {\r
+\r
+ return Futures.immediateFuture(RpcResultBuilder.<Void>failed()\r
+ .withError(\r
+ ErrorType.RPC,\r
+ "Failed to expand bridge domain. Bridge domain " + input.getBridgeDomainId()\r
+ + " does not exist.")\r
+ .build());\r
+ }\r
+ TopologyTypes topologyTypes = optTopology.get().getTopologyTypes();\r
+ if (topologyTypes == null\r
+ || topologyTypes.getAugmentation(TopologyTypesVbridgeAugment.class) == null\r
+ || optTopology.get().getAugmentation(TopologyVbridgeAugment.class) == null) {\r
+ return Futures.immediateFuture(RpcResultBuilder.<Void>failed()\r
+ .withError(\r
+ ErrorType.RPC,\r
+ "Failed to expand bridge domain. Topology " + input.getBridgeDomainId()\r
+ + " is not bridge domain type.")\r
+ .build());\r
+ }\r
+ TopologyVbridgeAugment vBridge = optTopology.get()\r
+ .getAugmentation(TopologyVbridgeAugment.class);\r
+ if (vBridge.getTunnelParameters() instanceof TunnelTypeVxlan) {\r
+ VxlanTunnelParameters vxlanTunnelParams = (VxlanTunnelParameters) vBridge.getTunnelParameters();\r
+ VxlanVni vni = vxlanTunnelParams.getVni();\r
+ input.getBridgeDomainNode().forEach(\r
+ nodeId -> {\r
+ futures.add(bridgeDomainManager.createVxlanBridgeDomainOnVppNode(\r
+ input.getBridgeDomainId(), vni, nodeId));\r
+ });\r
+ } else if (vBridge.getTunnelParameters() instanceof TunnelTypeVlan) {\r
+ VlanNetworkParameters vlanTunnelParams = (VlanNetworkParameters) vBridge.getTunnelParameters();\r
+ VlanId vlanId = vlanTunnelParams.getVlanId();\r
+ input.getBridgeDomainNode().forEach(\r
+ nodeId -> {\r
+ futures.add(bridgeDomainManager.createVlanBridgeDomainOnVppNode(\r
+ input.getBridgeDomainId(), vlanId, nodeId));\r
+ });\r
+ }\r
+ return Futures.transform(Futures.allAsList(futures), voidsToRpcResult());\r
+ }\r
+ });\r
+ }\r
+\r
+ public ListenableFuture<RpcResult<Void>> createInterfaceOnNode(CreateInterfaceOnNodeInput input) {\r
+ InterfaceTypeChoice interfaceType = input.getInterfaceTypeChoice();\r
+ ConfigCommand ifaceCommand = null;\r
+ if (interfaceType instanceof VhostUserCase) {\r
+ VhostUserCommandBuilder vhostBuilder = VhostUserCommand.builder();\r
+ vhostBuilder.setName(input.getVppInterfaceName());\r
+ VhostUserCase vhostCase = (VhostUserCase) input.getInterfaceTypeChoice();\r
+ vhostBuilder.setSocket(vhostCase.getSocket());\r
+ vhostBuilder.setRole(VhostUserRole.Client);\r
+ vhostBuilder.setDescription(input.getDescription());\r
+ vhostBuilder.setOperation(Operations.PUT);\r
+ ifaceCommand = vhostBuilder.build();\r
+ }\r
+ if (interfaceType instanceof TapCase) {\r
+ TapPortCommand.TapPortCommandBuilder tapBuilder = TapPortCommand.builder();\r
+ TapCase tapIface = (TapCase) input.getInterfaceTypeChoice();\r
+ tapBuilder.setTapName(tapIface.getName());\r
+ tapBuilder.setPhysAddress(tapIface.getPhysicalAddress());\r
+ tapBuilder.setInterfaceName(input.getVppInterfaceName());\r
+ tapBuilder.setDescription(input.getDescription());\r
+ tapBuilder.setOperation(Operations.PUT);\r
+ ifaceCommand = tapBuilder.build();\r
+ }\r
+ Optional<DataBroker> optDataBroker = mountDataProvider.getDataBrokerForMountPoint(input.getVppNodePath());\r
+ if (!optDataBroker.isPresent()) {\r
+ return Futures.immediateFuture(RpcResultBuilder.<Void>failed()\r
+ .withError(ErrorType.RPC, "Cannot find data broker for mount point " + input.getVppNodePath())\r
+ .build());\r
+ }\r
+ return Futures.transform(interfaceManager.createInterfaceOnVpp(ifaceCommand, optDataBroker.get()),\r
+ voidToRpcResult());\r
+ }\r
+\r
+ public ListenableFuture<RpcResult<Void>> deleteInterfaceOnNode(DeleteInterfaceInput input) {\r
+ return Futures.transform(readInterface(input.getVppNodePath(), input.getVppInterfaceName()),\r
+ new AsyncFunction<Optional<Interface>, RpcResult<Void>>() {\r
+\r
+ @Override\r
+ public ListenableFuture<RpcResult<Void>> apply(Optional<Interface> optIface) throws Exception {\r
+ InterfaceKey iKey = new InterfaceKey(input.getVppInterfaceName());\r
+ if (!optIface.isPresent()) {\r
+ return Futures.immediateFuture(RpcResultBuilder.<Void>failed()\r
+ .withError(\r
+ ErrorType.RPC,\r
+ "Cannot delete interface " + iKey + " on node " + input.getVppNodePath()\r
+ + ". Not found or already deleted.")\r
+ .build());\r
+ }\r
+ Optional<DataBroker> dataBroker = mountDataProvider.getDataBrokerForMountPoint(input.getVppNodePath());\r
+ WriteTransaction wTx = dataBroker.get().newWriteOnlyTransaction();\r
+ wTx.delete(LogicalDatastoreType.CONFIGURATION, VppIidFactory.getInterfaceIID(iKey));\r
+ return Futures.transform(wTx.submit(), voidToRpcResult());\r
+ }\r
+ });\r
+ }\r
+\r
+ public ListenableFuture<RpcResult<Void>> addInterfaceToBridgeDomain(AddInterfaceToBridgeDomainInput input) {\r
+ return Futures.transform(readInterface(input.getVppNodePath(), input.getVppInterfaceName()),\r
+ new AsyncFunction<Optional<Interface>, RpcResult<Void>>() {\r
+\r
+ @Override\r
+ public ListenableFuture<RpcResult<Void>> apply(Optional<Interface> optIface) throws Exception {\r
+ InterfaceKey iKey = new InterfaceKey(input.getVppInterfaceName());\r
+ if (!optIface.isPresent()) {\r
+ return Futures.immediateFuture(RpcResultBuilder.<Void>failed()\r
+ .withError(\r
+ ErrorType.RPC,\r
+ "Cannot add interface " + iKey + " to bridge domain on node "\r
+ + input.getVppNodePath() + ". Not found or deleted.")\r
+ .build());\r
+ }\r
+ Optional<DataBroker> dataBroker = mountDataProvider.getDataBrokerForMountPoint(input.getVppNodePath());\r
+ return Futures.transform(interfaceManager.configureInterface(dataBroker.get(), iKey,\r
+ input.getBridgeDomainId(), null), voidToRpcResult());\r
+ }\r
+ });\r
+ }\r
+\r
+ public ListenableFuture<RpcResult<Void>> delInterfaceFromBridgeDomain(DelInterfaceFromBridgeDomainInput input) {\r
+ return Futures.transform(readInterface(input.getVppNodePath(), input.getVppInterfaceName()),\r
+ new AsyncFunction<Optional<Interface>, RpcResult<Void>>() {\r
+\r
+ @Override\r
+ public ListenableFuture<RpcResult<Void>> apply(Optional<Interface> optIface) throws Exception {\r
+ if (!optIface.isPresent()) {\r
+ return Futures.immediateFuture(RpcResultBuilder.<Void>failed()\r
+ .withError(\r
+ ErrorType.RPC,\r
+ "Cannot remove interface " + input.getVppInterfaceName()\r
+ + " from bridge domain on node " + input.getVppNodePath()\r
+ + ". Not found or deleted.")\r
+ .build());\r
+ }\r
+ Optional<DataBroker> dataBroker = mountDataProvider.getDataBrokerForMountPoint(input.getVppNodePath());\r
+ return Futures.transform(interfaceManager.removeInterfaceFromBridgeDomain(dataBroker.get(),\r
+ optIface.get().getKey()), voidToRpcResult());\r
+ }\r
+ });\r
+ }\r
+\r
+ private CheckedFuture<Optional<Interface>, ReadFailedException> readInterface(InstanceIdentifier<?> nodeIid,\r
+ String interfaceName) {\r
+ Optional<DataBroker> optDataBroker = mountDataProvider.getDataBrokerForMountPoint(nodeIid);\r
+ if (!optDataBroker.isPresent()) {\r
+ LOG.error("Cannot find data broker for node {}", nodeIid);\r
+ return Futures.immediateCheckedFuture(Optional.absent());\r
+ }\r
+ ReadOnlyTransaction rwTx = optDataBroker.get().newReadOnlyTransaction();\r
+ InterfaceKey iKey = new InterfaceKey(interfaceName);\r
+ InstanceIdentifier<Interface> interfaceIID = VppIidFactory.getInterfaceIID(iKey);\r
+ CheckedFuture<Optional<Interface>, ReadFailedException> readInterface = rwTx.read(\r
+ LogicalDatastoreType.CONFIGURATION, interfaceIID);\r
+ rwTx.close();\r
+ return readInterface;\r
+ }\r
+\r
+ private AsyncFunction<Void, RpcResult<Void>> voidToRpcResult() {\r
+ return new AsyncFunction<Void, RpcResult<Void>>() {\r
+\r
+ @Override\r
+ public ListenableFuture<RpcResult<Void>> apply(Void input) throws Exception {\r
+ return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());\r
+ }\r
+ };\r
+ }\r
+\r
+ private AsyncFunction<List<Void>, RpcResult<Void>> voidsToRpcResult() {\r
+ return new AsyncFunction<List<Void>, RpcResult<Void>>() {\r
+\r
+ @Override\r
+ public ListenableFuture<RpcResult<Void>> apply(List<Void> input) throws Exception {\r
+ return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());\r
+ }\r
+ };\r
+ }\r
+}\r