Adding nemo engine.
[nemo.git] / nemo-impl / src / main / java / org / opendaylight / nemo / intent / computation / PNComputationUnit.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 com.google.common.base.Optional;\r
12 import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
13 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;\r
14 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;\r
15 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;\r
16 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;\r
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
18 import org.opendaylight.nemo.intent.algorithm.Edge;\r
19 import org.opendaylight.nemo.intent.algorithm.RoutingAlgorithm;\r
20 import org.opendaylight.nemo.intent.algorithm.Vertex;\r
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.PhysicalNetwork;\r
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.network.PhysicalLinks;\r
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.network.PhysicalNodes;\r
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.network.PhysicalPaths;\r
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.network.physical.links.PhysicalLink;\r
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.network.physical.nodes.PhysicalNode;\r
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.network.physical.paths.PhysicalPath;\r
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.network.physical.paths.PhysicalPathBuilder;\r
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.path.instance.PhysicalLinkBuilder;\r
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.PhysicalLinkId;\r
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.PhysicalNodeId;\r
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.PhysicalPathId;\r
33 import org.opendaylight.yangtools.concepts.ListenerRegistration;\r
34 import org.opendaylight.yangtools.yang.binding.DataObject;\r
35 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
36 import org.slf4j.Logger;\r
37 import org.slf4j.LoggerFactory;\r
38 \r
39 import java.util.*;\r
40 import java.util.concurrent.ExecutionException;\r
41 \r
42 /**\r
43  * The physical network computation unit implements the following functions:\r
44  * (1) Maintain the underlying physical network topology information through\r
45  *     subscribing from the data store.\r
46  * (2) Provide the tunnel computation with SLA constraints to the virtual\r
47  *     network mapping computation unit.\r
48  *\r
49  * @author Zhigang Ji\r
50  */\r
51 public class PNComputationUnit implements AutoCloseable {\r
52     private static final Logger LOG = LoggerFactory.getLogger(PNComputationUnit.class);\r
53 \r
54     private final DataBroker dataBroker;\r
55 \r
56     /**\r
57      * The routing algorithm instance.\r
58      */\r
59     private RoutingAlgorithm routingAlgorithm;\r
60 \r
61     /**\r
62      * The registration for the physical node change listener.\r
63      */\r
64     private ListenerRegistration<DataChangeListener> physicalNodeChangeListenerReg;\r
65 \r
66     /**\r
67      * The registration for the physical link change listener.\r
68      */\r
69     private ListenerRegistration<DataChangeListener> physicalLinkChangeListenerReg;\r
70 \r
71     /**\r
72      * The registration for the physical path change listener.\r
73      */\r
74     private ListenerRegistration<DataChangeListener> physicalPathChangeListenerReg;\r
75 \r
76     public PNComputationUnit(DataBroker dataBroker) {\r
77         super();\r
78 \r
79         this.dataBroker = dataBroker;\r
80         routingAlgorithm = new RoutingAlgorithm();\r
81 \r
82         InstanceIdentifier<PhysicalNode> physicalNodeIid = InstanceIdentifier\r
83                 .builder(PhysicalNetwork.class)\r
84                 .child(PhysicalNodes.class)\r
85                 .child(PhysicalNode.class)\r
86                 .build();\r
87         InstanceIdentifier<PhysicalLink> physicalLinkIid = InstanceIdentifier\r
88                 .builder(PhysicalNetwork.class)\r
89                 .child(PhysicalLinks.class)\r
90                 .child(PhysicalLink.class)\r
91                 .build();\r
92         InstanceIdentifier<PhysicalPath> physicalPathIid = InstanceIdentifier\r
93                 .builder(PhysicalNetwork.class)\r
94                 .child(PhysicalPaths.class)\r
95                 .child(PhysicalPath.class)\r
96                 .build();\r
97 \r
98         physicalNodeChangeListenerReg = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,\r
99                 physicalNodeIid, new PhysicalNodeChangeListener(), DataChangeScope.BASE);\r
100         physicalLinkChangeListenerReg = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,\r
101                 physicalLinkIid, new PhysicalLinkChangeListener(), DataChangeScope.BASE);\r
102         physicalPathChangeListenerReg = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,\r
103                 physicalPathIid, new PhysicalPathChangeListener(), DataChangeScope.BASE);\r
104 \r
105         ReadOnlyTransaction readOnlyTransaction = dataBroker.newReadOnlyTransaction();\r
106 \r
107         InstanceIdentifier<PhysicalNodes> physicalNodesIid = InstanceIdentifier\r
108                 .builder(PhysicalNetwork.class)\r
109                 .child(PhysicalNodes.class)\r
110                 .build();\r
111         Optional<PhysicalNodes> result;\r
112 \r
113         try {\r
114             result = readOnlyTransaction.read(LogicalDatastoreType.OPERATIONAL, physicalNodesIid).get();\r
115         } catch ( InterruptedException | ExecutionException exception ) {\r
116             throw new RuntimeException("Can not read the physical nodes.");\r
117         }\r
118 \r
119         if ( result.isPresent() ) {\r
120             PhysicalNodes physicalNodes = result.get();\r
121             Vertex vertex;\r
122 \r
123             for ( PhysicalNode physicalNode : physicalNodes.getPhysicalNode() ) {\r
124                 vertex = new Vertex(physicalNode.getNodeId().getValue());\r
125                 routingAlgorithm.addVertex(vertex);\r
126             }\r
127         }\r
128 \r
129         InstanceIdentifier<PhysicalLinks> physicalLinksIid = InstanceIdentifier\r
130                 .builder(PhysicalNetwork.class)\r
131                 .child(PhysicalLinks.class)\r
132                 .build();\r
133         Optional<PhysicalLinks> result1;\r
134 \r
135         try {\r
136             result1 = readOnlyTransaction.read(LogicalDatastoreType.OPERATIONAL, physicalLinksIid).get();\r
137         } catch ( InterruptedException | ExecutionException exception ) {\r
138             throw new RuntimeException("Can not read the physical links.");\r
139         }\r
140 \r
141         if ( result1.isPresent() ) {\r
142             PhysicalLinks physicalLinks = result1.get();\r
143             Edge edge;\r
144 \r
145             for ( PhysicalLink physicalLink : physicalLinks.getPhysicalLink() ) {\r
146                 edge = new Edge(physicalLink.getLinkId().getValue(), physicalLink.getSrcNodeId().getValue(),\r
147                         physicalLink.getDestNodeId().getValue(), physicalLink.getMetric(),\r
148                         physicalLink.getBandwidth());\r
149                 routingAlgorithm.addEdge(edge);\r
150             }\r
151         }\r
152 \r
153         LOG.debug("Initialized the physical network computation unit.");\r
154 \r
155         return;\r
156     }\r
157 \r
158     /**\r
159      * Compute a shortest physical path from the given source vertex to\r
160      * target one without any constraint.\r
161      *\r
162      * @param source The given source physical node id.\r
163      * @param target The given target physical node id.\r
164      * @return The physical path if successful,or null otherwise.\r
165      */\r
166     protected PhysicalPath computePath(PhysicalNodeId source, PhysicalNodeId target) {\r
167         List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),\r
168                 routingAlgorithm.getVertex(target.getValue()));\r
169 \r
170         if ( null == edges || edges.isEmpty() ) {\r
171             return null;\r
172         }\r
173 \r
174         List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.path.instance.PhysicalLink> physicalLinks =\r
175                 new ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.path.instance.PhysicalLink>(edges.size());\r
176         org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.path.instance.PhysicalLink physicalLink;\r
177         long metric = 0;\r
178         long delay = 0;\r
179 \r
180         for ( Edge edge : edges ) {\r
181             physicalLink = new PhysicalLinkBuilder()\r
182                     .setLinkId(new PhysicalLinkId(edge.getId()))\r
183                     .setOrder((long) physicalLinks.size())\r
184                     .build();\r
185             physicalLinks.add(physicalLink);\r
186 \r
187             metric += edge.getMetric();\r
188 //            delay += edge.getDelay();\r
189         }\r
190 \r
191         PhysicalPath physicalPath = new PhysicalPathBuilder()\r
192                 .setPathId(new PhysicalPathId(UUID.randomUUID().toString()))\r
193                 .setPhysicalLink(physicalLinks)\r
194                 .setMetric(metric)\r
195                 .setBandwidth(0L)\r
196                 .setDelay(delay)\r
197                 .build();\r
198 \r
199         return physicalPath;\r
200     }\r
201 \r
202     /**\r
203      * Compute a shortest physical path with the given bandwidth from the\r
204      * given source vertex to target one.\r
205      *\r
206      * @param source The given source physical node id.\r
207      * @param target The given target physical node id.\r
208      * @param bandwidth The given bandwidth for the physical path.\r
209      * @return The physical path if successful,or null otherwise.\r
210      */\r
211     protected PhysicalPath computePath(PhysicalNodeId source, PhysicalNodeId target, long bandwidth) {\r
212         List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),\r
213                 routingAlgorithm.getVertex(target.getValue()), bandwidth);\r
214 \r
215         if ( null == edges || edges.isEmpty() ) {\r
216             return null;\r
217         }\r
218 \r
219         List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.path.instance.PhysicalLink> physicalLinks =\r
220                 new ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.path.instance.PhysicalLink>(edges.size());\r
221         org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.path.instance.PhysicalLink physicalLink;\r
222         long metric = 0;\r
223         long delay = 0;\r
224 \r
225         for ( Edge edge : edges ) {\r
226             edge.setBandwidth(edge.getBandwidth() - bandwidth);\r
227             routingAlgorithm.updateEdge(edge);\r
228 \r
229             physicalLink = new PhysicalLinkBuilder()\r
230                     .setLinkId(new PhysicalLinkId(edge.getId()))\r
231                     .setOrder((long) physicalLinks.size())\r
232                     .build();\r
233             physicalLinks.add(physicalLink);\r
234 \r
235             metric += edge.getMetric();\r
236 //            delay += edge.getDelay();\r
237         }\r
238 \r
239         PhysicalPath physicalPath = new PhysicalPathBuilder()\r
240                 .setPathId(new PhysicalPathId(UUID.randomUUID().toString()))\r
241                 .setPhysicalLink(physicalLinks)\r
242                 .setMetric(metric)\r
243                 .setBandwidth(bandwidth)\r
244                 .setDelay(delay)\r
245                 .build();\r
246 \r
247         return physicalPath;\r
248     }\r
249 \r
250     @Override\r
251     public void close() throws Exception {\r
252         if ( null != physicalNodeChangeListenerReg ) {\r
253             physicalNodeChangeListenerReg.close();\r
254         }\r
255 \r
256         if ( null != physicalLinkChangeListenerReg ) {\r
257             physicalLinkChangeListenerReg.close();\r
258         }\r
259 \r
260         if ( null != physicalPathChangeListenerReg ) {\r
261             physicalPathChangeListenerReg.close();\r
262         }\r
263 \r
264         return;\r
265     }\r
266 \r
267     /**\r
268      * A listener to change events related to physical nodes being\r
269      * added, removed or updated.\r
270      *\r
271      * @author Zhigang Ji\r
272      */\r
273     private class PhysicalNodeChangeListener implements DataChangeListener {\r
274         @Override\r
275         public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {\r
276             if ( null == change ) {\r
277                 return;\r
278             }\r
279 \r
280             Map<InstanceIdentifier<?>, DataObject> createdData = change.getCreatedData();\r
281 \r
282             if ( null != createdData && !createdData.isEmpty() ) {\r
283                 PhysicalNode physicalNode;\r
284                 Vertex vertex;\r
285 \r
286                 for ( DataObject dataObject : createdData.values() ) {\r
287                     if ( dataObject instanceof PhysicalNode ) {\r
288                         physicalNode = (PhysicalNode)dataObject;\r
289                         vertex = new Vertex(physicalNode.getNodeId().getValue());\r
290 \r
291                         routingAlgorithm.addVertex(vertex);\r
292                     }\r
293                 }\r
294             }\r
295 \r
296             Map<InstanceIdentifier<?>, DataObject> originalData = change.getOriginalData();\r
297             Set<InstanceIdentifier<?>> removedPaths = change.getRemovedPaths();\r
298 \r
299             if ( null != removedPaths && !removedPaths.isEmpty() ) {\r
300                 DataObject dataObject;\r
301 \r
302                 for ( InstanceIdentifier<?> instanceId : removedPaths ) {\r
303                     dataObject = originalData.get(instanceId);\r
304 \r
305                     if ( null != dataObject && dataObject instanceof PhysicalNode ) {\r
306                         routingAlgorithm.removeVertex(((PhysicalNode)dataObject).getNodeId().getValue());\r
307                     }\r
308                 }\r
309             }\r
310 \r
311             return;\r
312         }\r
313     }\r
314 \r
315     /**\r
316      * A listener to change events related to physical links being\r
317      * added, removed or updated.\r
318      *\r
319      * @author Zhigang Ji\r
320      */\r
321     private class PhysicalLinkChangeListener implements DataChangeListener {\r
322         @Override\r
323         public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {\r
324             if ( null == change ) {\r
325                 return;\r
326             }\r
327 \r
328             Map<InstanceIdentifier<?>, DataObject> createdData = change.getCreatedData();\r
329 \r
330             if ( null != createdData && !createdData.isEmpty() ) {\r
331                 PhysicalLink physicalLink;\r
332                 Edge edge;\r
333 \r
334                 for ( DataObject dataObject : createdData.values() ) {\r
335                     if ( dataObject instanceof PhysicalLink ) {\r
336                         physicalLink = (PhysicalLink)dataObject;\r
337                         edge = new Edge(physicalLink.getLinkId().getValue(), physicalLink.getSrcNodeId().getValue(),\r
338                                 physicalLink.getDestNodeId().getValue(), physicalLink.getMetric(),\r
339                                 physicalLink.getBandwidth());\r
340 \r
341                         routingAlgorithm.addEdge(edge);\r
342                     }\r
343                 }\r
344             }\r
345 \r
346             Map<InstanceIdentifier<?>, DataObject> updatedData = change.getUpdatedData();\r
347 \r
348             if ( null != updatedData && !updatedData.isEmpty() ) {\r
349                 PhysicalLink physicalLink;\r
350                 Edge edge;\r
351 \r
352                 for ( DataObject dataObject : updatedData.values() ) {\r
353                     if ( dataObject instanceof PhysicalLink ) {\r
354                         physicalLink = (PhysicalLink)dataObject;\r
355                         edge = new Edge(physicalLink.getLinkId().getValue(), physicalLink.getSrcNodeId().getValue(),\r
356                                 physicalLink.getDestNodeId().getValue(), physicalLink.getMetric(),\r
357                                 physicalLink.getBandwidth());\r
358 \r
359                         routingAlgorithm.updateEdge(edge);\r
360                     }\r
361                 }\r
362             }\r
363 \r
364             Map<InstanceIdentifier<?>, DataObject> originalData = change.getOriginalData();\r
365             Set<InstanceIdentifier<?>> removedPaths = change.getRemovedPaths();\r
366 \r
367             if ( null != removedPaths && !removedPaths.isEmpty() ) {\r
368                 DataObject dataObject;\r
369 \r
370                 for ( InstanceIdentifier<?> instanceId : removedPaths ) {\r
371                     dataObject = originalData.get(instanceId);\r
372 \r
373                     if ( null != dataObject && dataObject instanceof PhysicalLink ) {\r
374                         routingAlgorithm.removeEdge(((PhysicalLink)dataObject).getLinkId().getValue());\r
375                     }\r
376                 }\r
377             }\r
378 \r
379             return;\r
380         }\r
381     }\r
382 \r
383     /**\r
384      * A listener to change events related to physical paths being\r
385      * added, removed or updated.\r
386      *\r
387      * @author Zhigang Ji\r
388      */\r
389     private class PhysicalPathChangeListener implements DataChangeListener {\r
390         @Override\r
391         public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {\r
392             if ( null == change ) {\r
393                 return;\r
394             }\r
395 \r
396             Map<InstanceIdentifier<?>, DataObject> originalData = change.getOriginalData();\r
397             Set<InstanceIdentifier<?>> removedPaths = change.getRemovedPaths();\r
398 \r
399             if ( null != removedPaths && !removedPaths.isEmpty() ) {\r
400                 DataObject dataObject;\r
401                 PhysicalPath physicalPath;\r
402                 long bandwidth;\r
403                 List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.path.instance.PhysicalLink> physicalLinks;\r
404                 Edge edge;\r
405 \r
406                 for ( InstanceIdentifier<?> instanceId : removedPaths ) {\r
407                     dataObject = originalData.get(instanceId);\r
408 \r
409                     if ( null != dataObject && dataObject instanceof PhysicalPath ) {\r
410                         physicalPath = (PhysicalPath)dataObject;\r
411                         bandwidth = physicalPath.getBandwidth();\r
412 \r
413                         if ( 0 < bandwidth ) {\r
414                             physicalLinks = physicalPath.getPhysicalLink();\r
415 \r
416                             if ( null != physicalLinks && !physicalLinks.isEmpty() ) {\r
417                                 for ( org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.physical.network.rev151010.physical.path.instance.PhysicalLink\r
418                                         physicalLink : physicalLinks ) {\r
419                                     edge = routingAlgorithm.getEdge(physicalLink.getLinkId().getValue());\r
420 \r
421                                     if ( null != edge ) {\r
422                                         edge.setBandwidth(edge.getBandwidth() + bandwidth);\r
423                                         routingAlgorithm.updateEdge(edge);\r
424                                     }\r
425                                 }\r
426                             }\r
427                         }\r
428                     }\r
429                 }\r
430             }\r
431 \r
432             return;\r
433         }\r
434     }\r
435 }\r