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 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.ReadWriteTransaction;
\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.virtual.network.rev151010.VirtualNetworks;
\r
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.VirtualNetwork;
\r
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.VirtualNetworkKey;
\r
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualLinks;
\r
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualNodes;
\r
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualPaths;
\r
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualRoutes;
\r
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.links.VirtualLink;
\r
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.nodes.VirtualNode;
\r
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPath;
\r
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPathBuilder;
\r
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPathKey;
\r
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRoute;
\r
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRouteBuilder;
\r
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRouteKey;
\r
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLinkBuilder;
\r
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.UserId;
\r
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualLinkId;
\r
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualNetworkId;
\r
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualNodeId;
\r
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualPathId;
\r
42 import org.opendaylight.yangtools.concepts.ListenerRegistration;
\r
43 import org.opendaylight.yangtools.yang.binding.DataObject;
\r
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
\r
45 import org.slf4j.Logger;
\r
46 import org.slf4j.LoggerFactory;
\r
49 import java.util.concurrent.ExecutionException;
\r
52 * The virtual network computation unit implements the following functions:
\r
53 * (1) Maintain a user's virtual network topology information generated in
\r
54 * terms of the user's intents through subscribing from the data store.
\r
55 * (2) Automatically recompute all routes of the virtual network when it
\r
56 * changed, and store or update the routes into the data store.
\r
57 * (3) Provide the path computation with SLA constraints to any other modules
\r
60 * @author Zhigang Ji
\r
62 public class VNComputationUnit implements AutoCloseable {
\r
63 private static final Logger LOG = LoggerFactory.getLogger(VNComputationUnit.class);
\r
65 private final DataBroker dataBroker;
\r
68 * The user id for the virtual network maintained by
\r
69 * this computation unit.
\r
71 private UserId userId;
\r
74 * The routing algorithm instance.
\r
76 private RoutingAlgorithm routingAlgorithm;
\r
79 * The virtual routers in the virtual network.
\r
81 private Set<VirtualNodeId> virtualRouters;
\r
84 * The registration for the virtual node change listener.
\r
86 private ListenerRegistration<DataChangeListener> virtualNodeChangeListenerReg;
\r
89 * The registration for the virtual link change listener.
\r
91 private ListenerRegistration<DataChangeListener> virtualLinkChangeListenerReg;
\r
93 public VNComputationUnit(DataBroker dataBroker, UserId userId) {
\r
96 this.dataBroker = dataBroker;
\r
97 this.userId = userId;
\r
98 routingAlgorithm = new RoutingAlgorithm();
\r
99 virtualRouters = new HashSet<VirtualNodeId>();
\r
101 VirtualNetworkKey virtualNetworkKey = new VirtualNetworkKey(new VirtualNetworkId(userId.getValue()));
\r
102 InstanceIdentifier<VirtualNode> virtualNodeIid = InstanceIdentifier
\r
103 .builder(VirtualNetworks.class)
\r
104 .child(VirtualNetwork.class, virtualNetworkKey)
\r
105 .child(VirtualNodes.class)
\r
106 .child(VirtualNode.class)
\r
108 InstanceIdentifier<VirtualLink> virtualLinkIid = InstanceIdentifier
\r
109 .builder(VirtualNetworks.class)
\r
110 .child(VirtualNetwork.class, virtualNetworkKey)
\r
111 .child(VirtualLinks.class)
\r
112 .child(VirtualLink.class)
\r
115 virtualNodeChangeListenerReg = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
\r
116 virtualNodeIid, new VirtualNodeChangeListener(), DataChangeScope.BASE);
\r
117 virtualLinkChangeListenerReg = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
\r
118 virtualLinkIid, new VirtualLinkChangeListener(), DataChangeScope.BASE);
\r
120 LOG.debug("Initialized the virtual network computation unit for the user {}.", userId.getValue());
\r
125 public VNComputationUnit(DataBroker dataBroker, VirtualNetwork virtualNetwork) {
\r
128 this.dataBroker = dataBroker;
\r
129 userId = virtualNetwork.getUserId();
\r
130 routingAlgorithm = new RoutingAlgorithm();
\r
131 virtualRouters = new HashSet<VirtualNodeId>();
\r
133 List<VirtualNode> virtualNodes = virtualNetwork.getVirtualNodes().getVirtualNode();
\r
136 for ( VirtualNode virtualNode : virtualNodes ) {
\r
137 vertex = new Vertex(virtualNode.getNodeId().getValue());
\r
138 routingAlgorithm.addVertex(vertex);
\r
140 if ( VirtualNode.NodeType.Vrouter == virtualNode.getNodeType() ) {
\r
141 virtualRouters.add(virtualNode.getNodeId());
\r
145 List<VirtualLink> virtualLinks = virtualNetwork.getVirtualLinks().getVirtualLink();
\r
148 for ( VirtualLink virtualLink : virtualLinks ) {
\r
149 edge = new Edge(virtualLink.getLinkId().getValue(), virtualLink.getSrcNodeId().getValue(),
\r
150 virtualLink.getDestNodeId().getValue(), virtualLink.getMetric(),
\r
151 virtualLink.getBandwidth());
\r
152 routingAlgorithm.addEdge(edge);
\r
155 // computeRoute(virtualNetwork);
\r
161 * Compute a shortest virtual path from the given source vertex to
\r
162 * target one without any constraint.
\r
164 * @param source The given source virtual node id.
\r
165 * @param target The given target virtual node id.
\r
166 * @return The virtual path if successful,or null otherwise.
\r
168 public VirtualPath computePath(VirtualNodeId source, VirtualNodeId target) {
\r
169 List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),
\r
170 routingAlgorithm.getVertex(target.getValue()));
\r
172 if ( null == edges || edges.isEmpty() ) {
\r
176 List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink> virtualLinks =
\r
177 new ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink>(edges.size());
\r
178 org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink virtualLink;
\r
182 for ( Edge edge : edges ) {
\r
183 virtualLink = new VirtualLinkBuilder()
\r
184 .setLinkId(new VirtualLinkId(edge.getId()))
\r
185 .setOrder((long) virtualLinks.size())
\r
187 virtualLinks.add(virtualLink);
\r
189 metric += edge.getMetric();
\r
190 // delay += edge.getDelay();
\r
193 VirtualPath virtualPath = new VirtualPathBuilder()
\r
194 .setPathId(new VirtualPathId(UUID.randomUUID().toString()))
\r
195 .setVirtualLink(virtualLinks)
\r
201 return virtualPath;
\r
205 * Compute a shortest virtual path with the given bandwidth from the
\r
206 * given source vertex to target one.
\r
208 * @param source The given source virtual node id.
\r
209 * @param target The given target virtual node id.
\r
210 * @param bandwidth The given bandwidth for the virtual path.
\r
211 * @return The virtual path if successful,or null otherwise.
\r
213 public VirtualPath computePath(VirtualNodeId source, VirtualNodeId target, long bandwidth) {
\r
214 List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),
\r
215 routingAlgorithm.getVertex(target.getValue()), bandwidth);
\r
217 if ( null == edges || edges.isEmpty() ) {
\r
221 List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink> virtualLinks =
\r
222 new ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink>(edges.size());
\r
223 org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink virtualLink;
\r
227 for ( Edge edge : edges ) {
\r
228 edge.setBandwidth(edge.getBandwidth() - bandwidth);
\r
229 routingAlgorithm.updateEdge(edge);
\r
231 virtualLink = new VirtualLinkBuilder()
\r
232 .setLinkId(new VirtualLinkId(edge.getId()))
\r
233 .setOrder((long)virtualLinks.size())
\r
235 virtualLinks.add(virtualLink);
\r
237 metric += edge.getMetric();
\r
238 // delay += edge.getDelay();
\r
241 VirtualPath virtualPath = new VirtualPathBuilder()
\r
242 .setPathId(new VirtualPathId(UUID.randomUUID().toString()))
\r
243 .setVirtualLink(virtualLinks)
\r
245 .setBandwidth(bandwidth)
\r
249 return virtualPath;
\r
253 public void close() throws Exception {
\r
254 if ( null != virtualNodeChangeListenerReg ) {
\r
255 virtualNodeChangeListenerReg.close();
\r
258 if ( null != virtualLinkChangeListenerReg ) {
\r
259 virtualLinkChangeListenerReg.close();
\r
266 * Compute the routes between all virtual routers in the virtual
\r
267 * network, and store or update them into the data store.
\r
269 private void computeRoute() {
\r
270 Map<VirtualRouteKey, VirtualPath> routes = new HashMap<VirtualRouteKey, VirtualPath>();
\r
271 VirtualPath virtualPath;
\r
273 for ( VirtualNodeId source : virtualRouters ) {
\r
274 for ( VirtualNodeId target : virtualRouters ) {
\r
275 if ( !source.equals(target) ) {
\r
276 virtualPath = computePath(source, target);
\r
278 if ( null == virtualPath ) {
\r
282 routes.put(new VirtualRouteKey(source, target), virtualPath);
\r
287 updateRoute(routes);
\r
293 * Compute the routes between all virtual routers in the virtual
\r
294 * network, and store them into the virtual network.
\r
296 * @param virtualNetwork The virtual network to store the routes.
\r
298 private void computeRoute(VirtualNetwork virtualNetwork) {
\r
299 List<VirtualRoute> virtualRoutes = virtualNetwork.getVirtualRoutes().getVirtualRoute();
\r
300 List<VirtualPath> virtualPaths = virtualNetwork.getVirtualPaths().getVirtualPath();
\r
301 VirtualRoute virtualRoute;
\r
302 VirtualPath virtualPath;
\r
304 for ( VirtualNodeId source : virtualRouters ) {
\r
305 for ( VirtualNodeId target : virtualRouters ) {
\r
306 if ( !source.equals(target) ) {
\r
307 virtualPath = computePath(source, target);
\r
309 if ( null == virtualPath ) {
\r
313 virtualRoute = new VirtualRouteBuilder().setSrcNodeId(source)
\r
314 .setDestNodeId(target)
\r
315 .setPathId(virtualPath.getPathId())
\r
318 virtualPaths.add(virtualPath);
\r
319 virtualRoutes.add(virtualRoute);
\r
328 * Update the given routes into the data store. If the route
\r
329 * already exists, remove it's old virtual path and store the
\r
330 * given new one into the data store.
\r
332 * @param routes The given routes to be updated.
\r
334 private void updateRoute(Map<VirtualRouteKey, VirtualPath> routes) {
\r
335 ReadWriteTransaction readWriteTransaction = dataBroker.newReadWriteTransaction();
\r
337 VirtualNetworkKey virtualNetworkKey = new VirtualNetworkKey(new VirtualNetworkId(userId.getValue()));
\r
338 InstanceIdentifier<VirtualRoute> virtualRouteIid;
\r
339 InstanceIdentifier<VirtualPath> virtualPathIid;
\r
340 Optional<VirtualRoute> result;
\r
341 VirtualRoute virtualRoute;
\r
343 for ( Map.Entry<VirtualRouteKey, VirtualPath> route : routes.entrySet() ) {
\r
344 virtualRouteIid = InstanceIdentifier.builder(VirtualNetworks.class)
\r
345 .child(VirtualNetwork.class, virtualNetworkKey)
\r
346 .child(VirtualRoutes.class)
\r
347 .child(VirtualRoute.class, route.getKey())
\r
351 result = readWriteTransaction.read(LogicalDatastoreType.CONFIGURATION, virtualRouteIid).get();
\r
352 } catch ( InterruptedException | ExecutionException exception ) {
\r
353 LOG.error("Can not read the virtual route from the virtual node {} to {}.",
\r
354 route.getKey().getSrcNodeId().getValue(), route.getKey().getDestNodeId().getValue());
\r
359 if ( result.isPresent() ) {
\r
360 virtualRoute = result.get();
\r
361 virtualPathIid = InstanceIdentifier.builder(VirtualNetworks.class)
\r
362 .child(VirtualNetwork.class, virtualNetworkKey)
\r
363 .child(VirtualPaths.class)
\r
364 .child(VirtualPath.class, new VirtualPathKey(virtualRoute.getPathId()))
\r
366 readWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, virtualPathIid);
\r
369 virtualPathIid = InstanceIdentifier.builder(VirtualNetworks.class)
\r
370 .child(VirtualNetwork.class, virtualNetworkKey)
\r
371 .child(VirtualPaths.class)
\r
372 .child(VirtualPath.class, route.getValue().getKey())
\r
374 readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualPathIid, route.getValue(), true);
\r
376 virtualRoute = new VirtualRouteBuilder().setSrcNodeId(route.getKey().getSrcNodeId())
\r
377 .setDestNodeId(route.getKey().getDestNodeId())
\r
378 .setPathId(route.getValue().getPathId())
\r
380 readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualRouteIid, virtualRoute, true);
\r
383 readWriteTransaction.submit();
\r
389 * A listener to change events related to virtual nodes being
\r
390 * added, removed or updated.
\r
392 * @author Zhigang Ji
\r
394 private class VirtualNodeChangeListener implements DataChangeListener {
\r
396 public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
\r
397 if ( null == change ) {
\r
401 Map<InstanceIdentifier<?>, DataObject> createdData = change.getCreatedData();
\r
403 if ( null != createdData && !createdData.isEmpty() ) {
\r
404 VirtualNode virtualNode;
\r
407 for ( DataObject dataObject : createdData.values() ) {
\r
408 if ( dataObject instanceof VirtualNode ) {
\r
409 virtualNode = (VirtualNode)dataObject;
\r
410 vertex = new Vertex(virtualNode.getNodeId().getValue());
\r
412 routingAlgorithm.addVertex(vertex);
\r
414 if ( VirtualNode.NodeType.Vrouter == virtualNode.getNodeType() ) {
\r
415 virtualRouters.add(virtualNode.getNodeId());
\r
426 * A listener to change events related to virtual links being
\r
427 * added, removed or updated.
\r
429 * @author Zhigang Ji
\r
431 private class VirtualLinkChangeListener implements DataChangeListener {
\r
433 public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
\r
434 if ( null == change ) {
\r
438 Map<InstanceIdentifier<?>, DataObject> createdData = change.getCreatedData();
\r
440 if ( null != createdData && !createdData.isEmpty() ) {
\r
441 VirtualLink virtualLink;
\r
443 boolean needRerouting = false;
\r
445 for ( DataObject dataObject : createdData.values() ) {
\r
446 if ( dataObject instanceof VirtualLink ) {
\r
447 virtualLink = (VirtualLink)dataObject;
\r
448 edge = new Edge(virtualLink.getLinkId().getValue(), virtualLink.getSrcNodeId().getValue(),
\r
449 virtualLink.getDestNodeId().getValue(), virtualLink.getMetric(),
\r
450 virtualLink.getBandwidth());
\r
452 routingAlgorithm.addEdge(edge);
\r
454 if ( virtualRouters.contains(virtualLink.getSrcNodeId())
\r
455 && virtualRouters.contains(virtualLink.getDestNodeId()) ) {
\r
456 needRerouting = true;
\r
461 if ( needRerouting ) {
\r