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
154 for ( VirtualLink virtualLink : virtualLinks ) {
\r
155 routingAlgorithm.addEdge(new Edge(virtualLink));
\r
158 // computeRoute(virtualNetwork);
\r
164 * Compute a shortest virtual path from the given source vertex to
\r
165 * target one without any constraint.
\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
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
175 if ( null == edges || edges.isEmpty() ) {
\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
185 for ( Edge edge : edges ) {
\r
186 virtualLink = new VirtualLinkBuilder()
\r
187 .setLinkId(new VirtualLinkId(edge.getId()))
\r
188 .setOrder((long) virtualLinks.size())
\r
190 virtualLinks.add(virtualLink);
\r
192 metric += edge.getMetric();
\r
193 // delay += edge.getDelay();
\r
196 VirtualPath virtualPath = new VirtualPathBuilder()
\r
197 .setPathId(new VirtualPathId(UUID.randomUUID().toString()))
\r
198 .setVirtualLink(virtualLinks)
\r
204 return virtualPath;
\r
208 * Compute a shortest virtual path with the given bandwidth from the
\r
209 * given source vertex to target one.
\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
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
220 if ( null == edges || edges.isEmpty() ) {
\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
230 for ( Edge edge : edges ) {
\r
231 edge.setBandwidth(edge.getBandwidth() - bandwidth);
\r
232 routingAlgorithm.updateEdge(edge);
\r
234 virtualLink = new VirtualLinkBuilder()
\r
235 .setLinkId(new VirtualLinkId(edge.getId()))
\r
236 .setOrder((long)virtualLinks.size())
\r
238 virtualLinks.add(virtualLink);
\r
240 metric += edge.getMetric();
\r
241 // delay += edge.getDelay();
\r
244 VirtualPath virtualPath = new VirtualPathBuilder()
\r
245 .setPathId(new VirtualPathId(UUID.randomUUID().toString()))
\r
246 .setVirtualLink(virtualLinks)
\r
248 .setBandwidth(bandwidth)
\r
252 return virtualPath;
\r
256 public void close() throws Exception {
\r
257 if ( null != virtualNodeChangeListenerReg ) {
\r
258 virtualNodeChangeListenerReg.close();
\r
261 if ( null != virtualLinkChangeListenerReg ) {
\r
262 virtualLinkChangeListenerReg.close();
\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
272 private void computeRoute() {
\r
273 Map<VirtualRouteKey, VirtualPath> routes = new HashMap<VirtualRouteKey, VirtualPath>();
\r
274 VirtualPath virtualPath;
\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
281 if ( null == virtualPath ) {
\r
285 routes.put(new VirtualRouteKey(source, target), virtualPath);
\r
290 updateRoute(routes);
\r
296 * Compute the routes between all virtual routers in the virtual
\r
297 * network, and store them into the virtual network.
\r
299 * @param virtualNetwork The virtual network to store the routes.
\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
307 for ( VirtualNodeId source : virtualRouters ) {
\r
308 for ( VirtualNodeId target : virtualRouters ) {
\r
309 if ( !source.equals(target) ) {
\r
310 virtualPath = computePath(source, target);
\r
312 if ( null == virtualPath ) {
\r
316 virtualRoute = new VirtualRouteBuilder().setSrcNodeId(source)
\r
317 .setDestNodeId(target)
\r
318 .setPathId(virtualPath.getPathId())
\r
321 virtualPaths.add(virtualPath);
\r
322 virtualRoutes.add(virtualRoute);
\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
335 * @param routes The given routes to be updated.
\r
337 private void updateRoute(Map<VirtualRouteKey, VirtualPath> routes) {
\r
338 ReadWriteTransaction readWriteTransaction = dataBroker.newReadWriteTransaction();
\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
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
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
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
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
374 readWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, virtualPathIid);
\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
382 readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualPathIid, route.getValue(), true);
\r
384 virtualRoute = new VirtualRouteBuilder().setSrcNodeId(route.getKey().getSrcNodeId())
\r
385 .setDestNodeId(route.getKey().getDestNodeId())
\r
386 .setPathId(route.getValue().getPathId())
\r
388 readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualRouteIid, virtualRoute, true);
\r
391 readWriteTransaction.submit();
\r
397 * A listener to change events related to virtual nodes being
\r
398 * added, removed or updated.
\r
400 * @author Zhigang Ji
\r
402 private class VirtualNodeChangeListener implements DataChangeListener {
\r
404 public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
\r
405 if ( null == change ) {
\r
409 Map<InstanceIdentifier<?>, DataObject> createdData = change.getCreatedData();
\r
411 if ( null != createdData && !createdData.isEmpty() ) {
\r
412 VirtualNode virtualNode;
\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
420 routingAlgorithm.addVertex(vertex);
\r
422 if ( VirtualNode.NodeType.Vrouter == virtualNode.getNodeType() ) {
\r
423 virtualRouters.add(virtualNode.getNodeId());
\r
434 * A listener to change events related to virtual links being
\r
435 * added, removed or updated.
\r
437 * @author Zhigang Ji
\r
439 private class VirtualLinkChangeListener implements DataChangeListener {
\r
441 public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
\r
442 if ( null == change ) {
\r
446 Map<InstanceIdentifier<?>, DataObject> createdData = change.getCreatedData();
\r
448 if ( null != createdData && !createdData.isEmpty() ) {
\r
449 boolean needRerouting = false;
\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
456 routingAlgorithm.addEdge(edge);
\r
458 if ( virtualRouters.contains(virtualLink.getSrcNodeId())
\r
459 && virtualRouters.contains(virtualLink.getDestNodeId()) ) {
\r
460 needRerouting = true;
\r
465 if ( needRerouting ) {
\r