2 * Copyright (c) 2016 Cisco Systems, Inc. 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
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.adapter;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.concurrent.Future;
14 import java.util.stream.Collectors;
16 import javax.annotation.Nonnull;
18 import org.opendaylight.controller.config.yang.config.vpp_provider.impl.VppRenderer;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
21 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.api.BridgeDomainManager;
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.interfaces.ConfigCommand;
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.TapPortCommand;
27 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.VhostUserCommand;
28 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.VhostUserCommand.VhostUserCommandBuilder;
29 import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;
30 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General.Operations;
31 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
32 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.AddInterfaceToBridgeDomainInput;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.CreateInterfaceOnNodeInput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.CreateVirtualBridgeDomainOnNodesInput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.DelInterfaceFromBridgeDomainInput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.DeleteInterfaceFromNodeInput;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.DeleteVirtualBridgeDomainFromNodesInput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.CloneVirtualBridgeDomainOnNodesInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.VppAdapterService;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.bridge.domain.attributes.tunnel.type.Vlan;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.bridge.domain.attributes.tunnel.type.Vxlan;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes.InterfaceTypeChoice;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.TapCase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.VhostUserCase;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425.bridge.domain.base.attributes.PhysicalLocationRef;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.VhostUserRole;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.VxlanVni;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugment;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev170327.network.topology.topology.tunnel.parameters.VlanNetworkParameters;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vxlan.rev170327.network.topology.topology.tunnel.parameters.VxlanTunnelParameters;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
59 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
60 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
61 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
62 import org.opendaylight.yangtools.yang.common.RpcResult;
63 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
67 import com.google.common.base.Optional;
68 import com.google.common.util.concurrent.AsyncFunction;
69 import com.google.common.util.concurrent.CheckedFuture;
70 import com.google.common.util.concurrent.Futures;
71 import com.google.common.util.concurrent.ListenableFuture;
72 import com.google.common.util.concurrent.MoreExecutors;
74 public class VppRpcServiceImpl implements VppAdapterService, AutoCloseable {
76 private static final Logger LOG = LoggerFactory.getLogger(VppRpcServiceImpl.class);
78 private final DataBroker dataBroker;
79 private final BridgeDomainManager bridgeDomainManager;
80 private final InterfaceManager interfaceManager;
81 private final MountedDataBrokerProvider mountDataProvider;
83 public VppRpcServiceImpl(@Nonnull DataBroker dataBroker, @Nonnull VppRenderer renderer) {
84 this.dataBroker = dataBroker;
85 this.bridgeDomainManager = renderer.getBridgeDomainManager();
86 this.interfaceManager = renderer.getInterfaceManager();
87 this.mountDataProvider = renderer.getMountedDataBroker();
90 public Future<RpcResult<Void>> createVirtualBridgeDomainOnNodes(CreateVirtualBridgeDomainOnNodesInput input) {
91 LOG.info("Processing a remote call for creating bridge domain {}", input.getId());
92 if (input.getTunnelType() == null) {
93 return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
94 .withError(ErrorType.RPC,
95 "Failed to create bridge domain" + input.getId() + "." + "Tunnel type not specified")
98 List<ListenableFuture<Void>> futures = new ArrayList<>();
99 List<NodeId> nodeIds = (input.getPhysicalLocationRef() == null) ? new ArrayList<>() : input
100 .getPhysicalLocationRef().stream().map(locationRef -> locationRef.getNodeId()).collect(Collectors.toList());
101 LOG.trace("Corresponding nodes for bridge-domain {}", input.getPhysicalLocationRef());
102 if (input.getTunnelType() instanceof Vxlan) {
103 LOG.trace("Detected VXLAN type for bridge domain {}", input.getId());
104 Vxlan tunnelType = (Vxlan) input.getTunnelType();
105 VxlanVni vxlanVni = new VxlanVni(tunnelType.getVni().getValue());
106 nodeIds.forEach(nodeId -> {
107 futures.add(bridgeDomainManager.createVxlanBridgeDomainOnVppNode(input.getId(), vxlanVni, nodeId));
109 } else if (input.getTunnelType() instanceof Vlan) {
110 LOG.trace("Detected VLAN type for bridge domain {}", input.getId());
111 Vlan vlan = (Vlan) input.getTunnelType();
112 VlanId vlanId = new VlanId(vlan.getVlanId().getValue());
113 nodeIds.forEach(nodeId -> {
114 futures.add(bridgeDomainManager.createVlanBridgeDomainOnVppNode(input.getId(), vlanId, nodeId));
117 return Futures.transformAsync(Futures.allAsList(futures), voidsToRpcResult(), MoreExecutors.directExecutor());
120 public Future<RpcResult<Void>> deleteVirtualBridgeDomainFromNodes(DeleteVirtualBridgeDomainFromNodesInput input) {
121 LOG.info("Processing a remote call for removing bridge domain {}", input.getBridgeDomainId());
122 List<ListenableFuture<Void>> futures = new ArrayList<>();
123 input.getBridgeDomainNode().forEach(nodeId -> {
124 futures.add(bridgeDomainManager.removeBridgeDomainFromVppNode(input.getBridgeDomainId(), nodeId));
126 return Futures.transformAsync(Futures.allAsList(futures), voidsToRpcResult(), MoreExecutors.directExecutor());
129 public ListenableFuture<RpcResult<Void>> cloneVirtualBridgeDomainOnNodes(CloneVirtualBridgeDomainOnNodesInput input) {
130 LOG.info("Processing a remote call for clonning bridge domain {}", input.getBridgeDomainId());
131 List<ListenableFuture<Void>> futures = new ArrayList<>();
132 ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
133 InstanceIdentifier<Topology> topologyIid = VppIidFactory.getTopologyIid(new TopologyKey(new TopologyId(
134 input.getBridgeDomainId())));
135 return Futures.transformAsync(rTx.read(LogicalDatastoreType.CONFIGURATION, topologyIid),
136 new AsyncFunction<Optional<Topology>, RpcResult<Void>>() {
139 public ListenableFuture<RpcResult<Void>> apply(Optional<Topology> optTopology) throws Exception {
140 if (!optTopology.isPresent()) {
142 return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
145 "Failed to clone bridge domain. Bridge domain " + input.getBridgeDomainId()
146 + " does not exist.")
149 TopologyVbridgeAugment vBridgeAug = optTopology.get().getAugmentation(TopologyVbridgeAugment.class);
150 if (vBridgeAug == null) {
151 return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
154 "Failed to clone bridge domain. Topology " + input.getBridgeDomainId()
155 + " is not bridge domain type.")
158 if (vBridgeAug.getTunnelParameters() instanceof VxlanTunnelParameters) {
159 LOG.debug("Clonning VXLAN type bridge domain {} on nodes {}", input.getBridgeDomainId(),
160 input.getBridgeDomainNode());
161 VxlanTunnelParameters vxlanTunnelParams = (VxlanTunnelParameters) vBridgeAug.getTunnelParameters();
162 VxlanVni vni = vxlanTunnelParams.getVni();
163 input.getBridgeDomainNode().forEach(
165 futures.add(bridgeDomainManager.createVxlanBridgeDomainOnVppNode(
166 input.getBridgeDomainId(), vni, nodeId));
168 } else if (vBridgeAug.getTunnelParameters() instanceof VlanNetworkParameters) {
169 LOG.debug("Clonning VLAN type bridge domain {} on nodes {}", input.getBridgeDomainId(),
170 input.getBridgeDomainNode());
171 VlanNetworkParameters vlanTunnelParams = (VlanNetworkParameters) vBridgeAug.getTunnelParameters();
172 VlanId vlanId = vlanTunnelParams.getVlanId();
173 input.getBridgeDomainNode().forEach(
175 futures.add(bridgeDomainManager.createVlanBridgeDomainOnVppNode(
176 input.getBridgeDomainId(), vlanId, nodeId));
179 return Futures.transformAsync(Futures.allAsList(futures), voidsToRpcResult(), MoreExecutors.directExecutor());
181 }, MoreExecutors.directExecutor());
184 public ListenableFuture<RpcResult<Void>> createInterfaceOnNode(CreateInterfaceOnNodeInput input) {
185 LOG.info("Processing a remote call for creating interface {} on node {}", input.getVppInterfaceName(),
186 input.getVppNodeId());
187 InterfaceTypeChoice interfaceType = input.getInterfaceTypeChoice();
188 ConfigCommand ifaceCommand = null;
189 if (interfaceType instanceof VhostUserCase) {
190 VhostUserCommandBuilder vhostBuilder = VhostUserCommand.builder();
191 vhostBuilder.setName(input.getVppInterfaceName());
192 VhostUserCase vhostCase = (VhostUserCase) input.getInterfaceTypeChoice();
193 vhostBuilder.setSocket(vhostCase.getSocket());
194 vhostBuilder.setRole(VhostUserRole.Client);
195 vhostBuilder.setDescription(input.getDescription());
196 vhostBuilder.setOperation(Operations.PUT);
197 ifaceCommand = vhostBuilder.build();
199 if (interfaceType instanceof TapCase) {
200 TapPortCommand.TapPortCommandBuilder tapBuilder = TapPortCommand.builder();
201 TapCase tapIface = (TapCase) input.getInterfaceTypeChoice();
202 tapBuilder.setTapName(tapIface.getName());
203 tapBuilder.setPhysAddress(tapIface.getPhysicalAddress());
204 tapBuilder.setInterfaceName(input.getVppInterfaceName());
205 tapBuilder.setDescription(input.getDescription());
206 tapBuilder.setOperation(Operations.PUT);
207 ifaceCommand = tapBuilder.build();
209 InstanceIdentifier<Node> vppNodeIid = VppIidFactory.getNetconfNodeIid(input.getVppNodeId());
210 return Futures.transformAsync(interfaceManager.createInterfaceOnVpp(ifaceCommand, vppNodeIid),
211 voidToRpcResult(), MoreExecutors.directExecutor());
214 public ListenableFuture<RpcResult<Void>> deleteInterfaceFromNode(DeleteInterfaceFromNodeInput input) {
215 LOG.info("Processing a remote call for removing interface {} from node {}", input.getVppInterfaceName(),
216 input.getVppNodeId());
217 InstanceIdentifier<Node> vppNodeIid = VppIidFactory.getNetconfNodeIid(input.getVppNodeId());
218 return Futures.transformAsync(readInterface(vppNodeIid, input.getVppInterfaceName()),
219 new AsyncFunction<Optional<Interface>, RpcResult<Void>>() {
222 public ListenableFuture<RpcResult<Void>> apply(Optional<Interface> optIface) throws Exception {
223 InterfaceKey iKey = new InterfaceKey(input.getVppInterfaceName());
224 if (!optIface.isPresent()) {
225 return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
228 "Cannot delete interface " + iKey + " on node " + vppNodeIid
229 + ". Not found or already deleted.")
232 Optional<DataBroker> dataBroker = mountDataProvider.resolveDataBrokerForMountPoint(vppNodeIid);
233 WriteTransaction wTx = dataBroker.get().newWriteOnlyTransaction();
234 wTx.delete(LogicalDatastoreType.CONFIGURATION, VppIidFactory.getInterfaceIID(iKey));
235 return Futures.transformAsync(wTx.submit(), voidToRpcResult(), MoreExecutors.directExecutor());
237 }, MoreExecutors.directExecutor());
240 public ListenableFuture<RpcResult<Void>> addInterfaceToBridgeDomain(AddInterfaceToBridgeDomainInput input) {
241 LOG.info("Processing a remote call for adding interface {} to bridge domain {}", input.getVppInterfaceName(),
242 input.getBridgeDomainId());
243 InstanceIdentifier<Node> vppNodeIid = VppIidFactory.getNetconfNodeIid(input.getVppNodeId());
244 return Futures.transformAsync(readInterface(vppNodeIid, input.getVppInterfaceName()),
245 new AsyncFunction<Optional<Interface>, RpcResult<Void>>() {
248 public ListenableFuture<RpcResult<Void>> apply(Optional<Interface> optIface) throws Exception {
249 InterfaceKey iKey = new InterfaceKey(input.getVppInterfaceName());
250 if (!optIface.isPresent()) {
251 return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
254 "Cannot add interface " + iKey + " to bridge domain on node "
255 + vppNodeIid + ". Not found or deleted.")
258 return Futures.transformAsync(interfaceManager.configureInterface(vppNodeIid, iKey,
259 input.getBridgeDomainId(), null), voidToRpcResult(), MoreExecutors.directExecutor());
261 }, MoreExecutors.directExecutor());
264 public ListenableFuture<RpcResult<Void>> delInterfaceFromBridgeDomain(DelInterfaceFromBridgeDomainInput input) {
265 LOG.info("Processing a remote call for removing interface {} from bridge domain.", input.getVppInterfaceName());
266 InstanceIdentifier<Node> vppNodeIid = VppIidFactory.getNetconfNodeIid(input.getVppNodeId());
267 return Futures.transformAsync(readInterface(vppNodeIid, input.getVppInterfaceName()),
268 new AsyncFunction<Optional<Interface>, RpcResult<Void>>() {
271 public ListenableFuture<RpcResult<Void>> apply(Optional<Interface> optIface) throws Exception {
272 if (!optIface.isPresent()) {
273 return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
276 "Cannot remove interface " + input.getVppInterfaceName()
277 + " from bridge domain on node " + vppNodeIid
278 + ". Not found or deleted.")
281 return Futures.transformAsync(interfaceManager.removeInterfaceFromBridgeDomain(vppNodeIid,
282 optIface.get().getKey()), voidToRpcResult(), MoreExecutors.directExecutor());
284 }, MoreExecutors.directExecutor());
287 private CheckedFuture<Optional<Interface>, ReadFailedException> readInterface(InstanceIdentifier<Node> nodeIid,
288 String interfaceName) {
289 Optional<DataBroker> optDataBroker = mountDataProvider.resolveDataBrokerForMountPoint(nodeIid);
290 if (!optDataBroker.isPresent()) {
291 LOG.error("Cannot find data broker for node {}", nodeIid);
292 return Futures.immediateCheckedFuture(Optional.absent());
294 ReadOnlyTransaction rwTx = optDataBroker.get().newReadOnlyTransaction();
295 InterfaceKey iKey = new InterfaceKey(interfaceName);
296 InstanceIdentifier<Interface> interfaceIID = VppIidFactory.getInterfaceIID(iKey);
297 CheckedFuture<Optional<Interface>, ReadFailedException> readInterface = rwTx.read(
298 LogicalDatastoreType.CONFIGURATION, interfaceIID);
300 return readInterface;
303 private AsyncFunction<Void, RpcResult<Void>> voidToRpcResult() {
304 return new AsyncFunction<Void, RpcResult<Void>>() {
307 public ListenableFuture<RpcResult<Void>> apply(Void input) throws Exception {
308 return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
313 private AsyncFunction<List<Void>, RpcResult<Void>> voidsToRpcResult() {
314 return new AsyncFunction<List<Void>, RpcResult<Void>>() {
317 public ListenableFuture<RpcResult<Void>> apply(List<Void> input) throws Exception {
318 return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
324 public void close() throws Exception {