-/*\r
- * Copyright (c) 2015 Huawei, Inc. and others. All rights reserved.\r
- *\r
- * This program and the accompanying materials are made available under the\r
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
- * and is available at http://www.eclipse.org/legal/epl-v10.html\r
- */\r
-\r
-package org.opendaylight.nemo.intent.computation;\r
-\r
-import java.util.ArrayList;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.UUID;\r
-import java.util.concurrent.ExecutionException;\r
-\r
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
-import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;\r
-import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;\r
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;\r
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;\r
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
-import org.opendaylight.nemo.intent.algorithm.Edge;\r
-import org.opendaylight.nemo.intent.algorithm.RoutingAlgorithm;\r
-import org.opendaylight.nemo.intent.algorithm.Vertex;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.VirtualNetworks;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.VirtualNetwork;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.VirtualNetworkKey;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualLinks;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualNodes;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualPaths;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualRoutes;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.links.VirtualLink;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.nodes.VirtualNode;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPath;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPathBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPathKey;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRoute;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRouteBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRouteKey;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLinkBuilder;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.UserId;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualLinkId;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualNetworkId;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualNodeId;\r
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualPathId;\r
-import org.opendaylight.yangtools.concepts.ListenerRegistration;\r
-import org.opendaylight.yangtools.yang.binding.DataObject;\r
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-\r
-import com.google.common.base.Optional;\r
-\r
-/**\r
- * The virtual network computation unit implements the following functions:\r
- * (1) Maintain a user's virtual network topology information generated in\r
- * terms of the user's intents through subscribing from the data store.\r
- * (2) Automatically recompute all routes of the virtual network when it\r
- * changed, and store or update the routes into the data store.\r
- * (3) Provide the path computation with SLA constraints to any other modules\r
- * that need it.\r
- *\r
- * @author Zhigang Ji\r
- */\r
-public class VNComputationUnit implements AutoCloseable {\r
- private static final Logger LOG = LoggerFactory.getLogger(VNComputationUnit.class);\r
-\r
- private final DataBroker dataBroker;\r
-\r
- /**\r
- * The user id for the virtual network maintained by\r
- * this computation unit.\r
- */\r
- private UserId userId;\r
-\r
- /**\r
- * The routing algorithm instance.\r
- */\r
- private RoutingAlgorithm routingAlgorithm;\r
-\r
- /**\r
- * The virtual routers in the virtual network.\r
- */\r
- private Set<VirtualNodeId> virtualRouters;\r
-\r
- /**\r
- * The registration for the virtual node change listener.\r
- */\r
- private ListenerRegistration<DataChangeListener> virtualNodeChangeListenerReg;\r
-\r
- /**\r
- * The registration for the virtual link change listener.\r
- */\r
- private ListenerRegistration<DataChangeListener> virtualLinkChangeListenerReg;\r
-\r
- public VNComputationUnit(DataBroker dataBroker, UserId userId) {\r
- super();\r
-\r
- this.dataBroker = dataBroker;\r
- this.userId = userId;\r
- routingAlgorithm = new RoutingAlgorithm();\r
- virtualRouters = new HashSet<VirtualNodeId>();\r
-\r
- VirtualNetworkKey virtualNetworkKey = new VirtualNetworkKey(new VirtualNetworkId(userId.getValue()));\r
- InstanceIdentifier<VirtualNode> virtualNodeIid = InstanceIdentifier\r
- .builder(VirtualNetworks.class)\r
- .child(VirtualNetwork.class, virtualNetworkKey)\r
- .child(VirtualNodes.class)\r
- .child(VirtualNode.class)\r
- .build();\r
- InstanceIdentifier<VirtualLink> virtualLinkIid = InstanceIdentifier\r
- .builder(VirtualNetworks.class)\r
- .child(VirtualNetwork.class, virtualNetworkKey)\r
- .child(VirtualLinks.class)\r
- .child(VirtualLink.class)\r
- .build();\r
-\r
- virtualNodeChangeListenerReg = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,\r
- virtualNodeIid, new VirtualNodeChangeListener(), DataChangeScope.BASE);\r
- virtualLinkChangeListenerReg = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,\r
- virtualLinkIid, new VirtualLinkChangeListener(), DataChangeScope.BASE);\r
-\r
- LOG.debug("Initialized the virtual network computation unit for the user {}.", userId.getValue());\r
-\r
- return;\r
- }\r
-\r
- public VNComputationUnit(DataBroker dataBroker, VirtualNetwork virtualNetwork) {\r
- super();\r
-\r
- this.dataBroker = dataBroker;\r
- userId = virtualNetwork.getUserId();\r
- routingAlgorithm = new RoutingAlgorithm();\r
- virtualRouters = new HashSet<VirtualNodeId>();\r
-\r
- List<VirtualNode> virtualNodes = virtualNetwork.getVirtualNodes().getVirtualNode();\r
- Vertex vertex;\r
-\r
- for ( VirtualNode virtualNode : virtualNodes ) {\r
- vertex = new Vertex(virtualNode.getNodeId().getValue());\r
- routingAlgorithm.addVertex(vertex);\r
-\r
- if ( VirtualNode.NodeType.Vrouter == virtualNode.getNodeType() ) {\r
- virtualRouters.add(virtualNode.getNodeId());\r
- }\r
- }\r
-\r
- List<VirtualLink> virtualLinks = virtualNetwork.getVirtualLinks().getVirtualLink();\r
-\r
- for ( VirtualLink virtualLink : virtualLinks ) {\r
- routingAlgorithm.addEdge(new Edge(virtualLink));\r
- }\r
-\r
-// computeRoute(virtualNetwork);\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * Compute a shortest virtual path from the given source vertex to\r
- * target one without any constraint.\r
- *\r
- * @param source The given source virtual node id.\r
- * @param target The given target virtual node id.\r
- * @return The virtual path if successful,or null otherwise.\r
- */\r
- public VirtualPath computePath(VirtualNodeId source, VirtualNodeId target) {\r
- List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),\r
- routingAlgorithm.getVertex(target.getValue()));\r
-\r
- if ( null == edges || edges.isEmpty() ) {\r
- return null;\r
- }\r
-\r
- List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink> virtualLinks =\r
- new ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink>(edges.size());\r
- org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink virtualLink;\r
- long metric = 0;\r
- long delay = 0;\r
-\r
- for ( Edge edge : edges ) {\r
- virtualLink = new VirtualLinkBuilder()\r
- .setLinkId(new VirtualLinkId(edge.getId()))\r
- .setOrder((long) virtualLinks.size())\r
- .build();\r
- virtualLinks.add(virtualLink);\r
-\r
- metric += edge.getMetric();\r
-// delay += edge.getDelay();\r
- }\r
-\r
- VirtualPath virtualPath = new VirtualPathBuilder()\r
- .setPathId(new VirtualPathId(UUID.randomUUID().toString()))\r
- .setVirtualLink(virtualLinks)\r
- .setMetric(metric)\r
- .setBandwidth(0L)\r
- .setDelay(delay)\r
- .build();\r
-\r
- return virtualPath;\r
- }\r
-\r
- /**\r
- * Compute a shortest virtual path with the given bandwidth from the\r
- * given source vertex to target one.\r
- *\r
- * @param source The given source virtual node id.\r
- * @param target The given target virtual node id.\r
- * @param bandwidth The given bandwidth for the virtual path.\r
- * @return The virtual path if successful,or null otherwise.\r
- */\r
- public VirtualPath computePath(VirtualNodeId source, VirtualNodeId target, long bandwidth) {\r
- List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),\r
- routingAlgorithm.getVertex(target.getValue()), bandwidth);\r
-\r
- if ( null == edges || edges.isEmpty() ) {\r
- return null;\r
- }\r
-\r
- List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink> virtualLinks =\r
- new ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink>(edges.size());\r
- org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink virtualLink;\r
- long metric = 0;\r
- long delay = 0;\r
-\r
- for ( Edge edge : edges ) {\r
- edge.setBandwidth(edge.getBandwidth() - bandwidth);\r
- routingAlgorithm.updateEdge(edge);\r
-\r
- virtualLink = new VirtualLinkBuilder()\r
- .setLinkId(new VirtualLinkId(edge.getId()))\r
- .setOrder((long)virtualLinks.size())\r
- .build();\r
- virtualLinks.add(virtualLink);\r
-\r
- metric += edge.getMetric();\r
-// delay += edge.getDelay();\r
- }\r
-\r
- VirtualPath virtualPath = new VirtualPathBuilder()\r
- .setPathId(new VirtualPathId(UUID.randomUUID().toString()))\r
- .setVirtualLink(virtualLinks)\r
- .setMetric(metric)\r
- .setBandwidth(bandwidth)\r
- .setDelay(delay)\r
- .build();\r
-\r
- return virtualPath;\r
- }\r
-\r
- @Override\r
- public void close() throws Exception {\r
- if ( null != virtualNodeChangeListenerReg ) {\r
- virtualNodeChangeListenerReg.close();\r
- }\r
-\r
- if ( null != virtualLinkChangeListenerReg ) {\r
- virtualLinkChangeListenerReg.close();\r
- }\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * Compute the routes between all virtual routers in the virtual\r
- * network, and store or update them into the data store.\r
- */\r
- private void computeRoute() {\r
- Map<VirtualRouteKey, VirtualPath> routes = new HashMap<VirtualRouteKey, VirtualPath>();\r
- VirtualPath virtualPath;\r
-\r
- for ( VirtualNodeId source : virtualRouters ) {\r
- for ( VirtualNodeId target : virtualRouters ) {\r
- if ( !source.equals(target) ) {\r
- virtualPath = computePath(source, target);\r
-\r
- if ( null == virtualPath ) {\r
- continue;\r
- }\r
-\r
- routes.put(new VirtualRouteKey(source, target), virtualPath);\r
- }\r
- }\r
- }\r
-\r
- updateRoute(routes);\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * Compute the routes between all virtual routers in the virtual\r
- * network, and store them into the virtual network.\r
- *\r
- * @param virtualNetwork The virtual network to store the routes.\r
- */\r
- private void computeRoute(VirtualNetwork virtualNetwork) {\r
- List<VirtualRoute> virtualRoutes = virtualNetwork.getVirtualRoutes().getVirtualRoute();\r
- List<VirtualPath> virtualPaths = virtualNetwork.getVirtualPaths().getVirtualPath();\r
- VirtualRoute virtualRoute;\r
- VirtualPath virtualPath;\r
-\r
- for ( VirtualNodeId source : virtualRouters ) {\r
- for ( VirtualNodeId target : virtualRouters ) {\r
- if ( !source.equals(target) ) {\r
- virtualPath = computePath(source, target);\r
-\r
- if ( null == virtualPath ) {\r
- continue;\r
- }\r
-\r
- virtualRoute = new VirtualRouteBuilder().setSrcNodeId(source)\r
- .setDestNodeId(target)\r
- .setPathId(virtualPath.getPathId())\r
- .build();\r
-\r
- virtualPaths.add(virtualPath);\r
- virtualRoutes.add(virtualRoute);\r
- }\r
- }\r
- }\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * Update the given routes into the data store. If the route\r
- * already exists, remove it's old virtual path and store the\r
- * given new one into the data store.\r
- *\r
- * @param routes The given routes to be updated.\r
- */\r
- private void updateRoute(Map<VirtualRouteKey, VirtualPath> routes) {\r
- ReadWriteTransaction readWriteTransaction = dataBroker.newReadWriteTransaction();\r
-\r
- VirtualNetworkKey virtualNetworkKey = new VirtualNetworkKey(new VirtualNetworkId(userId.getValue()));\r
- InstanceIdentifier<VirtualRoute> virtualRouteIid;\r
- InstanceIdentifier<VirtualPath> virtualPathIid;\r
- Optional<VirtualRoute> result;\r
- VirtualRoute virtualRoute;\r
-\r
- for ( Map.Entry<VirtualRouteKey, VirtualPath> route : routes.entrySet() ) {\r
- virtualRouteIid = InstanceIdentifier.builder(VirtualNetworks.class)\r
- .child(VirtualNetwork.class, virtualNetworkKey)\r
- .child(VirtualRoutes.class)\r
- .child(VirtualRoute.class, route.getKey())\r
- .build();\r
-\r
- try {\r
- result = readWriteTransaction.read(LogicalDatastoreType.CONFIGURATION, virtualRouteIid).get();\r
- } catch ( InterruptedException exception ) {\r
- LOG.error("Can not read the virtual route from the virtual node {} to {}.",\r
- route.getKey().getSrcNodeId().getValue(), route.getKey().getDestNodeId().getValue());\r
-\r
- continue;\r
- } catch ( ExecutionException exception ) {\r
- LOG.error("Can not read the virtual route from the virtual node {} to {}.",\r
- route.getKey().getSrcNodeId().getValue(), route.getKey().getDestNodeId().getValue());\r
-\r
- continue;\r
- }\r
-\r
- if ( result.isPresent() ) {\r
- virtualRoute = result.get();\r
- virtualPathIid = InstanceIdentifier.builder(VirtualNetworks.class)\r
- .child(VirtualNetwork.class, virtualNetworkKey)\r
- .child(VirtualPaths.class)\r
- .child(VirtualPath.class, new VirtualPathKey(virtualRoute.getPathId()))\r
- .build();\r
- readWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, virtualPathIid);\r
- }\r
-\r
- virtualPathIid = InstanceIdentifier.builder(VirtualNetworks.class)\r
- .child(VirtualNetwork.class, virtualNetworkKey)\r
- .child(VirtualPaths.class)\r
- .child(VirtualPath.class, route.getValue().getKey())\r
- .build();\r
- readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualPathIid, route.getValue(), true);\r
-\r
- virtualRoute = new VirtualRouteBuilder().setSrcNodeId(route.getKey().getSrcNodeId())\r
- .setDestNodeId(route.getKey().getDestNodeId())\r
- .setPathId(route.getValue().getPathId())\r
- .build();\r
- readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualRouteIid, virtualRoute, true);\r
- }\r
-\r
- readWriteTransaction.submit();\r
-\r
- return;\r
- }\r
-\r
- /**\r
- * A listener to change events related to virtual nodes being\r
- * added, removed or updated.\r
- *\r
- * @author Zhigang Ji\r
- */\r
- private class VirtualNodeChangeListener implements DataChangeListener {\r
- @Override\r
- public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {\r
- if ( null == change ) {\r
- return;\r
- }\r
-\r
- Map<InstanceIdentifier<?>, DataObject> createdData = change.getCreatedData();\r
-\r
- if ( null != createdData && !createdData.isEmpty() ) {\r
- VirtualNode virtualNode;\r
- Vertex vertex;\r
-\r
- for ( DataObject dataObject : createdData.values() ) {\r
- if ( dataObject instanceof VirtualNode ) {\r
- virtualNode = (VirtualNode)dataObject;\r
- vertex = new Vertex(virtualNode.getNodeId().getValue());\r
-\r
- routingAlgorithm.addVertex(vertex);\r
-\r
- if ( VirtualNode.NodeType.Vrouter == virtualNode.getNodeType() ) {\r
- virtualRouters.add(virtualNode.getNodeId());\r
- }\r
- }\r
- }\r
- }\r
-\r
- return;\r
- }\r
- }\r
-\r
- /**\r
- * A listener to change events related to virtual links being\r
- * added, removed or updated.\r
- *\r
- * @author Zhigang Ji\r
- */\r
- private class VirtualLinkChangeListener implements DataChangeListener {\r
- @Override\r
- public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {\r
- if ( null == change ) {\r
- return;\r
- }\r
-\r
- Map<InstanceIdentifier<?>, DataObject> createdData = change.getCreatedData();\r
-\r
- if ( null != createdData && !createdData.isEmpty() ) {\r
- boolean needRerouting = false;\r
-\r
- for ( DataObject dataObject : createdData.values() ) {\r
- if ( dataObject instanceof VirtualLink ) {\r
- VirtualLink virtualLink = (VirtualLink)dataObject;\r
- Edge edge = new Edge(virtualLink);\r
-\r
- routingAlgorithm.addEdge(edge);\r
-\r
- if ( virtualRouters.contains(virtualLink.getSrcNodeId())\r
- && virtualRouters.contains(virtualLink.getDestNodeId()) ) {\r
- needRerouting = true;\r
- }\r
- }\r
- }\r
-\r
- if ( needRerouting ) {\r
- computeRoute();\r
- }\r
- }\r
-\r
- return;\r
- }\r
- }\r
-}\r
+/*
+ * Copyright (c) 2015 Huawei, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.nemo.intent.computation;
+
+import com.google.common.base.Optional;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.nemo.intent.algorithm.Edge;
+import org.opendaylight.nemo.intent.algorithm.RoutingAlgorithm;
+import org.opendaylight.nemo.intent.algorithm.Vertex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.VirtualNetworks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.VirtualNetwork;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.VirtualNetworkKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualLinks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualNodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualPaths;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.VirtualRoutes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.links.VirtualLink;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.nodes.VirtualNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPath;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPathBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.paths.VirtualPathKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRoute;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRouteBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.networks.virtual.network.virtual.routes.VirtualRouteKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLinkBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.UserId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualLinkId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualNetworkId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualNodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.engine.common.rev151010.VirtualPathId;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The virtual network computation unit implements the following functions:
+ * (1) Maintain a user's virtual network topology information generated in
+ * terms of the user's intents through subscribing from the data store.
+ * (2) Automatically recompute all routes of the virtual network when it
+ * changed, and store or update the routes into the data store.
+ * (3) Provide the path computation with SLA constraints to any other modules
+ * that need it.
+ *
+ * @author Zhigang Ji
+ */
+public class VNComputationUnit implements AutoCloseable {
+ private static final Logger LOG = LoggerFactory.getLogger(VNComputationUnit.class);
+
+ private final DataBroker dataBroker;
+
+ /**
+ * The user id for the virtual network maintained by
+ * this computation unit.
+ */
+ private UserId userId;
+
+ /**
+ * The routing algorithm instance.
+ */
+ private RoutingAlgorithm routingAlgorithm;
+
+ /**
+ * The virtual routers in the virtual network.
+ */
+ private Set<VirtualNodeId> virtualRouters = ConcurrentHashMap.newKeySet();
+
+ /**
+ * The registration for the virtual node change listener.
+ */
+ private ListenerRegistration<?> virtualNodeChangeListenerReg;
+
+ /**
+ * The registration for the virtual link change listener.
+ */
+ private ListenerRegistration<?> virtualLinkChangeListenerReg;
+
+ public VNComputationUnit(DataBroker dataBroker, UserId userId) {
+ super();
+
+ this.dataBroker = dataBroker;
+ this.userId = userId;
+ routingAlgorithm = new RoutingAlgorithm();
+
+ VirtualNetworkKey virtualNetworkKey = new VirtualNetworkKey(new VirtualNetworkId(userId.getValue()));
+ InstanceIdentifier<VirtualNode> virtualNodeIid = InstanceIdentifier
+ .builder(VirtualNetworks.class)
+ .child(VirtualNetwork.class, virtualNetworkKey)
+ .child(VirtualNodes.class)
+ .child(VirtualNode.class)
+ .build();
+ InstanceIdentifier<VirtualLink> virtualLinkIid = InstanceIdentifier
+ .builder(VirtualNetworks.class)
+ .child(VirtualNetwork.class, virtualNetworkKey)
+ .child(VirtualLinks.class)
+ .child(VirtualLink.class)
+ .build();
+
+ virtualNodeChangeListenerReg = dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(
+ LogicalDatastoreType.CONFIGURATION, virtualNodeIid), new VirtualNodeChangeListener());
+ virtualLinkChangeListenerReg = dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(
+ LogicalDatastoreType.CONFIGURATION, virtualLinkIid), new VirtualLinkChangeListener());
+
+ LOG.debug("Initialized the virtual network computation unit for the user {}.", userId.getValue());
+
+ return;
+ }
+
+ public VNComputationUnit(DataBroker dataBroker, VirtualNetwork virtualNetwork) {
+ super();
+
+ this.dataBroker = dataBroker;
+ userId = virtualNetwork.getUserId();
+ routingAlgorithm = new RoutingAlgorithm();
+ virtualRouters = new HashSet<>();
+
+ List<VirtualNode> virtualNodes = virtualNetwork.getVirtualNodes().getVirtualNode();
+ Vertex vertex;
+
+ for ( VirtualNode virtualNode : virtualNodes ) {
+ vertex = new Vertex(virtualNode.getNodeId().getValue());
+ routingAlgorithm.addVertex(vertex);
+
+ if ( VirtualNode.NodeType.Vrouter == virtualNode.getNodeType() ) {
+ virtualRouters.add(virtualNode.getNodeId());
+ }
+ }
+
+ List<VirtualLink> virtualLinks = virtualNetwork.getVirtualLinks().getVirtualLink();
+
+ for ( VirtualLink virtualLink : virtualLinks ) {
+ routingAlgorithm.addEdge(new Edge(virtualLink));
+ }
+
+// computeRoute(virtualNetwork);
+
+ return;
+ }
+
+ /**
+ * Compute a shortest virtual path from the given source vertex to
+ * target one without any constraint.
+ *
+ * @param source The given source virtual node id.
+ * @param target The given target virtual node id.
+ * @return The virtual path if successful,or null otherwise.
+ */
+ public VirtualPath computePath(VirtualNodeId source, VirtualNodeId target) {
+ List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),
+ routingAlgorithm.getVertex(target.getValue()));
+
+ if ( null == edges || edges.isEmpty() ) {
+ return null;
+ }
+
+ List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink> virtualLinks =
+ new ArrayList<>(edges.size());
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink virtualLink;
+ long metric = 0;
+ long delay = 0;
+
+ for ( Edge edge : edges ) {
+ virtualLink = new VirtualLinkBuilder()
+ .setLinkId(new VirtualLinkId(edge.getId()))
+ .setOrder((long) virtualLinks.size())
+ .build();
+ virtualLinks.add(virtualLink);
+
+ metric += edge.getMetric();
+// delay += edge.getDelay();
+ }
+
+ VirtualPath virtualPath = new VirtualPathBuilder()
+ .setPathId(new VirtualPathId(UUID.randomUUID().toString()))
+ .setVirtualLink(virtualLinks)
+ .setMetric(metric)
+ .setBandwidth(0L)
+ .setDelay(delay)
+ .build();
+
+ return virtualPath;
+ }
+
+ /**
+ * Compute a shortest virtual path with the given bandwidth from the
+ * given source vertex to target one.
+ *
+ * @param source The given source virtual node id.
+ * @param target The given target virtual node id.
+ * @param bandwidth The given bandwidth for the virtual path.
+ * @return The virtual path if successful,or null otherwise.
+ */
+ public VirtualPath computePath(VirtualNodeId source, VirtualNodeId target, long bandwidth) {
+ List<Edge> edges = routingAlgorithm.computePath(routingAlgorithm.getVertex(source.getValue()),
+ routingAlgorithm.getVertex(target.getValue()), bandwidth);
+
+ if ( null == edges || edges.isEmpty() ) {
+ return null;
+ }
+
+ List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink> virtualLinks =
+ new ArrayList<>(edges.size());
+ org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.generic.virtual.network.rev151010.virtual.path.instance.VirtualLink virtualLink;
+ long metric = 0;
+ long delay = 0;
+
+ for ( Edge edge : edges ) {
+ edge.setBandwidth(edge.getBandwidth() - bandwidth);
+ routingAlgorithm.updateEdge(edge);
+
+ virtualLink = new VirtualLinkBuilder()
+ .setLinkId(new VirtualLinkId(edge.getId()))
+ .setOrder((long)virtualLinks.size())
+ .build();
+ virtualLinks.add(virtualLink);
+
+ metric += edge.getMetric();
+// delay += edge.getDelay();
+ }
+
+ VirtualPath virtualPath = new VirtualPathBuilder()
+ .setPathId(new VirtualPathId(UUID.randomUUID().toString()))
+ .setVirtualLink(virtualLinks)
+ .setMetric(metric)
+ .setBandwidth(bandwidth)
+ .setDelay(delay)
+ .build();
+
+ return virtualPath;
+ }
+
+ @Override
+ public void close() throws Exception {
+ if ( null != virtualNodeChangeListenerReg ) {
+ virtualNodeChangeListenerReg.close();
+ }
+
+ if ( null != virtualLinkChangeListenerReg ) {
+ virtualLinkChangeListenerReg.close();
+ }
+
+ return;
+ }
+
+ /**
+ * Compute the routes between all virtual routers in the virtual
+ * network, and store or update them into the data store.
+ */
+ private void computeRoute() {
+ Map<VirtualRouteKey, VirtualPath> routes = new HashMap<>();
+ VirtualPath virtualPath;
+
+ for ( VirtualNodeId source : virtualRouters ) {
+ for ( VirtualNodeId target : virtualRouters ) {
+ if ( !source.equals(target) ) {
+ virtualPath = computePath(source, target);
+
+ if ( null == virtualPath ) {
+ continue;
+ }
+
+ routes.put(new VirtualRouteKey(source, target), virtualPath);
+ }
+ }
+ }
+
+ updateRoute(routes);
+
+ return;
+ }
+
+ /**
+ * Compute the routes between all virtual routers in the virtual
+ * network, and store them into the virtual network.
+ *
+ * @param virtualNetwork The virtual network to store the routes.
+ */
+ private void computeRoute(VirtualNetwork virtualNetwork) {
+ List<VirtualRoute> virtualRoutes = virtualNetwork.getVirtualRoutes().getVirtualRoute();
+ List<VirtualPath> virtualPaths = virtualNetwork.getVirtualPaths().getVirtualPath();
+ VirtualRoute virtualRoute;
+ VirtualPath virtualPath;
+
+ for ( VirtualNodeId source : virtualRouters ) {
+ for ( VirtualNodeId target : virtualRouters ) {
+ if ( !source.equals(target) ) {
+ virtualPath = computePath(source, target);
+
+ if ( null == virtualPath ) {
+ continue;
+ }
+
+ virtualRoute = new VirtualRouteBuilder().setSrcNodeId(source)
+ .setDestNodeId(target)
+ .setPathId(virtualPath.getPathId())
+ .build();
+
+ virtualPaths.add(virtualPath);
+ virtualRoutes.add(virtualRoute);
+ }
+ }
+ }
+
+ return;
+ }
+
+ /**
+ * Update the given routes into the data store. If the route
+ * already exists, remove it's old virtual path and store the
+ * given new one into the data store.
+ *
+ * @param routes The given routes to be updated.
+ */
+ private void updateRoute(Map<VirtualRouteKey, VirtualPath> routes) {
+ ReadWriteTransaction readWriteTransaction = dataBroker.newReadWriteTransaction();
+
+ VirtualNetworkKey virtualNetworkKey = new VirtualNetworkKey(new VirtualNetworkId(userId.getValue()));
+ InstanceIdentifier<VirtualRoute> virtualRouteIid;
+ InstanceIdentifier<VirtualPath> virtualPathIid;
+ Optional<VirtualRoute> result;
+ VirtualRoute virtualRoute;
+
+ for ( Map.Entry<VirtualRouteKey, VirtualPath> route : routes.entrySet() ) {
+ virtualRouteIid = InstanceIdentifier.builder(VirtualNetworks.class)
+ .child(VirtualNetwork.class, virtualNetworkKey)
+ .child(VirtualRoutes.class)
+ .child(VirtualRoute.class, route.getKey())
+ .build();
+
+ try {
+ result = readWriteTransaction.read(LogicalDatastoreType.CONFIGURATION, virtualRouteIid).get();
+ } catch ( InterruptedException exception ) {
+ LOG.error("Can not read the virtual route from the virtual node {} to {}.",
+ route.getKey().getSrcNodeId().getValue(), route.getKey().getDestNodeId().getValue());
+
+ continue;
+ } catch ( ExecutionException exception ) {
+ LOG.error("Can not read the virtual route from the virtual node {} to {}.",
+ route.getKey().getSrcNodeId().getValue(), route.getKey().getDestNodeId().getValue());
+
+ continue;
+ }
+
+ if ( result.isPresent() ) {
+ virtualRoute = result.get();
+ virtualPathIid = InstanceIdentifier.builder(VirtualNetworks.class)
+ .child(VirtualNetwork.class, virtualNetworkKey)
+ .child(VirtualPaths.class)
+ .child(VirtualPath.class, new VirtualPathKey(virtualRoute.getPathId()))
+ .build();
+ readWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, virtualPathIid);
+ }
+
+ virtualPathIid = InstanceIdentifier.builder(VirtualNetworks.class)
+ .child(VirtualNetwork.class, virtualNetworkKey)
+ .child(VirtualPaths.class)
+ .child(VirtualPath.class, route.getValue().getKey())
+ .build();
+ readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualPathIid, route.getValue(), true);
+
+ virtualRoute = new VirtualRouteBuilder().setSrcNodeId(route.getKey().getSrcNodeId())
+ .setDestNodeId(route.getKey().getDestNodeId())
+ .setPathId(route.getValue().getPathId())
+ .build();
+ readWriteTransaction.put(LogicalDatastoreType.CONFIGURATION, virtualRouteIid, virtualRoute, true);
+ }
+
+ readWriteTransaction.submit();
+
+ return;
+ }
+
+ /**
+ * A listener to change events related to virtual nodes being
+ * added, removed or updated.
+ *
+ * @author Zhigang Ji
+ */
+ private class VirtualNodeChangeListener implements DataTreeChangeListener<VirtualNode> {
+ @Override
+ public void onDataTreeChanged(Collection<DataTreeModification<VirtualNode>> changes) {
+ for (DataTreeModification<VirtualNode> change: changes) {
+ DataObjectModification<VirtualNode> rootNode = change.getRootNode();
+ switch (rootNode.getModificationType()) {
+ case WRITE:
+ if (rootNode.getDataBefore() == null) {
+ VirtualNode virtualNode = rootNode.getDataAfter();
+ Vertex vertex = new Vertex(virtualNode.getNodeId().getValue());
+
+ routingAlgorithm.addVertex(vertex);
+
+ if (VirtualNode.NodeType.Vrouter == virtualNode.getNodeType()) {
+ virtualRouters.add(virtualNode.getNodeId());
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * A listener to change events related to virtual links being
+ * added, removed or updated.
+ *
+ * @author Zhigang Ji
+ */
+ private class VirtualLinkChangeListener implements DataTreeChangeListener<VirtualLink> {
+ @Override
+ public void onDataTreeChanged(Collection<DataTreeModification<VirtualLink>> changes) {
+ boolean needRerouting = false;
+ for (DataTreeModification<VirtualLink> change: changes) {
+ DataObjectModification<VirtualLink> rootNode = change.getRootNode();
+ switch (rootNode.getModificationType()) {
+ case WRITE:
+ if (rootNode.getDataBefore() == null) {
+ VirtualLink virtualLink = rootNode.getDataAfter();
+ Edge edge = new Edge(virtualLink);
+
+ routingAlgorithm.addEdge(edge);
+
+ if (virtualRouters.contains(virtualLink.getSrcNodeId())
+ && virtualRouters.contains(virtualLink.getDestNodeId())) {
+ needRerouting = true;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if ( needRerouting ) {
+ computeRoute();
+ }
+ }
+ }
+ }
+}