Introducing RPCs for remote calls to VPP
[groupbasedpolicy.git] / renderers / vpp / src / main / java / org / opendaylight / groupbasedpolicy / renderer / vpp / external / VppRpcServiceImpl.java
1 /*\r
2  * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.\r
3  *\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
7  */\r
8 \r
9 package org.opendaylight.groupbasedpolicy.renderer.vpp.adapter;\r
10 \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
15 \r
16 import javax.annotation.Nonnull;\r
17 \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
66 \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
72 \r
73 public class VppRpcServiceImpl {\r
74 \r
75     private static final Logger LOG = LoggerFactory.getLogger(VppRpcServiceImpl.class);\r
76 \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
81 \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
88     }\r
89 \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
95                 .build());\r
96         }\r
97         List<ListenableFuture<Void>> futures = new ArrayList<>();\r
98         List<NodeId> nodeIds = input.getPhysicalLocationRef()\r
99             .stream()\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
107             });\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
113             });\r
114         }\r
115         return Futures.transform(Futures.allAsList(futures), voidsToRpcResult());\r
116     }\r
117 \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
122         });\r
123         return Futures.transform(Futures.allAsList(futures), voidsToRpcResult());\r
124     }\r
125 \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
133 \r
134                     @Override\r
135                     public ListenableFuture<RpcResult<Void>> apply(Optional<Topology> optTopology) throws Exception {\r
136                         if (!optTopology.isPresent()) {\r
137 \r
138                             return Futures.immediateFuture(RpcResultBuilder.<Void>failed()\r
139                                 .withError(\r
140                                         ErrorType.RPC,\r
141                                         "Failed to expand bridge domain. Bridge domain " + input.getBridgeDomainId()\r
142                                                 + " does not exist.")\r
143                                 .build());\r
144                         }\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
150                                 .withError(\r
151                                         ErrorType.RPC,\r
152                                         "Failed to expand bridge domain. Topology " + input.getBridgeDomainId()\r
153                                                 + " is not bridge domain type.")\r
154                                 .build());\r
155                         }\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
162                                     nodeId -> {\r
163                                         futures.add(bridgeDomainManager.createVxlanBridgeDomainOnVppNode(\r
164                                                 input.getBridgeDomainId(), vni, nodeId));\r
165                                     });\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
170                                     nodeId -> {\r
171                                         futures.add(bridgeDomainManager.createVlanBridgeDomainOnVppNode(\r
172                                                 input.getBridgeDomainId(), vlanId, nodeId));\r
173                                     });\r
174                         }\r
175                         return Futures.transform(Futures.allAsList(futures), voidsToRpcResult());\r
176                     }\r
177                 });\r
178     }\r
179 \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
192         }\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
202         }\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
207                 .build());\r
208         }\r
209         return Futures.transform(interfaceManager.createInterfaceOnVpp(ifaceCommand, optDataBroker.get()),\r
210                 voidToRpcResult());\r
211     }\r
212 \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
216 \r
217                     @Override\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
222                                 .withError(\r
223                                         ErrorType.RPC,\r
224                                         "Cannot delete interface " + iKey + " on node " + input.getVppNodePath()\r
225                                                 + ". Not found or already deleted.")\r
226                                 .build());\r
227                         }\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
232                     }\r
233                 });\r
234     }\r
235 \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
239 \r
240                     @Override\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
245                                 .withError(\r
246                                         ErrorType.RPC,\r
247                                         "Cannot add interface " + iKey + " to bridge domain on node "\r
248                                                 + input.getVppNodePath() + ". Not found or deleted.")\r
249                                 .build());\r
250                         }\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
254                     }\r
255                 });\r
256     }\r
257 \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
261 \r
262                     @Override\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
266                                 .withError(\r
267                                         ErrorType.RPC,\r
268                                         "Cannot remove interface " + input.getVppInterfaceName()\r
269                                                 + " from bridge domain on node " + input.getVppNodePath()\r
270                                                 + ". Not found or deleted.")\r
271                                 .build());\r
272                         }\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
276                     }\r
277                 });\r
278     }\r
279 \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
286         }\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
292         rwTx.close();\r
293         return readInterface;\r
294     }\r
295 \r
296     private AsyncFunction<Void, RpcResult<Void>> voidToRpcResult() {\r
297         return new AsyncFunction<Void, RpcResult<Void>>() {\r
298 \r
299             @Override\r
300             public ListenableFuture<RpcResult<Void>> apply(Void input) throws Exception {\r
301                 return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());\r
302             }\r
303         };\r
304     }\r
305 \r
306     private AsyncFunction<List<Void>, RpcResult<Void>> voidsToRpcResult() {\r
307         return new AsyncFunction<List<Void>, RpcResult<Void>>() {\r
308 \r
309             @Override\r
310             public ListenableFuture<RpcResult<Void>> apply(List<Void> input) throws Exception {\r
311                 return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());\r
312             }\r
313         };\r
314     }\r
315 }\r