2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
\r
4 * This program and the accompanying materials are made available under the
\r
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
\r
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
\r
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.adapter;
\r
11 import java.util.ArrayList;
\r
12 import java.util.List;
\r
13 import java.util.concurrent.Future;
\r
14 import java.util.stream.Collectors;
\r
16 import javax.annotation.Nonnull;
\r
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
\r
19 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
\r
20 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
\r
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
\r
22 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
\r
23 import org.opendaylight.groupbasedpolicy.renderer.vpp.api.BridgeDomainManager;
\r
24 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.ConfigCommand;
\r
25 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.TapPortCommand;
\r
26 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.VhostUserCommand;
\r
27 import org.opendaylight.groupbasedpolicy.renderer.vpp.commands.VhostUserCommand.VhostUserCommandBuilder;
\r
28 import org.opendaylight.groupbasedpolicy.renderer.vpp.iface.InterfaceManager;
\r
29 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.General.Operations;
\r
30 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.MountedDataBrokerProvider;
\r
31 import org.opendaylight.groupbasedpolicy.renderer.vpp.util.VppIidFactory;
\r
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
\r
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
\r
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.AddInterfaceToBridgeDomainInput;
\r
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.CreateInterfaceOnNodeInput;
\r
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.CreateVirtualBridgeDomainOnNodesInput;
\r
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.DelInterfaceFromBridgeDomainInput;
\r
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.DeleteInterfaceInput;
\r
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.DeleteVirtualBridgeDomainOnNodesInput;
\r
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.ExpandVirtualBridgeDomainOnNodesInput;
\r
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.bridge.domain.attributes.tunnel.type.Vlan;
\r
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_adapter.rev161201.bridge.domain.attributes.tunnel.type.Vxlan;
\r
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes.InterfaceTypeChoice;
\r
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.TapCase;
\r
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.vpp_renderer.rev160425._interface.attributes._interface.type.choice.VhostUserCase;
\r
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
\r
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VhostUserRole;
\r
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VxlanVni;
\r
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyTypesVbridgeAugment;
\r
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugment;
\r
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.TunnelTypeVlan;
\r
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev160429.network.topology.topology.tunnel.parameters.VlanNetworkParameters;
\r
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vxlan.rev160429.TunnelTypeVxlan;
\r
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vxlan.rev160429.network.topology.topology.tunnel.parameters.VxlanTunnelParameters;
\r
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
\r
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
\r
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
\r
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
\r
59 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.TopologyTypes;
\r
60 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
\r
61 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
\r
62 import org.opendaylight.yangtools.yang.common.RpcResult;
\r
63 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
\r
64 import org.slf4j.Logger;
\r
65 import org.slf4j.LoggerFactory;
\r
67 import com.google.common.base.Optional;
\r
68 import com.google.common.util.concurrent.AsyncFunction;
\r
69 import com.google.common.util.concurrent.CheckedFuture;
\r
70 import com.google.common.util.concurrent.Futures;
\r
71 import com.google.common.util.concurrent.ListenableFuture;
\r
73 public class VppRpcServiceImpl {
\r
75 private static final Logger LOG = LoggerFactory.getLogger(VppRpcServiceImpl.class);
\r
77 private final DataBroker dataBroker;
\r
78 private final BridgeDomainManager bridgeDomainManager;
\r
79 private final InterfaceManager interfaceManager;
\r
80 private final MountedDataBrokerProvider mountDataProvider;
\r
82 public VppRpcServiceImpl(@Nonnull DataBroker dataBroker, @Nonnull MountedDataBrokerProvider mountDataProvider,
\r
83 BridgeDomainManager bridgeDomainManager, InterfaceManager interfaceManager) {
\r
84 this.dataBroker = dataBroker;
\r
85 this.bridgeDomainManager = bridgeDomainManager;
\r
86 this.interfaceManager = interfaceManager;
\r
87 this.mountDataProvider = mountDataProvider;
\r
90 public Future<RpcResult<Void>> createVirtualBridgeDomain(CreateVirtualBridgeDomainOnNodesInput input) {
\r
91 if (input.getTunnelType() == null) {
\r
92 return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
\r
93 .withError(ErrorType.RPC,
\r
94 "Failed to create bridge domain" + input.getId() + "." + "Tunnel type not specified")
\r
97 List<ListenableFuture<Void>> futures = new ArrayList<>();
\r
98 List<NodeId> nodeIds = input.getPhysicalLocationRef()
\r
100 .map(locationRef -> locationRef.getNodeId())
\r
101 .collect(Collectors.toList());
\r
102 if (input.getTunnelType() instanceof Vxlan) {
\r
103 Vxlan tunnelType = (Vxlan) input.getTunnelType();
\r
104 VxlanVni vxlanVni = new VxlanVni(tunnelType.getVni().getValue());
\r
105 nodeIds.forEach(nodeId -> {
\r
106 futures.add(bridgeDomainManager.createVxlanBridgeDomainOnVppNode(input.getId(), vxlanVni, nodeId));
\r
108 } else if (input.getTunnelType() instanceof Vlan) {
\r
109 Vlan vlan = (Vlan) input.getTunnelType();
\r
110 VlanId vlanId = new VlanId(vlan.getVlanId().getValue());
\r
111 nodeIds.forEach(nodeId -> {
\r
112 futures.add(bridgeDomainManager.createVlanBridgeDomainOnVppNode(input.getId(), vlanId, nodeId));
\r
115 return Futures.transform(Futures.allAsList(futures), voidsToRpcResult());
\r
118 public Future<RpcResult<Void>> deleteVirtualBridgeDomain(DeleteVirtualBridgeDomainOnNodesInput input) {
\r
119 List<ListenableFuture<Void>> futures = new ArrayList<>();
\r
120 input.getBridgeDomainNode().forEach(nodeId -> {
\r
121 futures.add(bridgeDomainManager.removeBridgeDomainFromVppNode(input.getBridgeDomainId(), nodeId));
\r
123 return Futures.transform(Futures.allAsList(futures), voidsToRpcResult());
\r
126 public ListenableFuture<RpcResult<Void>> expandVirtualBridgeDomainOnNode(ExpandVirtualBridgeDomainOnNodesInput input) {
\r
127 List<ListenableFuture<Void>> futures = new ArrayList<>();
\r
128 ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
\r
129 InstanceIdentifier<Topology> topologyIid = VppIidFactory.getTopologyIid(new TopologyKey(new TopologyId(
\r
130 input.getBridgeDomainId())));
\r
131 return Futures.transform(rTx.read(LogicalDatastoreType.OPERATIONAL, topologyIid),
\r
132 new AsyncFunction<Optional<Topology>, RpcResult<Void>>() {
\r
135 public ListenableFuture<RpcResult<Void>> apply(Optional<Topology> optTopology) throws Exception {
\r
136 if (!optTopology.isPresent()) {
\r
138 return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
\r
141 "Failed to expand bridge domain. Bridge domain " + input.getBridgeDomainId()
\r
142 + " does not exist.")
\r
145 TopologyTypes topologyTypes = optTopology.get().getTopologyTypes();
\r
146 if (topologyTypes == null
\r
147 || topologyTypes.getAugmentation(TopologyTypesVbridgeAugment.class) == null
\r
148 || optTopology.get().getAugmentation(TopologyVbridgeAugment.class) == null) {
\r
149 return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
\r
152 "Failed to expand bridge domain. Topology " + input.getBridgeDomainId()
\r
153 + " is not bridge domain type.")
\r
156 TopologyVbridgeAugment vBridge = optTopology.get()
\r
157 .getAugmentation(TopologyVbridgeAugment.class);
\r
158 if (vBridge.getTunnelParameters() instanceof TunnelTypeVxlan) {
\r
159 VxlanTunnelParameters vxlanTunnelParams = (VxlanTunnelParameters) vBridge.getTunnelParameters();
\r
160 VxlanVni vni = vxlanTunnelParams.getVni();
\r
161 input.getBridgeDomainNode().forEach(
\r
163 futures.add(bridgeDomainManager.createVxlanBridgeDomainOnVppNode(
\r
164 input.getBridgeDomainId(), vni, nodeId));
\r
166 } else if (vBridge.getTunnelParameters() instanceof TunnelTypeVlan) {
\r
167 VlanNetworkParameters vlanTunnelParams = (VlanNetworkParameters) vBridge.getTunnelParameters();
\r
168 VlanId vlanId = vlanTunnelParams.getVlanId();
\r
169 input.getBridgeDomainNode().forEach(
\r
171 futures.add(bridgeDomainManager.createVlanBridgeDomainOnVppNode(
\r
172 input.getBridgeDomainId(), vlanId, nodeId));
\r
175 return Futures.transform(Futures.allAsList(futures), voidsToRpcResult());
\r
180 public ListenableFuture<RpcResult<Void>> createInterfaceOnNode(CreateInterfaceOnNodeInput input) {
\r
181 InterfaceTypeChoice interfaceType = input.getInterfaceTypeChoice();
\r
182 ConfigCommand ifaceCommand = null;
\r
183 if (interfaceType instanceof VhostUserCase) {
\r
184 VhostUserCommandBuilder vhostBuilder = VhostUserCommand.builder();
\r
185 vhostBuilder.setName(input.getVppInterfaceName());
\r
186 VhostUserCase vhostCase = (VhostUserCase) input.getInterfaceTypeChoice();
\r
187 vhostBuilder.setSocket(vhostCase.getSocket());
\r
188 vhostBuilder.setRole(VhostUserRole.Client);
\r
189 vhostBuilder.setDescription(input.getDescription());
\r
190 vhostBuilder.setOperation(Operations.PUT);
\r
191 ifaceCommand = vhostBuilder.build();
\r
193 if (interfaceType instanceof TapCase) {
\r
194 TapPortCommand.TapPortCommandBuilder tapBuilder = TapPortCommand.builder();
\r
195 TapCase tapIface = (TapCase) input.getInterfaceTypeChoice();
\r
196 tapBuilder.setTapName(tapIface.getName());
\r
197 tapBuilder.setPhysAddress(tapIface.getPhysicalAddress());
\r
198 tapBuilder.setInterfaceName(input.getVppInterfaceName());
\r
199 tapBuilder.setDescription(input.getDescription());
\r
200 tapBuilder.setOperation(Operations.PUT);
\r
201 ifaceCommand = tapBuilder.build();
\r
203 Optional<DataBroker> optDataBroker = mountDataProvider.getDataBrokerForMountPoint(input.getVppNodePath());
\r
204 if (!optDataBroker.isPresent()) {
\r
205 return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
\r
206 .withError(ErrorType.RPC, "Cannot find data broker for mount point " + input.getVppNodePath())
\r
209 return Futures.transform(interfaceManager.createInterfaceOnVpp(ifaceCommand, optDataBroker.get()),
\r
210 voidToRpcResult());
\r
213 public ListenableFuture<RpcResult<Void>> deleteInterfaceOnNode(DeleteInterfaceInput input) {
\r
214 return Futures.transform(readInterface(input.getVppNodePath(), input.getVppInterfaceName()),
\r
215 new AsyncFunction<Optional<Interface>, RpcResult<Void>>() {
\r
218 public ListenableFuture<RpcResult<Void>> apply(Optional<Interface> optIface) throws Exception {
\r
219 InterfaceKey iKey = new InterfaceKey(input.getVppInterfaceName());
\r
220 if (!optIface.isPresent()) {
\r
221 return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
\r
224 "Cannot delete interface " + iKey + " on node " + input.getVppNodePath()
\r
225 + ". Not found or already deleted.")
\r
228 Optional<DataBroker> dataBroker = mountDataProvider.getDataBrokerForMountPoint(input.getVppNodePath());
\r
229 WriteTransaction wTx = dataBroker.get().newWriteOnlyTransaction();
\r
230 wTx.delete(LogicalDatastoreType.CONFIGURATION, VppIidFactory.getInterfaceIID(iKey));
\r
231 return Futures.transform(wTx.submit(), voidToRpcResult());
\r
236 public ListenableFuture<RpcResult<Void>> addInterfaceToBridgeDomain(AddInterfaceToBridgeDomainInput input) {
\r
237 return Futures.transform(readInterface(input.getVppNodePath(), input.getVppInterfaceName()),
\r
238 new AsyncFunction<Optional<Interface>, RpcResult<Void>>() {
\r
241 public ListenableFuture<RpcResult<Void>> apply(Optional<Interface> optIface) throws Exception {
\r
242 InterfaceKey iKey = new InterfaceKey(input.getVppInterfaceName());
\r
243 if (!optIface.isPresent()) {
\r
244 return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
\r
247 "Cannot add interface " + iKey + " to bridge domain on node "
\r
248 + input.getVppNodePath() + ". Not found or deleted.")
\r
251 Optional<DataBroker> dataBroker = mountDataProvider.getDataBrokerForMountPoint(input.getVppNodePath());
\r
252 return Futures.transform(interfaceManager.configureInterface(dataBroker.get(), iKey,
\r
253 input.getBridgeDomainId(), null), voidToRpcResult());
\r
258 public ListenableFuture<RpcResult<Void>> delInterfaceFromBridgeDomain(DelInterfaceFromBridgeDomainInput input) {
\r
259 return Futures.transform(readInterface(input.getVppNodePath(), input.getVppInterfaceName()),
\r
260 new AsyncFunction<Optional<Interface>, RpcResult<Void>>() {
\r
263 public ListenableFuture<RpcResult<Void>> apply(Optional<Interface> optIface) throws Exception {
\r
264 if (!optIface.isPresent()) {
\r
265 return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
\r
268 "Cannot remove interface " + input.getVppInterfaceName()
\r
269 + " from bridge domain on node " + input.getVppNodePath()
\r
270 + ". Not found or deleted.")
\r
273 Optional<DataBroker> dataBroker = mountDataProvider.getDataBrokerForMountPoint(input.getVppNodePath());
\r
274 return Futures.transform(interfaceManager.removeInterfaceFromBridgeDomain(dataBroker.get(),
\r
275 optIface.get().getKey()), voidToRpcResult());
\r
280 private CheckedFuture<Optional<Interface>, ReadFailedException> readInterface(InstanceIdentifier<?> nodeIid,
\r
281 String interfaceName) {
\r
282 Optional<DataBroker> optDataBroker = mountDataProvider.getDataBrokerForMountPoint(nodeIid);
\r
283 if (!optDataBroker.isPresent()) {
\r
284 LOG.error("Cannot find data broker for node {}", nodeIid);
\r
285 return Futures.immediateCheckedFuture(Optional.absent());
\r
287 ReadOnlyTransaction rwTx = optDataBroker.get().newReadOnlyTransaction();
\r
288 InterfaceKey iKey = new InterfaceKey(interfaceName);
\r
289 InstanceIdentifier<Interface> interfaceIID = VppIidFactory.getInterfaceIID(iKey);
\r
290 CheckedFuture<Optional<Interface>, ReadFailedException> readInterface = rwTx.read(
\r
291 LogicalDatastoreType.CONFIGURATION, interfaceIID);
\r
293 return readInterface;
\r
296 private AsyncFunction<Void, RpcResult<Void>> voidToRpcResult() {
\r
297 return new AsyncFunction<Void, RpcResult<Void>>() {
\r
300 public ListenableFuture<RpcResult<Void>> apply(Void input) throws Exception {
\r
301 return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
\r
306 private AsyncFunction<List<Void>, RpcResult<Void>> voidsToRpcResult() {
\r
307 return new AsyncFunction<List<Void>, RpcResult<Void>>() {
\r
310 public ListenableFuture<RpcResult<Void>> apply(List<Void> input) throws Exception {
\r
311 return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
\r