2 * Copyright (c) 2015 Huawei, 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.nemo.intent.computation;
\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
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
56 import com.google.common.base.Optional;
\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
67 * @author Zhigang Ji
\r
69 public class VNComputationUnit implements AutoCloseable {
\r
70 private static final Logger LOG = LoggerFactory.getLogger(VNComputationUnit.class);
\r
72 private final DataBroker dataBroker;
\r
75 * The user id for the virtual network maintained by
\r
76 * this computation unit.
\r
78 private UserId userId;
\r
81 * The routing algorithm instance.
\r
83 private RoutingAlgorithm routingAlgorithm;
\r
86 * The virtual routers in the virtual network.
\r
88 private Set<VirtualNodeId> virtualRouters;
\r
91 * The registration for the virtual node change listener.
\r
93 private ListenerRegistration<DataChangeListener> virtualNodeChangeListenerReg;
\r
96 * The registration for the virtual link change listener.
\r
98 private ListenerRegistration<DataChangeListener> virtualLinkChangeListenerReg;
\r
100 public VNComputationUnit(DataBroker dataBroker, UserId userId) {
\r
103 this.dataBroker = dataBroker;
\r
104 this.userId = userId;
\r
105 routingAlgorithm = new RoutingAlgorithm();
\r
106 virtualRouters = new HashSet<VirtualNodeId>();
\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
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
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
127 LOG.debug("Initialized the virtual network computation unit for the user {}.", userId.getValue());
\r
132 public VNComputationUnit(DataBroker dataBroker, VirtualNetwork virtualNetwork) {
\r
135 this.dataBroker = dataBroker;
\r
136 userId = virtualNetwork.getUserId();
\r
137 routingAlgorithm = new RoutingAlgorithm();
\r
138 virtualRouters = new HashSet<VirtualNodeId>();
\r
140 List<VirtualNode> virtualNodes = virtualNetwork.getVirtualNodes().getVirtualNode();
\r
143 for ( VirtualNode virtualNode : virtualNodes ) {
\r
144 vertex = new Vertex(virtualNode.getNodeId().getValue());
\r
145 routingAlgorithm.addVertex(vertex);
\r
147 if ( VirtualNode.NodeType.Vrouter == virtualNode.getNodeType() ) {
\r
148 virtualRouters.add(virtualNode.getNodeId());
\r
152 List<VirtualLink> virtualLinks = virtualNetwork.getVirtualLinks().getVirtualLink();
\r
155 for ( VirtualLink virtualLink : virtualLinks ) {
\r
156 routingAlgorithm.addEdge(new Edge(virtualLink));
\r
159 // computeRoute(virtualNetwork);
\r
165 * Compute a shortest virtual path from the given source vertex to
\r
166 * target one without any constraint.
\r
168 * @param source The given source virtual node id.
\r
169 * @param target The given target virtual node id.
\r
170 * @return The virtual path if successful,or null otherwise.
\r
172 public VirtualPath computePath(VirtualNodeId source, VirtualNodeId target) {
\r
173 List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),
\r
174 routingAlgorithm.getVertex(target.getValue()));
\r
176 if ( null == edges || edges.isEmpty() ) {
\r
180 List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink> virtualLinks =
\r
181 new ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink>(edges.size());
\r
182 org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink virtualLink;
\r
186 for ( Edge edge : edges ) {
\r
187 virtualLink = new VirtualLinkBuilder()
\r
188 .setLinkId(new VirtualLinkId(edge.getId()))
\r
189 .setOrder((long) virtualLinks.size())
\r
191 virtualLinks.add(virtualLink);
\r
193 metric += edge.getMetric();
\r
194 // delay += edge.getDelay();
\r
197 VirtualPath virtualPath = new VirtualPathBuilder()
\r
198 .setPathId(new VirtualPathId(UUID.randomUUID().toString()))
\r
199 .setVirtualLink(virtualLinks)
\r
205 return virtualPath;
\r
209 * Compute a shortest virtual path with the given bandwidth from the
\r
210 * given source vertex to target one.
\r
212 * @param source The given source virtual node id.
\r
213 * @param target The given target virtual node id.
\r
214 * @param bandwidth The given bandwidth for the virtual path.
\r
215 * @return The virtual path if successful,or null otherwise.
\r
217 public VirtualPath computePath(VirtualNodeId source, VirtualNodeId target, long bandwidth) {
\r
218 List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),
\r
219 routingAlgorithm.getVertex(target.getValue()), bandwidth);
\r
221 if ( null == edges || edges.isEmpty() ) {
\r
225 List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink> virtualLinks =
\r
226 new ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink>(edges.size());
\r
227 org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink virtualLink;
\r
231 for ( Edge edge : edges ) {
\r
232 edge.setBandwidth(edge.getBandwidth() - bandwidth);
\r
233 routingAlgorithm.updateEdge(edge);
\r
235 virtualLink = new VirtualLinkBuilder()
\r
236 .setLinkId(new VirtualLinkId(edge.getId()))
\r
237 .setOrder((long)virtualLinks.size())
\r
239 virtualLinks.add(virtualLink);
\r
241 metric += edge.getMetric();
\r
242 // delay += edge.getDelay();
\r
245 VirtualPath virtualPath = new VirtualPathBuilder()
\r
246 .setPathId(new VirtualPathId(UUID.randomUUID().toString()))
\r
247 .setVirtualLink(virtualLinks)
\r
249 .setBandwidth(bandwidth)
\r
253 return virtualPath;
\r
257 public void close() throws Exception {
\r
258 if ( null != virtualNodeChangeListenerReg ) {
\r
259 virtualNodeChangeListenerReg.close();
\r
262 if ( null != virtualLinkChangeListenerReg ) {
\r
263 virtualLinkChangeListenerReg.close();
\r
270 * Compute the routes between all virtual routers in the virtual
\r
271 * network, and store or update them into the data store.
\r
273 private void computeRoute() {
\r
274 Map<VirtualRouteKey, VirtualPath> routes = new HashMap<VirtualRouteKey, VirtualPath>();
\r
275 VirtualPath virtualPath;
\r
277 for ( VirtualNodeId source : virtualRouters ) {
\r
278 for ( VirtualNodeId target : virtualRouters ) {
\r
279 if ( !source.equals(target) ) {
\r
280 virtualPath = computePath(source, target);
\r
282 if ( null == virtualPath ) {
\r
286 routes.put(new VirtualRouteKey(source, target), virtualPath);
\r
291 updateRoute(routes);
\r
297 * Compute the routes between all virtual routers in the virtual
\r
298 * network, and store them into the virtual network.
\r
300 * @param virtualNetwork The virtual network to store the routes.
\r
302 private void computeRoute(VirtualNetwork virtualNetwork) {
\r
303 List<VirtualRoute> virtualRoutes = virtualNetwork.getVirtualRoutes().getVirtualRoute();
\r
304 List<VirtualPath> virtualPaths = virtualNetwork.getVirtualPaths().getVirtualPath();
\r
305 VirtualRoute virtualRoute;
\r
306 VirtualPath virtualPath;
\r
308 for ( VirtualNodeId source : virtualRouters ) {
\r
309 for ( VirtualNodeId target : virtualRouters ) {
\r
310 if ( !source.equals(target) ) {
\r
311 virtualPath = computePath(source, target);
\r
313 if ( null == virtualPath ) {
\r
317 virtualRoute = new VirtualRouteBuilder().setSrcNodeId(source)
\r
318 .setDestNodeId(target)
\r
319 .setPathId(virtualPath.getPathId())
\r
322 virtualPaths.add(virtualPath);
\r
323 virtualRoutes.add(virtualRoute);
\r
332 * Update the given routes into the data store. If the route
\r
333 * already exists, remove it's old virtual path and store the
\r
334 * given new one into the data store.
\r
336 * @param routes The given routes to be updated.
\r
338 private void updateRoute(Map<VirtualRouteKey, VirtualPath> routes) {
\r
339 ReadWriteTransaction readWriteTransaction = dataBroker.newReadWriteTransaction();
\r
341 VirtualNetworkKey virtualNetworkKey = new VirtualNetworkKey(new VirtualNetworkId(userId.getValue()));
\r
342 InstanceIdentifier<VirtualRoute> virtualRouteIid;
\r
343 InstanceIdentifier<VirtualPath> virtualPathIid;
\r
344 Optional<VirtualRoute> result;
\r
345 VirtualRoute virtualRoute;
\r
347 for ( Map.Entry<VirtualRouteKey, VirtualPath> route : routes.entrySet() ) {
\r
348 virtualRouteIid = InstanceIdentifier.builder(VirtualNetworks.class)
\r
349 .child(VirtualNetwork.class, virtualNetworkKey)
\r
350 .child(VirtualRoutes.class)
\r
351 .child(VirtualRoute.class, route.getKey())
\r
355 result = readWriteTransaction.read(LogicalDatastoreType.CONFIGURATION, virtualRouteIid).get();
\r
356 } catch ( InterruptedException | ExecutionException exception ) {
\r
357 LOG.error("Can not read the virtual route from the virtual node {} to {}.",
\r
358 route.getKey().getSrcNodeId().getValue(), route.getKey().getDestNodeId().getValue());
\r
363 if ( result.isPresent() ) {
\r
364 virtualRoute = result.get();
\r
365 virtualPathIid = InstanceIdentifier.builder(VirtualNetworks.class)
\r
366 .child(VirtualNetwork.class, virtualNetworkKey)
\r
367 .child(VirtualPaths.class)
\r
368 .child(VirtualPath.class, new VirtualPathKey(virtualRoute.getPathId()))
\r
370 readWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, virtualPathIid);
\r
373 virtualPathIid = InstanceIdentifier.builder(VirtualNetworks.class)
\r
374 .child(VirtualNetwork.class, virtualNetworkKey)
\r
375 .child(VirtualPaths.class)
\r
376 .child(VirtualPath.class, route.getValue().getKey())
\r
378 readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualPathIid, route.getValue(), true);
\r
380 virtualRoute = new VirtualRouteBuilder().setSrcNodeId(route.getKey().getSrcNodeId())
\r
381 .setDestNodeId(route.getKey().getDestNodeId())
\r
382 .setPathId(route.getValue().getPathId())
\r
384 readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualRouteIid, virtualRoute, true);
\r
387 readWriteTransaction.submit();
\r
393 * A listener to change events related to virtual nodes being
\r
394 * added, removed or updated.
\r
396 * @author Zhigang Ji
\r
398 private class VirtualNodeChangeListener implements DataChangeListener {
\r
400 public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
\r
401 if ( null == change ) {
\r
405 Map<InstanceIdentifier<?>, DataObject> createdData = change.getCreatedData();
\r
407 if ( null != createdData && !createdData.isEmpty() ) {
\r
408 VirtualNode virtualNode;
\r
411 for ( DataObject dataObject : createdData.values() ) {
\r
412 if ( dataObject instanceof VirtualNode ) {
\r
413 virtualNode = (VirtualNode)dataObject;
\r
414 vertex = new Vertex(virtualNode.getNodeId().getValue());
\r
416 routingAlgorithm.addVertex(vertex);
\r
418 if ( VirtualNode.NodeType.Vrouter == virtualNode.getNodeType() ) {
\r
419 virtualRouters.add(virtualNode.getNodeId());
\r
430 * A listener to change events related to virtual links being
\r
431 * added, removed or updated.
\r
433 * @author Zhigang Ji
\r
435 private class VirtualLinkChangeListener implements DataChangeListener {
\r
437 public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
\r
438 if ( null == change ) {
\r
442 Map<InstanceIdentifier<?>, DataObject> createdData = change.getCreatedData();
\r
444 if ( null != createdData && !createdData.isEmpty() ) {
\r
446 boolean needRerouting = false;
\r
448 for ( DataObject dataObject : createdData.values() ) {
\r
449 if ( dataObject instanceof VirtualLink ) {
\r
450 VirtualLink virtualLink = (VirtualLink)dataObject;
\r
451 Edge edge = new Edge(virtualLink);
\r
453 routingAlgorithm.addEdge(edge);
\r
455 if ( virtualRouters.contains(virtualLink.getSrcNodeId())
\r
456 && virtualRouters.contains(virtualLink.getDestNodeId()) ) {
\r
457 needRerouting = true;
\r
462 if ( needRerouting ) {
\r