Modify the second virtualNetworkMapping method in VNMappingUnit.
[nemo.git] / nemo-impl / src / main / java / org / opendaylight / nemo / intent / computation / VNComputationUnit.java
1 /*\r
2  * Copyright (c) 2015 Huawei, 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.nemo.intent.computation;\r
10 \r
11 import java.util.ArrayList;\r
12 import java.util.HashMap;\r
13 import java.util.HashSet;\r
14 import java.util.List;\r
15 import java.util.Map;\r
16 import java.util.Set;\r
17 import java.util.UUID;\r
18 import java.util.concurrent.ExecutionException;\r
19 \r
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
21 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;\r
22 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;\r
23 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;\r
24 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;\r
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
26 import org.opendaylight.nemo.intent.algorithm.Edge;\r
27 import org.opendaylight.nemo.intent.algorithm.RoutingAlgorithm;\r
28 import org.opendaylight.nemo.intent.algorithm.Vertex;\r
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.VirtualNetworks;\r
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.VirtualNetwork;\r
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.VirtualNetworkKey;\r
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualLinks;\r
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualNodes;\r
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualPaths;\r
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualRoutes;\r
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.links.VirtualLink;\r
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.nodes.VirtualNode;\r
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPath;\r
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPathBuilder;\r
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPathKey;\r
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRoute;\r
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRouteBuilder;\r
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRouteKey;\r
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLinkBuilder;\r
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.UserId;\r
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualLinkId;\r
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualNetworkId;\r
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualNodeId;\r
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualPathId;\r
50 import org.opendaylight.yangtools.concepts.ListenerRegistration;\r
51 import org.opendaylight.yangtools.yang.binding.DataObject;\r
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
53 import org.slf4j.Logger;\r
54 import org.slf4j.LoggerFactory;\r
55 \r
56 import com.google.common.base.Optional;\r
57 \r
58 /**\r
59  * The virtual network computation unit implements the following functions:\r
60  * (1) Maintain a user's virtual network topology information generated in\r
61  *     terms of the user's intents through subscribing from the data store.\r
62  * (2) Automatically recompute all routes of the virtual network when it\r
63  *     changed, and store or update the routes into the data store.\r
64  * (3) Provide the path computation with SLA constraints to any other modules\r
65  *     that need it.\r
66  *\r
67  * @author Zhigang Ji\r
68  */\r
69 public class VNComputationUnit implements AutoCloseable {\r
70     private static final Logger LOG = LoggerFactory.getLogger(VNComputationUnit.class);\r
71 \r
72     private final DataBroker dataBroker;\r
73 \r
74     /**\r
75      * The user id for the virtual network maintained by\r
76      * this computation unit.\r
77      */\r
78     private UserId userId;\r
79 \r
80     /**\r
81      * The routing algorithm instance.\r
82      */\r
83     private RoutingAlgorithm routingAlgorithm;\r
84 \r
85     /**\r
86      * The virtual routers in the virtual network.\r
87      */\r
88     private Set<VirtualNodeId> virtualRouters;\r
89 \r
90     /**\r
91      * The registration for the virtual node change listener.\r
92      */\r
93     private ListenerRegistration<DataChangeListener> virtualNodeChangeListenerReg;\r
94 \r
95     /**\r
96      * The registration for the virtual link change listener.\r
97      */\r
98     private ListenerRegistration<DataChangeListener> virtualLinkChangeListenerReg;\r
99 \r
100     public VNComputationUnit(DataBroker dataBroker, UserId userId) {\r
101         super();\r
102 \r
103         this.dataBroker = dataBroker;\r
104         this.userId = userId;\r
105         routingAlgorithm = new RoutingAlgorithm();\r
106         virtualRouters = new HashSet<VirtualNodeId>();\r
107 \r
108         VirtualNetworkKey virtualNetworkKey = new VirtualNetworkKey(new VirtualNetworkId(userId.getValue()));\r
109         InstanceIdentifier<VirtualNode> virtualNodeIid = InstanceIdentifier\r
110                 .builder(VirtualNetworks.class)\r
111                 .child(VirtualNetwork.class, virtualNetworkKey)\r
112                 .child(VirtualNodes.class)\r
113                 .child(VirtualNode.class)\r
114                 .build();\r
115         InstanceIdentifier<VirtualLink> virtualLinkIid = InstanceIdentifier\r
116                 .builder(VirtualNetworks.class)\r
117                 .child(VirtualNetwork.class, virtualNetworkKey)\r
118                 .child(VirtualLinks.class)\r
119                 .child(VirtualLink.class)\r
120                 .build();\r
121 \r
122         virtualNodeChangeListenerReg = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,\r
123                 virtualNodeIid, new VirtualNodeChangeListener(), DataChangeScope.BASE);\r
124         virtualLinkChangeListenerReg = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,\r
125                 virtualLinkIid, new VirtualLinkChangeListener(), DataChangeScope.BASE);\r
126 \r
127         LOG.debug("Initialized the virtual network computation unit for the user {}.", userId.getValue());\r
128 \r
129         return;\r
130     }\r
131 \r
132     public VNComputationUnit(DataBroker dataBroker, VirtualNetwork virtualNetwork) {\r
133         super();\r
134 \r
135         this.dataBroker = dataBroker;\r
136         userId = virtualNetwork.getUserId();\r
137         routingAlgorithm = new RoutingAlgorithm();\r
138         virtualRouters = new HashSet<VirtualNodeId>();\r
139 \r
140         List<VirtualNode> virtualNodes = virtualNetwork.getVirtualNodes().getVirtualNode();\r
141         Vertex vertex;\r
142 \r
143         for ( VirtualNode virtualNode : virtualNodes ) {\r
144             vertex = new Vertex(virtualNode.getNodeId().getValue());\r
145             routingAlgorithm.addVertex(vertex);\r
146 \r
147             if ( VirtualNode.NodeType.Vrouter == virtualNode.getNodeType() ) {\r
148                 virtualRouters.add(virtualNode.getNodeId());\r
149             }\r
150         }\r
151 \r
152         List<VirtualLink> virtualLinks = virtualNetwork.getVirtualLinks().getVirtualLink();\r
153 \r
154         for ( VirtualLink virtualLink : virtualLinks ) {\r
155             routingAlgorithm.addEdge(new Edge(virtualLink));\r
156         }\r
157 \r
158 //        computeRoute(virtualNetwork);\r
159 \r
160         return;\r
161     }\r
162 \r
163     /**\r
164      * Compute a shortest virtual path from the given source vertex to\r
165      * target one without any constraint.\r
166      *\r
167      * @param source The given source virtual node id.\r
168      * @param target The given target virtual node id.\r
169      * @return The virtual path if successful,or null otherwise.\r
170      */\r
171     public VirtualPath computePath(VirtualNodeId source, VirtualNodeId target) {\r
172         List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),\r
173                 routingAlgorithm.getVertex(target.getValue()));\r
174 \r
175         if ( null == edges || edges.isEmpty() ) {\r
176             return null;\r
177         }\r
178 \r
179         List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink> virtualLinks =\r
180                 new ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink>(edges.size());\r
181         org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink virtualLink;\r
182         long metric = 0;\r
183         long delay = 0;\r
184 \r
185         for ( Edge edge : edges ) {\r
186             virtualLink = new VirtualLinkBuilder()\r
187                     .setLinkId(new VirtualLinkId(edge.getId()))\r
188                     .setOrder((long) virtualLinks.size())\r
189                     .build();\r
190             virtualLinks.add(virtualLink);\r
191 \r
192             metric += edge.getMetric();\r
193 //            delay += edge.getDelay();\r
194         }\r
195 \r
196         VirtualPath virtualPath = new VirtualPathBuilder()\r
197                 .setPathId(new VirtualPathId(UUID.randomUUID().toString()))\r
198                 .setVirtualLink(virtualLinks)\r
199                 .setMetric(metric)\r
200                 .setBandwidth(0L)\r
201                 .setDelay(delay)\r
202                 .build();\r
203 \r
204         return virtualPath;\r
205     }\r
206 \r
207     /**\r
208      * Compute a shortest virtual path with the given bandwidth from the\r
209      * given source vertex to target one.\r
210      *\r
211      * @param source The given source virtual node id.\r
212      * @param target The given target virtual node id.\r
213      * @param bandwidth The given bandwidth for the virtual path.\r
214      * @return The virtual path if successful,or null otherwise.\r
215      */\r
216     public VirtualPath computePath(VirtualNodeId source, VirtualNodeId target, long bandwidth) {\r
217         List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),\r
218                 routingAlgorithm.getVertex(target.getValue()), bandwidth);\r
219 \r
220         if ( null == edges || edges.isEmpty() ) {\r
221             return null;\r
222         }\r
223 \r
224         List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink> virtualLinks =\r
225                 new ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink>(edges.size());\r
226         org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink virtualLink;\r
227         long metric = 0;\r
228         long delay = 0;\r
229 \r
230         for ( Edge edge : edges ) {\r
231             edge.setBandwidth(edge.getBandwidth() - bandwidth);\r
232             routingAlgorithm.updateEdge(edge);\r
233 \r
234             virtualLink = new VirtualLinkBuilder()\r
235                     .setLinkId(new VirtualLinkId(edge.getId()))\r
236                     .setOrder((long)virtualLinks.size())\r
237                     .build();\r
238             virtualLinks.add(virtualLink);\r
239 \r
240             metric += edge.getMetric();\r
241 //            delay += edge.getDelay();\r
242         }\r
243 \r
244         VirtualPath virtualPath = new VirtualPathBuilder()\r
245                 .setPathId(new VirtualPathId(UUID.randomUUID().toString()))\r
246                 .setVirtualLink(virtualLinks)\r
247                 .setMetric(metric)\r
248                 .setBandwidth(bandwidth)\r
249                 .setDelay(delay)\r
250                 .build();\r
251 \r
252         return virtualPath;\r
253     }\r
254 \r
255     @Override\r
256     public void close() throws Exception {\r
257         if ( null != virtualNodeChangeListenerReg ) {\r
258             virtualNodeChangeListenerReg.close();\r
259         }\r
260 \r
261         if ( null != virtualLinkChangeListenerReg ) {\r
262             virtualLinkChangeListenerReg.close();\r
263         }\r
264 \r
265         return;\r
266     }\r
267 \r
268     /**\r
269      * Compute the routes between all virtual routers in the virtual\r
270      * network, and store or update them into the data store.\r
271      */\r
272     private void computeRoute() {\r
273         Map<VirtualRouteKey, VirtualPath> routes = new HashMap<VirtualRouteKey, VirtualPath>();\r
274         VirtualPath virtualPath;\r
275 \r
276         for ( VirtualNodeId source : virtualRouters ) {\r
277             for ( VirtualNodeId target : virtualRouters ) {\r
278                 if ( !source.equals(target) ) {\r
279                     virtualPath = computePath(source, target);\r
280 \r
281                     if ( null == virtualPath ) {\r
282                         continue;\r
283                     }\r
284 \r
285                     routes.put(new VirtualRouteKey(source, target), virtualPath);\r
286                 }\r
287             }\r
288         }\r
289 \r
290         updateRoute(routes);\r
291 \r
292         return;\r
293     }\r
294 \r
295     /**\r
296      * Compute the routes between all virtual routers in the virtual\r
297      * network, and store them into the virtual network.\r
298      *\r
299      * @param virtualNetwork The virtual network to store the routes.\r
300      */\r
301     private void computeRoute(VirtualNetwork virtualNetwork) {\r
302         List<VirtualRoute> virtualRoutes = virtualNetwork.getVirtualRoutes().getVirtualRoute();\r
303         List<VirtualPath> virtualPaths = virtualNetwork.getVirtualPaths().getVirtualPath();\r
304         VirtualRoute virtualRoute;\r
305         VirtualPath virtualPath;\r
306 \r
307         for ( VirtualNodeId source : virtualRouters ) {\r
308             for ( VirtualNodeId target : virtualRouters ) {\r
309                 if ( !source.equals(target) ) {\r
310                     virtualPath = computePath(source, target);\r
311 \r
312                     if ( null == virtualPath ) {\r
313                         continue;\r
314                     }\r
315 \r
316                     virtualRoute = new VirtualRouteBuilder().setSrcNodeId(source)\r
317                             .setDestNodeId(target)\r
318                             .setPathId(virtualPath.getPathId())\r
319                             .build();\r
320 \r
321                     virtualPaths.add(virtualPath);\r
322                     virtualRoutes.add(virtualRoute);\r
323                 }\r
324             }\r
325         }\r
326 \r
327         return;\r
328     }\r
329 \r
330     /**\r
331      * Update the given routes into the data store. If the route\r
332      * already exists, remove it's old virtual path and store the\r
333      * given new one into the data store.\r
334      *\r
335      * @param routes The given routes to be updated.\r
336      */\r
337     private void updateRoute(Map<VirtualRouteKey, VirtualPath> routes) {\r
338         ReadWriteTransaction readWriteTransaction = dataBroker.newReadWriteTransaction();\r
339 \r
340         VirtualNetworkKey virtualNetworkKey = new VirtualNetworkKey(new VirtualNetworkId(userId.getValue()));\r
341         InstanceIdentifier<VirtualRoute> virtualRouteIid;\r
342         InstanceIdentifier<VirtualPath> virtualPathIid;\r
343         Optional<VirtualRoute> result;\r
344         VirtualRoute virtualRoute;\r
345 \r
346         for ( Map.Entry<VirtualRouteKey, VirtualPath> route : routes.entrySet() ) {\r
347             virtualRouteIid = InstanceIdentifier.builder(VirtualNetworks.class)\r
348                     .child(VirtualNetwork.class, virtualNetworkKey)\r
349                     .child(VirtualRoutes.class)\r
350                     .child(VirtualRoute.class, route.getKey())\r
351                     .build();\r
352 \r
353             try {\r
354                 result = readWriteTransaction.read(LogicalDatastoreType.CONFIGURATION, virtualRouteIid).get();\r
355             } catch ( InterruptedException exception ) {\r
356                 LOG.error("Can not read the virtual route from the virtual node {} to {}.",\r
357                         route.getKey().getSrcNodeId().getValue(), route.getKey().getDestNodeId().getValue());\r
358 \r
359                 continue;\r
360             } catch ( ExecutionException exception ) {\r
361                 LOG.error("Can not read the virtual route from the virtual node {} to {}.",\r
362                         route.getKey().getSrcNodeId().getValue(), route.getKey().getDestNodeId().getValue());\r
363 \r
364                 continue;\r
365             }\r
366 \r
367             if ( result.isPresent() ) {\r
368                 virtualRoute = result.get();\r
369                 virtualPathIid = InstanceIdentifier.builder(VirtualNetworks.class)\r
370                         .child(VirtualNetwork.class, virtualNetworkKey)\r
371                         .child(VirtualPaths.class)\r
372                         .child(VirtualPath.class, new VirtualPathKey(virtualRoute.getPathId()))\r
373                         .build();\r
374                 readWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, virtualPathIid);\r
375             }\r
376 \r
377             virtualPathIid = InstanceIdentifier.builder(VirtualNetworks.class)\r
378                     .child(VirtualNetwork.class, virtualNetworkKey)\r
379                     .child(VirtualPaths.class)\r
380                     .child(VirtualPath.class, route.getValue().getKey())\r
381                     .build();\r
382             readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualPathIid, route.getValue(), true);\r
383 \r
384             virtualRoute = new VirtualRouteBuilder().setSrcNodeId(route.getKey().getSrcNodeId())\r
385                     .setDestNodeId(route.getKey().getDestNodeId())\r
386                     .setPathId(route.getValue().getPathId())\r
387                     .build();\r
388             readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualRouteIid, virtualRoute, true);\r
389         }\r
390 \r
391         readWriteTransaction.submit();\r
392 \r
393         return;\r
394     }\r
395 \r
396     /**\r
397      * A listener to change events related to virtual nodes being\r
398      * added, removed or updated.\r
399      *\r
400      * @author Zhigang Ji\r
401      */\r
402     private class VirtualNodeChangeListener implements DataChangeListener {\r
403         @Override\r
404         public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {\r
405             if ( null == change ) {\r
406                 return;\r
407             }\r
408 \r
409             Map<InstanceIdentifier<?>, DataObject> createdData = change.getCreatedData();\r
410 \r
411             if ( null != createdData && !createdData.isEmpty() ) {\r
412                 VirtualNode virtualNode;\r
413                 Vertex vertex;\r
414 \r
415                 for ( DataObject dataObject : createdData.values() ) {\r
416                     if ( dataObject instanceof VirtualNode ) {\r
417                         virtualNode = (VirtualNode)dataObject;\r
418                         vertex = new Vertex(virtualNode.getNodeId().getValue());\r
419 \r
420                         routingAlgorithm.addVertex(vertex);\r
421 \r
422                         if ( VirtualNode.NodeType.Vrouter == virtualNode.getNodeType() ) {\r
423                             virtualRouters.add(virtualNode.getNodeId());\r
424                         }\r
425                     }\r
426                 }\r
427             }\r
428 \r
429             return;\r
430         }\r
431     }\r
432 \r
433     /**\r
434      * A listener to change events related to virtual links being\r
435      * added, removed or updated.\r
436      *\r
437      * @author Zhigang Ji\r
438      */\r
439     private class VirtualLinkChangeListener implements DataChangeListener {\r
440         @Override\r
441         public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {\r
442             if ( null == change ) {\r
443                 return;\r
444             }\r
445 \r
446             Map<InstanceIdentifier<?>, DataObject> createdData = change.getCreatedData();\r
447 \r
448             if ( null != createdData && !createdData.isEmpty() ) {\r
449                 boolean needRerouting = false;\r
450 \r
451                 for ( DataObject dataObject : createdData.values() ) {\r
452                     if ( dataObject instanceof VirtualLink ) {\r
453                         VirtualLink virtualLink = (VirtualLink)dataObject;\r
454                         Edge edge = new Edge(virtualLink);\r
455 \r
456                         routingAlgorithm.addEdge(edge);\r
457 \r
458                         if ( virtualRouters.contains(virtualLink.getSrcNodeId())\r
459                                 && virtualRouters.contains(virtualLink.getDestNodeId()) ) {\r
460                             needRerouting = true;\r
461                         }\r
462                     }\r
463                 }\r
464 \r
465                 if ( needRerouting ) {\r
466                     computeRoute();\r
467                 }\r
468             }\r
469 \r
470             return;\r
471         }\r
472     }\r
473 }\r