Migrate to odlparent 2.0.0
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / adapter / VppRpcServiceImpl.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. 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
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.adapter;
10
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.concurrent.Future;
14 import java.util.stream.Collectors;
15
16 import javax.annotation.Nonnull;
17
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.l2.types.rev130827.VlanId;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.VhostUserRole;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev170607.VxlanVni;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.topology.rev160129.TopologyVbridgeAugment;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vlan.rev170327.network.topology.topology.tunnel.parameters.VlanNetworkParameters;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vbridge.tunnel.vxlan.rev170327.network.topology.topology.tunnel.parameters.VxlanTunnelParameters;
54 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
55 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
56 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
58 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
61 import org.opendaylight.yangtools.yang.common.RpcResult;
62 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66 import com.google.common.base.Optional;
67 import com.google.common.util.concurrent.AsyncFunction;
68 import com.google.common.util.concurrent.CheckedFuture;
69 import com.google.common.util.concurrent.Futures;
70 import com.google.common.util.concurrent.ListenableFuture;
71
72 public class VppRpcServiceImpl implements VppAdapterService, AutoCloseable {
73
74     private static final Logger LOG = LoggerFactory.getLogger(VppRpcServiceImpl.class);
75
76     private final DataBroker dataBroker;
77     private final BridgeDomainManager bridgeDomainManager;
78     private final InterfaceManager interfaceManager;
79     private final MountedDataBrokerProvider mountDataProvider;
80
81     public VppRpcServiceImpl(@Nonnull DataBroker dataBroker, @Nonnull VppRenderer renderer) {
82         this.dataBroker = dataBroker;
83         this.bridgeDomainManager = renderer.getBridgeDomainManager();
84         this.interfaceManager = renderer.getInterfaceManager();
85         this.mountDataProvider = renderer.getMountedDataBroker();
86     }
87
88     public Future<RpcResult<Void>> createVirtualBridgeDomainOnNodes(CreateVirtualBridgeDomainOnNodesInput input) {
89         LOG.info("Processing a remote call for creating bridge domain {}", input.getId());
90         if (input.getTunnelType() == null) {
91             return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
92                 .withError(ErrorType.RPC,
93                         "Failed to create bridge domain" + input.getId() + "." + "Tunnel type not specified")
94                 .build());
95         }
96         List<ListenableFuture<Void>> futures = new ArrayList<>();
97         List<NodeId> nodeIds = (input.getPhysicalLocationRef() == null) ? new ArrayList<>() : input
98             .getPhysicalLocationRef().stream().map(locationRef -> locationRef.getNodeId()).collect(Collectors.toList());
99         LOG.trace("Corresponding nodes for bridge-domain {}", input.getPhysicalLocationRef());
100         if (input.getTunnelType() instanceof Vxlan) {
101             LOG.trace("Detected VXLAN type for bridge domain {}", input.getId());
102             Vxlan tunnelType = (Vxlan) input.getTunnelType();
103             VxlanVni vxlanVni = new VxlanVni(tunnelType.getVni().getValue());
104             nodeIds.forEach(nodeId -> {
105                 futures.add(bridgeDomainManager.createVxlanBridgeDomainOnVppNode(input.getId(), vxlanVni, nodeId));
106             });
107         } else if (input.getTunnelType() instanceof Vlan) {
108             LOG.trace("Detected VLAN type for bridge domain {}", input.getId());
109             Vlan vlan = (Vlan) input.getTunnelType();
110             VlanId vlanId = new VlanId(vlan.getVlanId().getValue());
111             nodeIds.forEach(nodeId -> {
112                 futures.add(bridgeDomainManager.createVlanBridgeDomainOnVppNode(input.getId(), vlanId, nodeId));
113             });
114         }
115         return Futures.transformAsync(Futures.allAsList(futures), voidsToRpcResult());
116     }
117
118     public Future<RpcResult<Void>> deleteVirtualBridgeDomainFromNodes(DeleteVirtualBridgeDomainFromNodesInput input) {
119         LOG.info("Processing a remote call for removing bridge domain {}", input.getBridgeDomainId());
120         List<ListenableFuture<Void>> futures = new ArrayList<>();
121         input.getBridgeDomainNode().forEach(nodeId -> {
122             futures.add(bridgeDomainManager.removeBridgeDomainFromVppNode(input.getBridgeDomainId(), nodeId));
123         });
124         return Futures.transformAsync(Futures.allAsList(futures), voidsToRpcResult());
125     }
126
127     public ListenableFuture<RpcResult<Void>> cloneVirtualBridgeDomainOnNodes(CloneVirtualBridgeDomainOnNodesInput input) {
128         LOG.info("Processing a remote call for clonning  bridge domain {}", input.getBridgeDomainId());
129         List<ListenableFuture<Void>> futures = new ArrayList<>();
130         ReadOnlyTransaction rTx = dataBroker.newReadOnlyTransaction();
131         InstanceIdentifier<Topology> topologyIid = VppIidFactory.getTopologyIid(new TopologyKey(new TopologyId(
132                 input.getBridgeDomainId())));
133         return Futures.transformAsync(rTx.read(LogicalDatastoreType.CONFIGURATION, topologyIid),
134                 new AsyncFunction<Optional<Topology>, RpcResult<Void>>() {
135
136                     @Override
137                     public ListenableFuture<RpcResult<Void>> apply(Optional<Topology> optTopology) throws Exception {
138                         if (!optTopology.isPresent()) {
139
140                             return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
141                                 .withError(
142                                         ErrorType.RPC,
143                                         "Failed to clone bridge domain. Bridge domain " + input.getBridgeDomainId()
144                                                 + " does not exist.")
145                                 .build());
146                         }
147                         TopologyVbridgeAugment vBridgeAug = optTopology.get().getAugmentation(TopologyVbridgeAugment.class);
148                         if (vBridgeAug == null) {
149                             return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
150                                 .withError(
151                                         ErrorType.RPC,
152                                         "Failed to clone bridge domain. Topology " + input.getBridgeDomainId()
153                                                 + " is not bridge domain type.")
154                                 .build());
155                         }
156                         if (vBridgeAug.getTunnelParameters() instanceof VxlanTunnelParameters) {
157                             LOG.debug("Clonning VXLAN type bridge domain {} on nodes {}", input.getBridgeDomainId(),
158                                     input.getBridgeDomainNode());
159                             VxlanTunnelParameters vxlanTunnelParams = (VxlanTunnelParameters) vBridgeAug.getTunnelParameters();
160                             VxlanVni vni = vxlanTunnelParams.getVni();
161                             input.getBridgeDomainNode().forEach(
162                                     nodeId -> {
163                                         futures.add(bridgeDomainManager.createVxlanBridgeDomainOnVppNode(
164                                                 input.getBridgeDomainId(), vni, nodeId));
165                                     });
166                         } else if (vBridgeAug.getTunnelParameters() instanceof VlanNetworkParameters) {
167                             LOG.debug("Clonning VLAN type bridge domain {} on nodes {}", input.getBridgeDomainId(),
168                                     input.getBridgeDomainNode());
169                             VlanNetworkParameters vlanTunnelParams = (VlanNetworkParameters) vBridgeAug.getTunnelParameters();
170                             VlanId vlanId = vlanTunnelParams.getVlanId();
171                             input.getBridgeDomainNode().forEach(
172                                     nodeId -> {
173                                         futures.add(bridgeDomainManager.createVlanBridgeDomainOnVppNode(
174                                                 input.getBridgeDomainId(), vlanId, nodeId));
175                                     });
176                         }
177                         return Futures.transformAsync(Futures.allAsList(futures), voidsToRpcResult());
178                     }
179                 });
180     }
181
182     public ListenableFuture<RpcResult<Void>> createInterfaceOnNode(CreateInterfaceOnNodeInput input) {
183         LOG.info("Processing a remote call for creating interface {} on node {}", input.getVppInterfaceName(),
184                 input.getVppNodeId());
185         InterfaceTypeChoice interfaceType = input.getInterfaceTypeChoice();
186         ConfigCommand ifaceCommand = null;
187         if (interfaceType instanceof VhostUserCase) {
188             VhostUserCommandBuilder vhostBuilder = VhostUserCommand.builder();
189             vhostBuilder.setName(input.getVppInterfaceName());
190             VhostUserCase vhostCase = (VhostUserCase) input.getInterfaceTypeChoice();
191             vhostBuilder.setSocket(vhostCase.getSocket());
192             vhostBuilder.setRole(VhostUserRole.Client);
193             vhostBuilder.setDescription(input.getDescription());
194             vhostBuilder.setOperation(Operations.PUT);
195             ifaceCommand = vhostBuilder.build();
196         }
197         if (interfaceType instanceof TapCase) {
198             TapPortCommand.TapPortCommandBuilder tapBuilder = TapPortCommand.builder();
199             TapCase tapIface = (TapCase) input.getInterfaceTypeChoice();
200             tapBuilder.setTapName(tapIface.getName());
201             tapBuilder.setPhysAddress(tapIface.getPhysicalAddress());
202             tapBuilder.setInterfaceName(input.getVppInterfaceName());
203             tapBuilder.setDescription(input.getDescription());
204             tapBuilder.setOperation(Operations.PUT);
205             ifaceCommand = tapBuilder.build();
206         }
207         InstanceIdentifier<Node> vppNodeIid = VppIidFactory.getNetconfNodeIid(input.getVppNodeId());
208         Optional<DataBroker> optDataBroker = mountDataProvider.getDataBrokerForMountPoint(vppNodeIid);
209         if (!optDataBroker.isPresent()) {
210             return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
211                 .withError(ErrorType.RPC, "Cannot find data broker for mount point " + vppNodeIid)
212                 .build());
213         }
214         return Futures.transformAsync(interfaceManager.createInterfaceOnVpp(ifaceCommand, optDataBroker.get()),
215                 voidToRpcResult());
216     }
217
218     public ListenableFuture<RpcResult<Void>> deleteInterfaceFromNode(DeleteInterfaceFromNodeInput input) {
219         LOG.info("Processing a remote call for removing interface {} from node {}", input.getVppInterfaceName(),
220                 input.getVppNodeId());
221         InstanceIdentifier<Node> vppNodeIid = VppIidFactory.getNetconfNodeIid(input.getVppNodeId());
222         return Futures.transformAsync(readInterface(vppNodeIid, input.getVppInterfaceName()),
223                 new AsyncFunction<Optional<Interface>, RpcResult<Void>>() {
224
225                     @Override
226                     public ListenableFuture<RpcResult<Void>> apply(Optional<Interface> optIface) throws Exception {
227                         InterfaceKey iKey = new InterfaceKey(input.getVppInterfaceName());
228                         if (!optIface.isPresent()) {
229                             return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
230                                 .withError(
231                                         ErrorType.RPC,
232                                         "Cannot delete interface " + iKey + " on node " + vppNodeIid
233                                                 + ". Not found or already deleted.")
234                                 .build());
235                         }
236                         Optional<DataBroker> dataBroker = mountDataProvider.getDataBrokerForMountPoint(vppNodeIid);
237                         WriteTransaction wTx = dataBroker.get().newWriteOnlyTransaction();
238                         wTx.delete(LogicalDatastoreType.CONFIGURATION, VppIidFactory.getInterfaceIID(iKey));
239                         return Futures.transformAsync(wTx.submit(), voidToRpcResult());
240                     }
241                 });
242     }
243
244     public ListenableFuture<RpcResult<Void>> addInterfaceToBridgeDomain(AddInterfaceToBridgeDomainInput input) {
245         LOG.info("Processing a remote call for adding interface {} to bridge domain {}", input.getVppInterfaceName(),
246                 input.getBridgeDomainId());
247         InstanceIdentifier<Node> vppNodeIid = VppIidFactory.getNetconfNodeIid(input.getVppNodeId());
248         return Futures.transformAsync(readInterface(vppNodeIid, input.getVppInterfaceName()),
249                 new AsyncFunction<Optional<Interface>, RpcResult<Void>>() {
250
251                     @Override
252                     public ListenableFuture<RpcResult<Void>> apply(Optional<Interface> optIface) throws Exception {
253                         InterfaceKey iKey = new InterfaceKey(input.getVppInterfaceName());
254                         if (!optIface.isPresent()) {
255                             return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
256                                 .withError(
257                                         ErrorType.RPC,
258                                         "Cannot add interface " + iKey + " to bridge domain on node "
259                                                 + vppNodeIid + ". Not found or deleted.")
260                                 .build());
261                         }
262                         Optional<DataBroker> dataBroker = mountDataProvider.getDataBrokerForMountPoint(vppNodeIid);
263                         return Futures.transformAsync(interfaceManager.configureInterface(dataBroker.get(), iKey,
264                                 input.getBridgeDomainId(), null), voidToRpcResult());
265                     }
266                 });
267     }
268
269     public ListenableFuture<RpcResult<Void>> delInterfaceFromBridgeDomain(DelInterfaceFromBridgeDomainInput input) {
270         LOG.info("Processing a remote call for removing interface {} from bridge domain.", input.getVppInterfaceName());
271         InstanceIdentifier<Node> vppNodeIid = VppIidFactory.getNetconfNodeIid(input.getVppNodeId());
272         return Futures.transformAsync(readInterface(vppNodeIid, input.getVppInterfaceName()),
273                 new AsyncFunction<Optional<Interface>, RpcResult<Void>>() {
274
275                     @Override
276                     public ListenableFuture<RpcResult<Void>> apply(Optional<Interface> optIface) throws Exception {
277                         if (!optIface.isPresent()) {
278                             return Futures.immediateFuture(RpcResultBuilder.<Void>failed()
279                                 .withError(
280                                         ErrorType.RPC,
281                                         "Cannot remove interface " + input.getVppInterfaceName()
282                                                 + " from bridge domain on node " + vppNodeIid
283                                                 + ". Not found or deleted.")
284                                 .build());
285                         }
286                         Optional<DataBroker> dataBroker = mountDataProvider.getDataBrokerForMountPoint(vppNodeIid);
287                         return Futures.transformAsync(interfaceManager.removeInterfaceFromBridgeDomain(dataBroker.get(),
288                                 optIface.get().getKey()), voidToRpcResult());
289                     }
290                 });
291     }
292
293     private CheckedFuture<Optional<Interface>, ReadFailedException> readInterface(InstanceIdentifier<?> nodeIid,
294             String interfaceName) {
295         Optional<DataBroker> optDataBroker = mountDataProvider.getDataBrokerForMountPoint(nodeIid);
296         if (!optDataBroker.isPresent()) {
297             LOG.error("Cannot find data broker for node {}", nodeIid);
298             return Futures.immediateCheckedFuture(Optional.absent());
299         }
300         ReadOnlyTransaction rwTx = optDataBroker.get().newReadOnlyTransaction();
301         InterfaceKey iKey = new InterfaceKey(interfaceName);
302         InstanceIdentifier<Interface> interfaceIID = VppIidFactory.getInterfaceIID(iKey);
303         CheckedFuture<Optional<Interface>, ReadFailedException> readInterface = rwTx.read(
304                 LogicalDatastoreType.CONFIGURATION, interfaceIID);
305         rwTx.close();
306         return readInterface;
307     }
308
309     private AsyncFunction<Void, RpcResult<Void>> voidToRpcResult() {
310         return new AsyncFunction<Void, RpcResult<Void>>() {
311
312             @Override
313             public ListenableFuture<RpcResult<Void>> apply(Void input) throws Exception {
314                 return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
315             }
316         };
317     }
318
319     private AsyncFunction<List<Void>, RpcResult<Void>> voidsToRpcResult() {
320         return new AsyncFunction<List<Void>, RpcResult<Void>>() {
321
322             @Override
323             public ListenableFuture<RpcResult<Void>> apply(List<Void> input) throws Exception {
324                 return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
325             }
326         };
327     }
328
329     @Override
330     public void close() throws Exception {
331         // NOOP
332     }
333 }