Initial commit of Graph Model.
This is the patch set 1/3 to implement the Path Computation Algorithms
to implement a full feature PCE server in conformity to RFC5440.
Details information about the yang model, REST and Java API are
provided in docs/graph directory.
JIRA: BGPCEP-858
Change-Id: Icf7b8320185f9d94377c76cdaecba836b7ef3bc5
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
Co-authored-by: Philippe Niger <philippe.niger@orange.com>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
<scope>import</scope>
<type>pom</type>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>graph-artifacts</artifactId>
+ <version>${project.version}</version>
+ <scope>import</scope>
+ <type>pom</type>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>topology-artifacts</artifactId>
<type>xml</type>
<scope>runtime</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>features-graph</artifactId>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <scope>runtime</scope>
+ </dependency>
<dependency>
<groupId>org.opendaylight.bgpcep</groupId>
<artifactId>features-rsvp</artifactId>
--- /dev/null
+.. _graph-user-guide-graph-model:
+
+Graph Model Overview
+====================
+This section provides a high-level overview of the Graph Model.
+
+.. contents:: Contents
+ :depth: 2
+ :local:
+
+Graph Theory and Path Computation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The primary goal of Graph and Algorithms features, is to be able to compute
+constrainted path among a given IP/MPLS network. Such path could be used to
+enforce connectivity by means of RSVP-TE or Segment Routing TE through PCEP
+protocol or simply provide a solution to answer a path request (coming from
+RESTCONF API or a PcRequest message).
+
+In IP/MPLS networks, these path computation algorithms need to access to a
+representation of the network topology which is, in general, denoted as
+*Traffic Engineering Database (TED)* in reference to information convey by
+the IGP Traffic Engineering routing protocols such as OSPF-TE or IS-IS-TE.
+There is many way to store this TED and the IETF is in the process of
+defining the corresponding yang model (draft-ietf-teas-yang-te-topo-22.txt).
+But, most of these path computation algorithms have been designed with a
+particular representation of network model for perfomrance efficiency: a Graph.
+This latter is denoted in literature as *G(V, E)* where V, the Vertices,
+represent the nodes (e.g. routers) and E, the Edges, represent the link between
+nodes. There is numerous graph type, but for path computation, a Directed and
+Connected Graph is recommended, again for performance efficiency.
+
+A Connected Graph is a particular graph type where each pair of vertices forms
+the endpoints of a path. It is used because path computation algorithms need to
+progress smoothly in the graph without searching for the next hops in the whole
+graph (mostly for performance issue) and also because some algorithms need to
+mark Vertices as visited once processed to avoid loop. Connected Graph is a
+particular graph type where each pair of vertices forms the endpoints of a
+path.
+
+In general, for modern networks (i.e. with optical links), links are considered
+as full-duplex. Thus, from a resources (mostly bandwidth) point of view, going
+from node *A to B* will consumes resources (mostly bandwidth) on the link from
+A to B while keeping intact resources on the link from B to A. So, the graph
+model needs to reflect this behaviour. The graph that represents the network
+will used Directed Edges for that purposes. So, the recommended graph is a
+Directed Graph (sometimes also named Oriented Graph). As a consequence, it is
+necessary to create 2 edges between 2 vertices: *A to B* and *B to A*.
+
+For more information, reader could refer to Graph Theory
+e.g. https://en.wikipedia.org/wiki/Graph_theory and Path Computation algorithms
+e.g. Shortest Path First (SPF) https://en.wikipedia.org/wiki/Shortest_path_problem
+and Constrainted Shortest Path First (CSPF) https://en.wikipedia.org/wiki/Constrained_Shortest_Path_First.
+
+Yang Model for Graph
+^^^^^^^^^^^^^^^^^^^^
+
+In order to manipulate the Graph within the OpenDaylight Data Store, the given
+yang model has been provided. It defines Edges and Vertices. Edges are enhanced
+by Edges Attributes which are define all link attributes we could collect from
+real network (e.g. through BGP Link State). Vertices are enhanced by Prefixes
+in order to find quickly where End Points of a path are attached in the Graph.
+It also serves to store Segment Routing information when computing path for
+Segment Routing TE setup.
+
+A new yang model is provided as an alternative to the IETF yang-te-topo model
+and IETF RFC8345 for several reasons:
+
+ * Some link and node parameters (e.g. Segment Routing, TE Metric extensions)
+ which are available in IP/MPLS networks, through the IGP-TE or BGP-LS
+ protocols (see Linkstate Routes in BGP RIB) are not present in the IETF
+ ted model
+ * Node and link identifier are represented as string in the IETF ted model
+ which it is not efficient when looking into a HashMap() to find node or
+ link by its identifier
+ * Even if LinkstateTopologyBuilder() provided mechanism to fulfil IETF ted
+ model in the datastore, the NodeHolder an TpHolder classes have been
+ defined as private, and thus could not be used outside the
+ LinkstateTopologyBuilder() class
+
+Graph and Algorithm have been also designed to be used by other projects
+(e.g. openflow) which not control IP/MPLS network. Thus, even if the graph
+model addresses in first case the IP/MPLS network, its genericity allows
+it to be suitable for other network types.
+
+The yand model for the Graph is as follow:
+
+.. code-block:: console
+
+ module: graph
+ +--rw graph-topology
+ +--rw graph* [name]
+ +--rw name string
+ +--rw domain-scope? enumeration
+ +--rw asn? uint32
+ +--rw vertex* [vertex-id]
+ | +--rw vertex-id uint64
+ | +--rw name? string
+ | +--rw router-id? inet:ip-address
+ | +--rw vertex-type? enumeration
+ | +--rw srgb
+ | | +--rw lower-bound? uint32
+ | | +--rw range-size? uint32
+ | +--rw asn? uint32
+ +--rw edge* [edge-id]
+ | +--rw edge-id uint64
+ | +--rw local-vertex-id? uint64
+ | +--rw remote-vertex-id? uint64
+ | +--rw name? string
+ | +--rw edge-attributes
+ | +--rw metric? uint32
+ | +--rw te-metric? uint32
+ | +--rw admin-group? uint32
+ | +--rw local-address? inet:ip-address
+ | +--rw remote-address? inet:ip-address
+ | +--rw local-identifier? uint32
+ | +--rw remote-identifier? uint32
+ | +--rw max-link-bandwidth? decimal-bandwidth
+ | +--rw max-resv-link-bandwidth? decimal-bandwidth
+ | +--rw unreserved-bandwidth* [class-type]
+ | | +--rw class-type uint8
+ | | +--rw bandwidth? decimal-bandwidth
+ | +--rw delay? delay
+ | +--rw min-max-delay
+ | | +--rw min-delay? delay
+ | | +--rw max-delay? delay
+ | +--rw jitter? delay
+ | +--rw loss? loss
+ | +--rw residual-bandwidth? decimal-bandwidth
+ | +--rw available-bandwidth? decimal-bandwidth
+ | +--rw utilized-bandwidth? decimal-bandwidth
+ | +--rw adj-sid? uint32
+ | +--rw backup-adj-sid? uint32
+ | +--rw srlgs* uint32
+ +--rw prefix* [prefix]
+ +--rw prefix inet:ip-prefix
+ +--rw prefix-sid? uint32
+ +--rw node-sid? boolean
+ +--rw vertex-id? uint64
+
+Java Class for Connected Graph
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Yang model represents data as a Flat Tree hierarchy. However, this particular
+graph representation (without a specific storage engine capabilities) is not
+very useful for Path Computation due to lower performance compared to other
+Graph types. Of course path computation algorithms could play with a such
+Graph, but at the cost of performance issue as algorithms need to search the
+neighbours of a vertices at each step when progressing in the graph. This will
+decrease the performance by a factor of *N* to *N²* depending of the
+algorithms. For large scale network, say 1000+ nodes, it is too high.
+
+Yang syntax authorizes reference to other grouping or leaf with 'leafref'.
+This could allows from a Vertex to access to Edges. However, it is not possible
+to achieve a cross reference between Vertex and Edge. In Connected Graph,
+both Vertex and Edge must reference each together: from Vertex it is needed to
+access directly at the list of Edges connected to this Vertex, and from Edge,
+it is need to access directly at the source and destination Vertex.
+
+So, to overcome this limitation, the implemented Graph is composed of two
+pieces:
+
+ * A standard Graph modeled in yang and stored in the Data Store
+ * A Connected Graph version based on the yang model but stored in memory only
+
+
+The connected version of Vertex is composed of:
+
+.. code-block:: java
+
+ /* Reference to input and output Connected Edge within the Connected Graph */
+ private ArrayList<ConnectedEdgeImpl> input = new ArrayList<>();
+ private ArrayList<ConnectedEdgeImpl> output = new ArrayList<>();
+
+ /* List of Prefixes announced by this Vertex */
+ private ArrayList<Prefix> prefixes = new ArrayList<>();
+
+ /* Reference to the Vertex of the standard Graph associated to the Connected Graph */
+ private Vertex vertex = null;
+
+Where distinction is made between input and output Edges in order to respect the Directed Graph
+behviour.
+
+The connected version of Edges is composed of:
+
+.. code-block:: java
+
+ /* Reference to Source and Destination Connected Vertex within the Connected Graph */
+ private ConnectedVertexImpl source;
+ private ConnectedVertexImpl destination;
+
+ /* Reference to the Edge within the Graph associated to the Connected Graph */
+ private Edge edge;
+
+Where source and destination Vertices also ease to implement the Directed Graph.
+
+And finally, the connected version of Graph is composed of:
+
+.. code-block:: java
+
+ /* List of Connected Vertics that composed this Connected Graph */
+ private final HashMap<Long, ConnectedVertexImpl> vertices = new HashMap<>();
+
+ /* List of Connected Edges that composed this Connected Graph */
+ private final HashMap<Long, ConnectedEdgeImpl> edges = new HashMap<>();
+
+ /* List of IP prefix attached to Vertices */
+ private final HashMap<IpPrefix, Prefix> prefixes = new HashMap<>();
+
+ /* Reference to the non connected Graph stored in DataStore */
+ private Graph graph;
+
+Where Vertices, Edges and Prefixes are stored in *HashMap* to speed up the
+access of a given element of the Graph.
+
+Note that the Unique Key identifier for Connected Edge and Connected Vertex
+must not be equal to zero (and as a consequence the Edge and Vertex key).
+This restriction is due to some algorithms that used the value 0 as a
+special indication during the path computation.
+
--- /dev/null
+.. _graph-user-guide-manage-graph:
+
+Manage Graph
+============
+This section explains how to manipulate the Graph through REST API.
+
+.. contents:: Contents
+ :depth: 2
+ :local:
+
+Concept
+^^^^^^^
+
+The connected Graph is not accessible through the REST API as it is not
+posssible to represent connected Edges and Vertices with yang model (see
+Graph Overview). Thus, Graph feature provides a new service named
+ConnectedGraphProvider published in Karaf. This service maintains an
+up-to-date list of Connected Graph stored in memory and allows to:
+
+ * Get Connected Graph by name or GraphKey
+ * Create Connected Graph
+ * Add existing graph to create associated Connected Graph
+ * Delete existing Graph identify by its GraphKey
+
+Then, Connected Graph provides method to manage Vertices, Edges and Prefix.
+The ConnectedGraphProvider is also in charge to maintain up to date the Graph
+associated to the Connected Graph in the OpenDaylight operational Data Store.
+
+In fact, two graphs are stored in the Data Store:
+
+ * Operational Graph in ``restconf/operational`` which is the graph
+ associated with the Connected Graph stored in memory
+ * Configuration Graph in ``restconf/config`` which is the graph that
+ could be create / modify / delete in order to produce the Connected
+ Graph and thus, the associated Graph stored in operational Data Store
+
+It is also possible to add / delete Vertices, Edges and Prefix on an existing
+Graph through the REST API.
+
+
+JAVA API
+^^^^^^^^
+
+Developper will refer to the Java Doc to manage Connected and standard Graph.
+The main principle is as follow:
+
+1. First Create a Connected Graph through the ConnectedGraphProvider which is a
+new service provided by the Graph feature through Karaf:
+
+.. code-block:: java
+
+ ConnectedGraph cgraph = graphProvider.createConnectedGraph("example", GraphType.IntraDomain);
+
+Or by adding an initial graph:
+
+.. code-block:: java
+
+ Graph graph = new GraphBuilder().setName("example").setGraphType(GraphType.IntraDomain).build();
+ ConnectedGraph cgraph = graphProvider.addGraph(graph);
+
+Where graphProvider is obtained from blueprint.
+
+2. Once created, the Connected Graph offers various method to manage Vertices
+and Edges. For example:
+
+.. code-block:: java
+
+ /* Add a Vertex */
+ Vertex vertex = new VertexBuilder().setVertexId(Uint64.ValueOf(1)).build();
+ cgraph.addVertex(vertex);
+
+ /* Add an Edge */
+ Edge edge = new EdgeBuilder().setEdgeId(Uint64.ValueOf(1)).build();
+ cgraph.addEdge(edge);
+
+ ...
+
+REST API
+^^^^^^^^
+
+This section provides the list of REST method that could be used to manage
+Graph.
+
+Get Graph
+'''''''''
+
+Graphs are stored in operation and config Data Store. Thus there are accessible
+through the ``graph:graph-topology`` namespace as follow:
+
+-----
+
+**URL:** ``restconf/operational/graph:graph-topology``
+
+**Method:** ``GET``
+
+**Response Body:**
+
+.. code-block:: json
+
+ {
+ "graph-topology": {
+ "graph": [
+ {
+ "name": "example",
+ "vertex": [
+ {
+ "vertex-id": 2,
+ "name": "r2",
+ "vertex-type": "standard"
+ },
+ {
+ "vertex-id": 1,
+ "name": "r1",
+ "vertex-type": "standard"
+ }
+ ],
+ "graph-type": "intra-domain"
+ }
+ ]
+ }
+ }
+
+Graphs publish in the configuration Data Store are also accessible through REST
+API with the same namespace as follow:
+
+-----
+
+**URL:** ``restconf/config/graph:graph-topology``
+
+**Method:** ``GET``
+
+**Response Body:**
+
+.. code-block:: json
+
+ {
+ "graph-topology": {
+ "graph": [
+ {
+ "name": "example",
+ "vertex": [
+ {
+ "vertex-id": 2,
+ "name": "r2",
+ "vertex-type": "standard"
+ },
+ {
+ "vertex-id": 1,
+ "name": "r1",
+ "vertex-type": "standard"
+ }
+ ],
+ "graph-type": "intra-domain"
+ }
+ ]
+ }
+ }
+
+Create Graph
+''''''''''''
+
+Graphs could be created with PUT method. In this case, all previously
+configured graphs are removed from both the configuration and operational
+Data Store. This includes all modification and associated Connected Graphs.
+
+-----
+
+**URL:** ``restconf/config/graph:graph-topology``
+
+**Method:** ``PUT``
+
+**Content-Type:** ``application/json``
+
+**Request Body:**
+
+.. code-block:: json
+
+ {
+ "graph-topology": {
+ "graph": [
+ {
+ "name": "example",
+ "graph-type": "intra-domain",
+ "vertex": [
+ {
+ "vertex-id": 1,
+ "name": "r1"
+ },
+ {
+ "vertex-id": 2,
+ "name": "r2"
+ }
+ ],
+ "edge": [
+ {
+ "edge-id": 1,
+ "name": "r1 - r2",
+ "local-vertex-id": 1,
+ "remote-vertex-id": 2
+ },
+ {
+ "edge-id": 2,
+ "name": "r2 - r1",
+ "local-vertex-id": 2,
+ "remote-vertex-id": 1
+ }
+ ]
+ }
+ ]
+ }
+ }
+
+@line 5: **name** The Graph identifier. Must be unique.
+
+@line 6: **graph-type** The type of the Graph: intra-domain or inter-domain.
+
+@line 7: **vertex** - List of Vertices. Each Vertex ID must be unique.
+
+@line 17: **edges** - List of Edges. Each Edge ID must be unique.
+
+@line 21: **local-vertex-id** - Vertex ID where the Edge is connected from.
+The vertex ID must correspond to vertex that is present in the vertex list,
+otherwise, the connection will not be estabished in the Connected Graph.
+
+@line 22: **remote-vertex-id** - Vertex ID where the Edge is connected to.
+The vertex ID must correspond to vertex that is present in the vertex list,
+otherwise, the connection will not be estabished in the Connected Graph.
+
+Add Graph
+'''''''''
+
+It is also possible to add a Graph to the existing list. POST method will
+be used instead of PUT. Body and URL remains the same.
+
+Delete Graph
+''''''''''''
+
+Removing a graph used the DELETE method as follow:
+
+-----
+
+**URL:** ``restconf/config/graph:graph-topology/graph/example``
+
+**Method:** ``DELETE``
+
+The name of the graph i.e. the Graph Key to be deleted must be provide
+within the URL.
+
+Add Vertices
+''''''''''''
+
+One or more vertex could be added to a Graph. If the graph doesn't exist,
+it will be automatically created. Only POST method must be used.
+
+-----
+
+**URL:** ``restconf/config/graph:graph-topology/graph/example``
+
+**Method:** ``POST``
+
+**Content-Type:** ``application/json``
+
+**Request Body:**
+
+.. code-block:: json
+
+ {
+ "vertex": [
+ {
+ "vertex-id": 100,
+ "name": "r100",
+ "router-id": "192.168.1.100"
+ }
+ ]
+ }
+
+Delete Vertex
+'''''''''''''
+
+Removing a vertex used the DELETE method as follow:
+
+-----
+
+**URL:** ``restconf/config/graph:graph-topology/graph/example/vertex/10``
+
+**Method:** ``DELETE``
+
+The Vertex to be deleted is identified by its Vertex Id and must be provide
+within the URL.
+
+Add Edges
+'''''''''
+
+One or more edges could be added to a Graph. If the graph doesn't exist,
+it will be automatically created. Only POST method must be used.
+
+-----
+
+**URL:** ``restconf/config/graph:graph-topology/graph/example``
+
+**Method:** ``POST``
+
+**Content-Type:** ``application/json``
+
+**Request Body:**
+
+.. code-block:: json
+
+ {
+ "edge": [
+ {
+ "edge-id": 10,
+ "name": "r1 - r2",
+ "local-vertex-id": 1,
+ "remote-vertex-id": 2
+ },
+ {
+ "edge-id": 20,
+ "name": "r2 - r1",
+ "local-vertex-id": 2,
+ "remote-vertex-id": 1
+ }
+ ]
+ }
+
+Delete Edge
+'''''''''''
+
+Removing an edge used the DELETE method as follow:
+
+-----
+
+**URL:** ``restconf/config/graph:graph-topology/graph/example/edge/10``
+
+**Method:** ``DELETE``
+
+The Edge to be deleted is identified by its Edge Id and must be provide
+within the URL.
+
+Add Prefixes
+''''''''''''
+
+One or more prefixe could be added to a Graph. If the graph doesn't exist,
+it will be automatically created. Only POST method must be used.
+
+-----
+
+**URL:** ``restconf/config/graph:graph-topology/graph/example``
+
+**Method:** ``POST``
+
+**Content-Type:** ``application/json``
+
+**Request Body:**
+
+.. code-block:: json
+
+ {
+ "prefix": [
+ {
+ "prefix": "192.168.1.0/24",
+ "vertex-id": 1
+ }
+ ]
+ }
+
+Delete Prefix
+'''''''''''''
+
+Removing a prefix used the DELETE method as follow:
+
+-----
+
+**URL:** ``restconf/config/graph:graph-topology/graph/example/prefix/192%2e168%2e1%2e0%2f24``
+
+**Method:** ``DELETE``
+
+The Prefix to be deleted is identified by its Prefix Id and must be provide
+within the URL. As the prefix identifier is the ip prefix, '.' and '/' must
+be replace by their respective ASCII representation i.e. '%2e' for dot and
+'%2f' for slash.
+
--- /dev/null
+.. _graph-user-guide-running-graph:
+
+Running Graph
+=============
+This section explains how to install Graph plugin.
+
+1. Install Graph feature - ``feature-graph``.
+ Also, for sake of this sample, it is required to install RESTCONF.
+ In the Karaf console, type command:
+
+ .. code-block:: console
+
+ feature:install feature-restconf feature-graph
+
+2. The Graph plugin contains a default empty configuration, which is applied
+ after the feature starts up. One instance of Graph plugin is created
+ (named *graph-topology*), and its presence can be verified via REST:
+
+ **URL:** ``restconf/config/graph:graph-topology``
+
+ **Method:** ``GET``
+
+ **Response Body:**
+
+ .. code-block:: json
+
+ {}
+
+ It is also posible to access to the operational graph topology which is
+ also empty by default via REST:
+
+ **URL:** ``restconf/operational/graph:graph-topology``
+
+ **Method:** ``GET``
+
+ **Response Body:**
+
+ .. code-block:: json
+
+ {}
--- /dev/null
+.. _graph-user-guide:
+
+GRAPH Model User Guide
+======================
+This guide contains information on how to use the OpenDaylight Graph Model plugin that is the basis
+for Path Computation Algorithms. Graph and algorithms are used in the PCE Server part to compute
+path. This path will then serves to fulfil Explicit Route Object (ERO) for PCResponse message in
+turn of a PCRequest message.
+
+Note: The user should learn about Graph Theory and (Constraint) Shortest Path First algorithms.
+
+
+.. toctree::
+ :maxdepth: 1
+
+ graph-user-guide-graph-model
+ graph-user-guide-running-graph
+ graph-user-guide-manage-graph
bgp/index
bmp/index
pcep/index
+ graph/index
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2019 Orange Labs 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>feature-repo-parent</artifactId>
+ <version>0.14.0-SNAPSHOT</version>
+ <relativePath>../../../feature-repo-parent</relativePath>
+ </parent>
+
+ <artifactId>features-graph</artifactId>
+ <packaging>feature</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>odl-bgpcep-graph</artifactId>
+ <type>xml</type>
+ <classifier>features</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>odl-bgpcep-graph-api</artifactId>
+ <type>xml</type>
+ <classifier>features</classifier>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2019 Orange Labs 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>single-feature-parent</artifactId>
+ <version>0.14.0-SNAPSHOT</version>
+ <relativePath>../../../single-feature-parent</relativePath>
+ </parent>
+
+ <artifactId>odl-bgpcep-graph-api</artifactId>
+ <packaging>feature</packaging>
+ <name>OpenDaylight :: GRAPH :: API</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>graph-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>odl-mdsal-model-rfc6991</artifactId>
+ <type>xml</type>
+ <classifier>features</classifier>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>odl-mdsal-model-odl-uint24</artifactId>
+ <type>xml</type>
+ <classifier>features</classifier>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2019 Orange Labs 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>single-feature-parent</artifactId>
+ <version>0.14.0-SNAPSHOT</version>
+ <relativePath>../../../single-feature-parent</relativePath>
+ </parent>
+
+ <artifactId>odl-bgpcep-graph</artifactId>
+ <packaging>feature</packaging>
+ <name>OpenDaylight :: GRAPH</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>odl-bgpcep-graph-api</artifactId>
+ <type>xml</type>
+ <classifier>features</classifier>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>odl-mdsal-broker</artifactId>
+ <type>xml</type>
+ <classifier>features</classifier>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>graph-impl</artifactId>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2019 Orange Labs 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.odlparent</groupId>
+ <artifactId>odlparent-lite</artifactId>
+ <version>6.0.4</version>
+ <relativePath/>
+ </parent>
+
+ <artifactId>features-aggregator-graph</artifactId>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <version>0.14.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>features-graph</module>
+ <module>odl-bgpcep-graph-api</module>
+ <module>odl-bgpcep-graph</module>
+ </modules>
+
+ <properties>
+ <maven.deploy.skip>true</maven.deploy.skip>
+ <maven.install.skip>true</maven.install.skip>
+ </properties>
+</project>
<modules>
<module>bgp</module>
<module>pcep</module>
+ <module>graph</module>
<module>bgpcep-extras</module>
<module>bmp</module>
<module>rsvp</module>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2019 Orange Labs. 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>binding-parent</artifactId>
+ <version>0.14.0-SNAPSHOT</version>
+ <relativePath>../../binding-parent</relativePath>
+ </parent>
+
+ <artifactId>graph-api</artifactId>
+ <description>Graph Network Topology API</description>
+ <packaging>bundle</packaging>
+ <name>${project.artifactId}</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.model</groupId>
+ <artifactId>odl-uint24</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.binding.model.ietf</groupId>
+ <artifactId>rfc6991-ietf-inet-types</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>concepts</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-common</artifactId>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2019 Orange. 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.graph;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Edge;
+
+/**
+ * Connected Edge class is the connected version of the Edge class from the graph yang model.
+ *
+ * <p>
+ * It is composed of a reference to the associated Edge class from the Graph class,
+ * a unique Key identifier in the associated Connected Graph,
+ * and two references to the associated Connected Vertex in the connected Graph: source and destination.
+ * <pre>
+ * {@code
+ * --------------------------- --------------------------------
+ * | Source Connected Vertex |---- Connected Edge --->| Destination Connected Vertex |
+ * --------------------------- --------------------------------
+ * }
+ * </pre>
+ *
+ * @author Olivier Dugeon
+ * @author Philippe Niger
+ */
+public interface ConnectedEdge {
+ /**
+ * Returns unique key associated to this Connected Edge.
+ *
+ * @return Edge Key
+ */
+ @NonNull Long getKey();
+
+ /**
+ * Returns the Edge from the Graph associated to this connection.
+ *
+ * @return Edge associated to this connection
+ */
+ @NonNull Edge getEdge();
+
+ /**
+ * Returns the source Connected Vertex from the Connected Graph associated to this Connected Edge.
+ *
+ * @return Source Connected Vertex
+ */
+ @Nullable ConnectedVertex getSource();
+
+ /**
+ * Returns the destination Connected Vertex from the Connected Graph associated to this Connected Edge.
+ *
+ * @return Destination Connected Vertex
+ */
+ @Nullable ConnectedVertex getDestination();
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 Orange. 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.graph;
+
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.Graph;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Edge;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.EdgeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Vertex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.VertexKey;
+
+/**
+ * Connected Graph class is the connected version of the Graph class from the graph yang model.
+ *
+ * <p>
+ * Connected Graph is composed by Connected Vertex, Connected Edges and Prefix. It models Unidirectional Connected
+ * Graph (see graph theory). So, Edge and Connected Edge are unidirectional, thus to connect bi-directionally 2 vertices
+ * Va and Vb, it is necessary to setup 2 edges: Va to Vb and Vb to Va.
+ * <pre>
+ * {@code
+ * -------------- --------------------------- --------------
+ * | Connected |---->| Connected Edge Va to Vb |--->| Connected |
+ * ---->| Vertex | --------------------------- | Vertex |---->
+ * | | | |
+ * | - Key (Va) | | - Key (Vb) |
+ * <----| - Vertex | --------------------------- | - Vertex |<----
+ * | |<----| Connected Edge Vb to Va |<---| |
+ * -------------- --------------------------- --------------
+ * }
+ * </pre>
+ *
+ * @author Olivier Dugeon
+ * @author Philippe Niger
+ */
+public interface ConnectedGraph {
+
+ /**
+ * Returns the Graph associated to this Connected Graph.
+ *
+ * @return Graph
+ */
+ Graph getGraph();
+
+ /**
+ * Returns the list of Connected Vertices that form this graph.
+ *
+ * @return list of Connected Vertices
+ */
+ List<ConnectedVertex> getVertices();
+
+ /**
+ * Returns the Vertex associated to the given key.
+ *
+ * @param key Unique Vertex Identifier
+ * @return Vertex or null if there is no Vertex associated to the given key in this graph
+ */
+ ConnectedVertex getConnectedVertex(Long key);
+
+ /**
+ * Returns the Vertex associated to the given IP address.
+ *
+ * @param address IP address of the Loopback of the Vertex
+ *
+ * @return Vertex or null if there is no Vertex associated to the given IP address in this graph
+ */
+ ConnectedVertex getConnectedVertex(IpAddress address);
+
+ /**
+ * Add Vertex in the Connected Graph. This action will automatically create the associated Connected Vertex and
+ * update the Graph in the DataStore.
+ *
+ * @param vertex Vertex to be added
+ *
+ * @return Connected Vertex associated to the given Vertex
+ */
+ ConnectedVertex addVertex(Vertex vertex);
+
+ /**
+ * Remove the Vertex in the Connected Graph. This action will automatically remove the associated Connected Vertex
+ * and update the Graph in the DataStore.
+ *
+ * @param vertexKey Unique Vertex Identifier
+ */
+ void deleteVertex(VertexKey vertexKey);
+
+ /**
+ * Returns the number of Vertices in the graph.
+ *
+ * @return number of vertices
+ */
+ int getVerticesSize();
+
+ /**
+ * Returns the list of Connected Edges that form this graph.
+ *
+ * @return list of Connected Edges
+ */
+ List<ConnectedEdge> getEdges();
+
+ /**
+ * Returns the Edge associated to the given key.
+ *
+ * @param key Unique Edge Identifier
+ * @return Edge or null if there is no Edge associated to the given key in this graph
+ */
+ ConnectedEdge getConnectedEdge(Long key);
+
+ /**
+ * Returns the Edge associated to the given IP address.
+ *
+ * @param address IP address of the Edge
+ *
+ * @return Edge or null if there is no Edge associated to the given IP address in this graph
+ */
+ ConnectedEdge getConnectedEdge(IpAddress address);
+
+ /**
+ * Add Edge in the Connected Graph. This action will automatically create the associated Connected Edge and
+ * update the Graph in the DataStore.
+ *
+ * @param edge Edge to be added
+ *
+ * @return Connected Edge associated to the given Edge
+ */
+ ConnectedEdge addEdge(Edge edge);
+
+ /**
+ * Remove the Edge in the Connected Graph. This action will automatically remove the associated Connected Edge
+ * and update the Graph in the DataStore.
+ *
+ * @param edgeKey Unique Edge Identifier
+ */
+ void deleteEdge(EdgeKey edgeKey);
+
+ /**
+ * Returns the number of Edges in the graph.
+ *
+ * @return number of edges
+ */
+ int getEdgesSize();
+
+ /**
+ * Returns the list of Prefix that are stored in this graph.
+ *
+ * @return list of Prefix
+ */
+ List<Prefix> getPrefixes();
+
+ /**
+ * Returns the Prefix associated to the given IP prefix.
+ *
+ * @param ippfx IPv4 or IPv6 prefix
+ *
+ * @return Prefix that match the given IPv4 or IPv6 prefix
+ */
+ Prefix getPrefix(IpPrefix ippfx);
+
+ /**
+ * Add Prefix in the Connected Graph. This action will automatically update the Graph in the DataStore.
+ *
+ * @param prefix Prefix to be added
+ *
+ */
+ void addPrefix(Prefix prefix);
+
+ /**
+ * Remove the Prefix in the Connected Graph. This action will automatically update the Graph in the DataStore.
+ *
+ * @param ippfx IPv4 or IPv6 prefix
+ */
+ void deletePrefix(IpPrefix ippfx);
+
+ /**
+ * Clear the Connected Graph by removing all Vertices, Edges and Prefixes. This also remove the associated Graph
+ * in the Datastore.
+ *
+ */
+ void clear();
+
+ /**
+ * Returns the summary of the graph characteristics: number of Vertices, Edges and Prefix.
+ *
+ * @return characteristics of the Graph as a string
+ */
+ String getSummary();
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 Orange. 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.graph;
+
+import java.util.List;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.Graph;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.Graph.DomainScope;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.GraphKey;
+
+/**
+ * Connected Graph Provider is a new service provided by the Graph feature to manage the Connected Graph.
+ *
+ * <p>
+ * It allows to get, create, add and delete Connected Graph. All associated Graph are automatically
+ * stored in the DataStore.
+ *
+ * @author Olivier Dugeon
+ * @author Philippe Niger
+ *
+ */
+
+public interface ConnectedGraphProvider {
+
+ /**
+ * Returns Graph for the given graph name.
+ *
+ * @param name Name of the Graph
+ *
+ * @return Graph
+ */
+ Graph getGraph(String name);
+
+ /**
+ * Returns the Graph for the given graph key.
+ *
+ * @param key Unique Graph Identifier
+ *
+ * @return Graph
+ */
+ Graph getGraph(GraphKey key);
+
+ /**
+ * Returns Connected Graph for the given graph name.
+ *
+ * @param name Name of the Graph
+ *
+ * @return Connected Graph
+ */
+ ConnectedGraph getConnectedGraph(String name);
+
+ /**
+ * Returns Connected Graph for the given graph key.
+ *
+ * @param key Unique Graph Identifier
+ *
+ * @return Connected Graph
+ */
+ ConnectedGraph getConnectedGraph(GraphKey key);
+
+ /**
+ * Returns all registered Connected Graphs.
+ *
+ * @return List of Connected Graph
+ */
+ List<ConnectedGraph> getConnectedGraphs();
+
+ /**
+ * Create Connected Graph and associated Graph for given name and Graph Type. The associated Graph is also stored
+ * in the DataStore.
+ *
+ * @param name Name of the Graph
+ * @param scope Domain scope of the Graph (Intra or Inter domain)
+ *
+ * @return Connected Graph
+ */
+ ConnectedGraph createConnectedGraph(String name, DomainScope scope);
+
+ /**
+ * Add a Graph. This action will automatically create the associated Connected Graph and store is in the DataStore.
+ *
+ * @param graph Graph to be added
+ *
+ * @return Connected Graph
+ */
+ ConnectedGraph addGraph(Graph graph);
+
+ /**
+ * Remove a Graph. This action will automatically delete the associated Connected Graph and store is in the
+ * DataStore.
+ *
+ * @param key Graph Identifier
+ *
+ */
+ void deleteGraph(GraphKey key);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 Orange. 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.graph;
+
+import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Edge;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Vertex;
+
+/**
+ * Connected Vertex class is the connected version of the Vertex class from the graph yang model.
+ *
+ * <p>
+ * It is composed of a reference to the associated Vertex class from the Graph class,
+ * a unique Key identifier in the associated Connected Graph,
+ * and two lists to the associated Connected Edges in the connected Graph: input and output.
+ * <pre>
+ * {@code
+ * -------------
+ * | Connected |
+ * ---->| Vertex |---->
+ * Input Connected Edges { ... | - Key | ... } Output Connected Edges
+ * ---->| - Vertex |---->
+ * -------------
+ * }
+ * </pre>
+ *
+ * @author Olivier Dugeon
+ * @author Philippe Niger
+ *
+ */
+public interface ConnectedVertex {
+
+ /**
+ * Returns unique key associated to this Connected Vertex.
+ *
+ * @return Vertex Key
+ */
+ @NonNull Long getKey();
+
+ /**
+ * Returns Vertex associated to this Connected Vertex.
+ *
+ * @return vertex Vertex
+ */
+ @NonNull Vertex getVertex();
+
+ /**
+ * Returns Connected Edges that has for destination the Connected Vertex identified by its key.
+ *
+ * @param destinationKey Unique Key that identify the destination Vertex
+ *
+ * @return List of Connected Edge
+ */
+ List<ConnectedEdge> getEdgeTo(Long destinationKey);
+
+ /**
+ * Returns the list of incoming Edge for this Connected Vertex.
+ *
+ * @return List of Edge
+ */
+ List<Edge> getInputEdges();
+
+ /**
+ * Returns the list of incoming Connected Edge for this Connected Vertex.
+ *
+ * @return List of Connected Edge
+ */
+ List<ConnectedEdge> getInputConnectedEdges();
+
+ /**
+ * Returns the list of outgoing Edge for this Connected Vertex.
+ *
+ * @return List of Edge
+ */
+ List<Edge> getOutputEdges();
+
+ /**
+ * Returns the list of outgoing Connected Edge for this Connected Vertex.
+ *
+ * @return List of Connected Edge
+ */
+ List<ConnectedEdge> getOutputConnectedEdges();
+
+ /**
+ * Return the list of prefix announced by this Connected Vertex. Prefix contains the associated SID when
+ * Segment Routing is enable.
+ *
+ * @return List of Prefix
+ */
+ List<Prefix> getPrefixes();
+
+}
--- /dev/null
+module graph {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:graph";
+ prefix "graph";
+
+ import ietf-inet-types { prefix inet; revision-date 2013-07-15; }
+ import odl-uint24 { prefix uint24; }
+
+ organization "Orange";
+ contact "Philippe Niger <philippe.niger@orange.com>";
+
+ description
+ "This module contains the graph data model for network topology and datastore
+ used in the Path Computation Algorithms.
+
+ Copyright (c)2019 Orange. 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";
+
+ revision "2019-11-25" {
+ description
+ "Initial revision.";
+ reference "";
+ }
+
+ typedef delay {
+ description "Link delay is in the range 0 - 16.777215 seconds. Larger value is also encoded with Max value.";
+ units "microseconds";
+ type uint24:uint24;
+ }
+
+ typedef loss {
+ description "Link loss is in the range 0 - 50.331642% (= 2^24 - 2). Larger value is also encoded with Max value.";
+ units "0.000003%";
+ type uint24:uint24;
+ }
+
+ typedef decimal-bandwidth {
+ description "Bandwidth in decimal format for easy comparison";
+ units "bytes/second";
+ type decimal64 {
+ fraction-digits 2;
+ }
+ }
+
+ grouping edge-attributes {
+ description "Attributes associated with the Edge";
+ reference "RFC 3630 & RFC 7471, RFC 3784 & RFC8570: OSPF / IS-IS Traffic Engineering (TE) & Extended Metrics";
+
+ leaf metric {
+ description "Standard Metric from the routing protocol";
+ type uint32;
+ }
+ leaf te-metric {
+ description "Traffic Engineering Metric";
+ type uint32;
+ }
+ leaf admin-group {
+ description "Administrative group or color of the link";
+ type uint32;
+ }
+ leaf local-address {
+ type inet:ip-address;
+ }
+ leaf remote-address {
+ type inet:ip-address;
+ }
+ leaf local-identifier {
+ type uint32;
+ }
+ leaf remote-identifier {
+ type uint32;
+ }
+ leaf max-link-bandwidth {
+ description "Maximum bandwidth that can be use";
+ type decimal-bandwidth;
+ }
+ leaf max-resv-link-bandwidth {
+ description "Maximum amount of bandwidth that can be reserved";
+ type decimal-bandwidth;
+ }
+ list unreserved-bandwidth {
+ description "Unreserved bandwidth for 0-7 class type";
+ max-elements "8";
+ ordered-by user;
+ key "class-type";
+ leaf class-type {
+ type uint8 {
+ range "0..7";
+ }
+ }
+ leaf bandwidth {
+ description "Unreserved bandwidth for this class type";
+ type decimal-bandwidth;
+ }
+ }
+ leaf delay {
+ description "Unidirectional Delay.";
+ type delay;
+ }
+ container min-max-delay {
+ description "Min/Max Unidirectional Delay";
+ leaf min-delay {
+ type delay;
+ }
+ leaf max-delay {
+ type delay;
+ }
+ }
+ leaf jitter {
+ description "Unidirectional Delay Variation";
+ type delay;
+ }
+ leaf loss {
+ description "Unidirectional Loss";
+ type loss;
+ }
+ leaf residual-bandwidth {
+ description "Unidirectional Residual Bandwidth";
+ type decimal-bandwidth;
+ }
+ leaf available-bandwidth {
+ description "Unidirectional Available Bandwidth";
+ type decimal-bandwidth;
+ }
+ leaf utilized-bandwidth {
+ description "Unidirectional Utilized Bandwidth";
+ type decimal-bandwidth;
+ }
+ leaf adj-sid {
+ description "Segment Routing Adjacency Identifier";
+ units "MPLS label";
+ type uint32;
+ }
+ leaf backup-adj-sid {
+ description "Segment Routing Backup Adjacency Identifier";
+ units "MPLS label";
+ type uint32;
+ }
+ leaf-list srlgs {
+ description "List of Shared Risk Link Group Attributes";
+ type uint32;
+ }
+ }
+
+ grouping edge {
+ description "Unidirectional Edge (link) representation for the network topology";
+ leaf edge-id {
+ type uint64;
+ mandatory true;
+ }
+ leaf local-vertex-id {
+ description "Vertex identifier where the Edge is attached";
+ type uint64;
+ }
+ leaf remote-vertex-id {
+ description "Vertex identifier where the Edge is going to";
+ type uint64;
+ }
+ leaf name {
+ description "Edge name";
+ type string;
+ }
+ container edge-attributes {
+ description "All attributes associated to the Edge";
+ uses edge-attributes;
+ }
+ }
+
+ grouping srgb {
+ description "Segment Routing Global Block: lower-bound + range-size";
+ leaf lower-bound {
+ description "Lower bound of label range in SRGB. Unit MPLS label";
+ type uint32;
+ }
+ leaf range-size {
+ description "Label range size in SRGB. Unit MPLS label";
+ type uint32;
+ }
+ }
+
+ grouping vertex {
+ description "Vertex (node) representation for the network topology";
+ leaf vertex-id {
+ description "Identifier of the Vertex";
+ type uint64;
+ mandatory true;
+ }
+ leaf name {
+ description "Name of the Vertex when known";
+ type string;
+ }
+ leaf router-id {
+ description "Global unique IP Trafic Engineering Router ID";
+ type inet:ip-address;
+ }
+ leaf vertex-type {
+ type enumeration {
+ enum standard {
+ value 0;
+ }
+ enum abr {
+ value 1;
+ }
+ enum asbr-in {
+ value 2;
+ }
+ enum asbr-out {
+ value 3;
+ }
+ enum pseudo {
+ value 4;
+ }
+ }
+ default standard;
+ }
+ container srgb {
+ description "Segment Routing Global Block";
+ uses srgb;
+ }
+ leaf asn {
+ description "AS Number";
+ type uint32;
+ }
+ }
+
+ grouping prefix {
+ leaf prefix {
+ description "IP (v4 or v6) Prefix.";
+ type inet:ip-prefix;
+ mandatory true;
+ }
+ leaf prefix-sid {
+ description "Segment Routing prefix Identifier. Unit MPLS label";
+ type uint32;
+ }
+ leaf node-sid {
+ description "Prefix is a Node Segment Routing Identifier (Node-SID)";
+ type boolean;
+ }
+ leaf vertex-id {
+ description "Reference to the Vertex where the prefix is attached";
+ type uint64;
+ }
+ }
+
+ container graph-topology {
+ list graph {
+ description "Graph representation of the Network Topology";
+ key "name";
+ leaf name {
+ type string;
+ }
+ leaf domain-scope {
+ description "Network domain scope: intra or inter domain";
+ type enumeration {
+ enum intra-domain {
+ value 1;
+ }
+ enum inter-domain {
+ value 2;
+ }
+ }
+ default intra-domain;
+ }
+ leaf asn {
+ description "AS Number";
+ type uint32;
+ }
+ list vertex {
+ description "The list of Vertices defined for the Graph.";
+ key "vertex-id";
+ uses vertex;
+ }
+ list edge {
+ description "The list of Edges defined for the Graph.";
+ key "edge-id";
+ uses edge;
+ }
+ list prefix {
+ description "The list of prefixes for the Graph.";
+ key "prefix";
+ uses prefix;
+ }
+ }
+ }
+}
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2019 Orange Labs. 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.opendaylight.odlparent</groupId>
+ <artifactId>odlparent-lite</artifactId>
+ <version>6.0.4</version>
+ <relativePath/>
+ </parent>
+
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>graph-artifacts</artifactId>
+ <version>0.14.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>graph-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>graph-impl</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <!-- GRAPH Features artifacts -->
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>features-graph</artifactId>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>odl-bgpcep-graph</artifactId>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>odl-bgpcep-graph-api</artifactId>
+ <classifier>features</classifier>
+ <type>xml</type>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+</project>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2019 Orange Labs 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
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>bgpcep-parent</artifactId>
+ <version>0.14.0-SNAPSHOT</version>
+ <relativePath>../../parent</relativePath>
+ </parent>
+
+ <artifactId>graph-impl</artifactId>
+ <description>Graph Network Topology Implementation</description>
+ <packaging>bundle</packaging>
+ <name>${project.artifactId}</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>graph-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>concepts</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-common-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>yang-binding</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal.binding.model.ietf</groupId>
+ <artifactId>rfc6991-ietf-inet-types</artifactId>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2019 Orange. 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.graph.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.graph.ConnectedEdge;
+import org.opendaylight.graph.ConnectedVertex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Edge;
+
+/**
+ * This Class implements the Connected Edge used by the Connected Graph for path computation algorithms.
+ *
+ * @author Olivier Dugeon
+ * @author Philippe Niger
+ */
+
+public class ConnectedEdgeImpl implements ConnectedEdge {
+
+ /* Reference to Source and Destination Connected Vertex within the Connected Graph */
+ private ConnectedVertexImpl source;
+ private ConnectedVertexImpl destination;
+
+ /* Reference to the Edge within the Graph associated to the Connected Graph */
+ private Edge edge;
+
+ /* Edge key in the Connected Graph */
+ private Long ceid;
+
+ public ConnectedEdgeImpl(@NonNull Long key) {
+ checkArgument(key != 0, "Edge Key must not be equal to 0");
+ this.ceid = key;
+ this.edge = null;
+ }
+
+ public ConnectedEdgeImpl(@NonNull Edge edge) {
+ checkArgument(edge.getEdgeId().longValue() != 0, "Edge Key must not be equal to 0");
+ this.edge = edge;
+ this.ceid = edge.getEdgeId().longValue();
+ }
+
+ /**
+ * When edge is removed, we must disconnect source and destination Connected Vertices.
+ */
+ void close() {
+ this.disconnect();
+ }
+
+ /**
+ * Set Connected Vertex as source.
+ *
+ * @param vertex Vertex
+ */
+ public ConnectedEdgeImpl setSource(ConnectedVertexImpl vertex) {
+ source = vertex;
+ return this;
+ }
+
+ /**
+ * Set Connected Vertex as destination.
+ *
+ * @param vertex Vertex
+ */
+ public ConnectedEdgeImpl setDestination(ConnectedVertexImpl vertex) {
+ destination = vertex;
+ return this;
+ }
+
+ /**
+ * Disconnect source Connected Vertex.
+ */
+ public void disconnectSource() {
+ if (source != null) {
+ source.removeOutput(this);
+ source = null;
+ }
+ }
+
+ /**
+ * Disconnect destination Connected Vertex.
+ */
+ public void disconnectDestination() {
+ if (destination != null) {
+ destination.removeInput(this);
+ destination = null;
+ }
+ }
+
+ /**
+ * Disconnect both source and destination Connected Vertices.
+ */
+ public void disconnect() {
+ disconnectSource();
+ disconnectDestination();
+ }
+
+ /**
+ * Set associated Edge to this Connected Edge.
+ *
+ * @param edge Edge
+ */
+ public ConnectedEdgeImpl setEdge(Edge edge) {
+ this.edge = edge;
+ return this;
+ }
+
+ @Override
+ public @NonNull Long getKey() {
+ return this.ceid;
+ }
+
+ @Override
+ public ConnectedVertex getSource() {
+ return this.source;
+ }
+
+ @Override
+ public ConnectedVertex getDestination() {
+ return this.destination;
+ }
+
+ @Override
+ public Edge getEdge() {
+ return this.edge;
+ }
+
+ /**
+ * Returns the name of the associated Edge if set or the interface address otherwise.
+ *
+ * @return Edge name or interface address
+ */
+ @Override
+ public String toString() {
+ if (edge == null) {
+ return "Null";
+ }
+ if (edge.getName() != null) {
+ return edge.getName();
+ }
+ if (edge.getEdgeAttributes() != null) {
+ if (edge.getEdgeAttributes().getLocalAddress() != null) {
+ return edge.getEdgeAttributes().getLocalAddress().toString();
+ }
+ if (edge.getEdgeAttributes().getLocalIdentifier() != null) {
+ return edge.getEdgeAttributes().getLocalIdentifier().toString();
+ }
+ }
+ return "Unknown Edge";
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 Orange. 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.graph.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.graph.ConnectedEdge;
+import org.opendaylight.graph.ConnectedGraph;
+import org.opendaylight.graph.ConnectedVertex;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.Graph;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Edge;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.EdgeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Vertex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.VertexKey;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This Class implements the Connected Graph for path computation algorithms.
+ *
+ * @author Olivier Dugeon
+ * @author Philippe Niger
+ */
+
+
+public class ConnectedGraphImpl implements ConnectedGraph {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ConnectedGraphImpl.class);
+
+ /* List of Connected Vertics that composed this Connected Graph */
+ private final HashMap<Long, ConnectedVertexImpl> vertices = new HashMap<>();
+
+ /* List of Connected Edges that composed this Connected Graph */
+ private final HashMap<Long, ConnectedEdgeImpl> edges = new HashMap<>();
+
+ /* List of IP prefix attached to Vertices */
+ private final HashMap<IpPrefix, Prefix> prefixes = new HashMap<>();
+
+ /* Reference to the non connected Graph stored in DataStore */
+ private Graph graph;
+
+ /* Reference to Graph Model Server to store corresponding graph in DataStore */
+ private final ConnectedGraphServer connectedGraphServer;
+
+ public ConnectedGraphImpl(Graph newGraph, ConnectedGraphServer server) {
+ this.graph = newGraph;
+ createConnectedGraph();
+ this.connectedGraphServer = server;
+ }
+
+ /**
+ * Transform the associated Graph in a Connected Graph. This method will automatically create associated Connected
+ * Vertices, from the Graph Vertices, Connected Edges, from the Graph Edges and Prefix from the Graph Prefix.
+ *
+ */
+ private void createConnectedGraph() {
+ if (this.graph == null) {
+ return;
+ }
+ /* Add all vertices */
+ if (this.graph.getVertex() != null) {
+ for (Vertex vertex : this.graph.getVertex()) {
+ ConnectedVertexImpl cvertex = new ConnectedVertexImpl(vertex);
+ vertices.put(cvertex.getKey(), cvertex);
+ }
+ }
+ /* Add all edges */
+ if (this.graph.getEdge() != null) {
+ for (Edge edge : this.graph.getEdge()) {
+ ConnectedEdgeImpl cedge = new ConnectedEdgeImpl(edge);
+ edges.put(cedge.getKey(), cedge);
+ }
+ }
+ /* Add all prefixes */
+ if (this.graph.getPrefix() != null) {
+ for (Prefix prefix : this.graph.getPrefix()) {
+ ConnectedVertexImpl cvertex = vertices.get(prefix.getVertexId().longValue());
+ if (cvertex != null) {
+ cvertex.addPrefix(prefix);
+ }
+ prefixes.putIfAbsent(prefix.getPrefix(), prefix);
+ }
+ }
+ }
+
+ /**
+ * Return Connected Vertex if it exists or create a new one.
+ *
+ * @param key Unique Vertex Key identifier
+ * @return new or existing Connected Vertex
+ */
+ private ConnectedVertexImpl updateConnectedVertex(@NonNull Long key) {
+ checkArgument(key != 0, "Provided Vertex Key must not be equal to 0");
+ ConnectedVertexImpl vertex = vertices.get(key);
+ if (vertex == null) {
+ vertex = new ConnectedVertexImpl(key);
+ vertices.put(key, vertex);
+ }
+ return vertex;
+ }
+
+ /**
+ * Return Connected Edge if it exist or create a new one.
+ *
+ * @param key Unique Edge Key identifier
+ * @return new or existing Connected Edge
+ */
+ private ConnectedEdgeImpl updateConnectedEdge(@NonNull Long key) {
+ checkArgument(key != 0, "Provided Edge Key must not be equal to 0");
+ ConnectedEdgeImpl edge = edges.get(key);
+ if (edge == null) {
+ edge = new ConnectedEdgeImpl(key);
+ edges.put(edge.getKey(), edge);
+ }
+ return edge;
+ }
+
+ /**
+ * Connect source and destination Connected Vertices with the given Connected Edge.
+ *
+ * @param srcVertex Source Connected Vertex
+ * @param dstVertex Destination Connected Vertex
+ * @param edge Connected Edge
+ */
+ private void connectVertices(ConnectedVertexImpl srcVertex, ConnectedVertexImpl dstVertex, ConnectedEdgeImpl edge) {
+ if (edge != null) {
+ edge.setSource(srcVertex);
+ edge.setDestination(dstVertex);
+ }
+ if (srcVertex != null) {
+ srcVertex.addOutput(edge);
+ }
+ if (dstVertex != null) {
+ dstVertex.addInput(edge);
+ }
+ }
+
+ @Override
+ public Graph getGraph() {
+ return this.graph;
+ }
+
+ @Override
+ public List<ConnectedVertex> getVertices() {
+ return new ArrayList<ConnectedVertex>(this.vertices.values());
+ }
+
+ @Override
+ public ConnectedVertex getConnectedVertex(@NonNull Long key) {
+ return vertices.get(key);
+ }
+
+ @Override
+ public ConnectedVertex getConnectedVertex(IpAddress address) {
+ IpPrefix prefix = null;
+ if (address.getIpv4Address() != null) {
+ prefix = new IpPrefix(new Ipv4Prefix(address.getIpv4Address().getValue() + "/32"));
+ }
+ if (address.getIpv6Address() != null) {
+ prefix = new IpPrefix(new Ipv6Prefix(address.getIpv6Address().getValue() + "/128"));
+ }
+ if (prefix != null && prefixes.containsKey(prefix)) {
+ long key = prefixes.get(prefix).getVertexId().longValue();
+ return vertices.get(key);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public int getVerticesSize() {
+ return vertices.size();
+ }
+
+ @Override
+ public List<ConnectedEdge> getEdges() {
+ return new ArrayList<ConnectedEdge>(this.edges.values());
+ }
+
+ @Override
+ public ConnectedEdge getConnectedEdge(@NonNull Long key) {
+ return edges.get(key);
+ }
+
+ @Override
+ public ConnectedEdge getConnectedEdge(IpAddress address) {
+ for (ConnectedEdge cedge : edges.values()) {
+ if (cedge.getEdge() == null) {
+ continue;
+ }
+ if (cedge.getEdge().getEdgeAttributes().getLocalAddress().equals(address)) {
+ return cedge;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public int getEdgesSize() {
+ return edges.size();
+ }
+
+ @Override
+ public List<Prefix> getPrefixes() {
+ return new ArrayList<Prefix>(this.prefixes.values());
+ }
+
+ @Override
+ public Prefix getPrefix(IpPrefix prefix) {
+ return this.prefixes.get(prefix);
+ }
+
+ @Override
+ public ConnectedVertex addVertex(Vertex vertex) {
+ checkArgument(vertex != null, "Provided Vertex is a null object");
+ ConnectedVertexImpl cvertex = updateConnectedVertex(vertex.getVertexId().longValue());
+ Vertex old = cvertex.getVertex();
+ this.connectedGraphServer.addVertex(this.graph, vertex, old);
+ cvertex.setVertex(vertex);
+ return cvertex;
+ }
+
+ @Override
+ public void deleteVertex(VertexKey key) {
+ checkArgument(key != null, "Provided Vertex Key is a null object");
+ ConnectedVertexImpl cvertex = vertices.get(key.getVertexId().longValue());
+ if (cvertex != null) {
+ cvertex.disconnect();
+ vertices.remove(cvertex.getKey());
+ this.connectedGraphServer.deleteVertex(this.graph, cvertex.getVertex());
+ cvertex.setVertex(null);
+ }
+ }
+
+ @Override
+ public ConnectedEdge addEdge(Edge edge) {
+ checkArgument(edge != null, "Provided Edge is a null object");
+ ConnectedEdgeImpl cedge = updateConnectedEdge(edge.getEdgeId().longValue());
+ Edge old = cedge.getEdge();
+ if (old == null) {
+ ConnectedVertexImpl source = null;
+ ConnectedVertexImpl destination = null;
+ if (edge.getLocalVertexId() != null) {
+ source = updateConnectedVertex(edge.getLocalVertexId().longValue());
+ }
+ if (edge.getRemoteVertexId() != null) {
+ destination = updateConnectedVertex(edge.getRemoteVertexId().longValue());
+ }
+ connectVertices(source, destination, cedge);
+ }
+ this.connectedGraphServer.addEdge(this.graph, edge, old);
+ cedge.setEdge(edge);
+ return cedge;
+ }
+
+ @Override
+ public void deleteEdge(EdgeKey key) {
+ checkArgument(key != null, "Provided Edge Key is a null object");
+ ConnectedEdgeImpl cedge = edges.get(key.getEdgeId().longValue());
+ if (cedge != null) {
+ this.connectedGraphServer.deleteEdge(this.graph, cedge.getEdge());
+ cedge.disconnect();
+ edges.remove(cedge.getKey());
+ cedge.setEdge(null);
+ }
+ }
+
+ @Override
+ public void addPrefix(Prefix prefix) {
+ checkArgument(prefix != null, "Provided Prefix is a null object");
+ ConnectedVertexImpl cvertex = updateConnectedVertex(prefix.getVertexId().longValue());
+ cvertex.addPrefix(prefix);
+ prefixes.putIfAbsent(prefix.getPrefix(), prefix);
+ this.connectedGraphServer.addPrefix(this.graph, prefix);
+ }
+
+ @Override
+ public void deletePrefix(IpPrefix ippfx) {
+ checkArgument(ippfx != null, "Provided Prefix is a null object");
+ Prefix prefix = prefixes.get(ippfx);
+ if (prefix != null) {
+ ConnectedVertexImpl cvertex = vertices.get(prefix.getVertexId().longValue());
+ if (cvertex != null) {
+ cvertex.removePrefix(prefix);
+ }
+ prefixes.remove(prefix.getPrefix());
+ this.connectedGraphServer.deletePrefix(this.graph, prefix);
+ }
+ }
+
+ @Override
+ public void clear() {
+ LOG.info("Reset Connected Graph({})", graph.getName());
+ this.vertices.clear();
+ this.edges.clear();
+ this.prefixes.clear();
+ this.connectedGraphServer.clearGraph(this.graph);
+ this.graph = null;
+ }
+
+ @Override
+ public String getSummary() {
+ return vertices.size() + "/" + edges.size() + "/" + prefixes.size();
+ }
+
+ /**
+ * Returns the name of the associated Graph.
+ *
+ * @return Graph name
+ */
+ @Override
+ public String toString() {
+ return this.graph.getName();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 Orange. 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.graph.impl;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.FluentFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import org.opendaylight.graph.ConnectedGraph;
+import org.opendaylight.graph.ConnectedGraphProvider;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.ReadWriteTransaction;
+import org.opendaylight.mdsal.binding.api.Transaction;
+import org.opendaylight.mdsal.binding.api.TransactionChain;
+import org.opendaylight.mdsal.binding.api.TransactionChainListener;
+import org.opendaylight.mdsal.binding.api.WriteTransaction;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.GraphTopology;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.GraphTopologyBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.Graph;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.Graph.DomainScope;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.GraphBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.GraphKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Edge;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Vertex;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This Class Implements the DataStoreService interface providing the methods
+ * required to manage the network representation elements in the datastore.
+ *
+ *
+ * @author Olivier Dugeon
+ * @author Philippe Niger
+ */
+
+public class ConnectedGraphServer implements ConnectedGraphProvider, TransactionChainListener {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ConnectedGraphServer.class);
+ private final DataBroker dataBroker;
+ private final InstanceIdentifier<GraphTopology> graphTopologyIdentifier;
+ private TransactionChain chain = null;
+
+ private final HashMap<GraphKey, ConnectedGraphImpl> graphs = new HashMap<>();
+
+ public ConnectedGraphServer(final DataBroker dataBroker) {
+ LOG.info("Create Graph Model Server");
+ this.dataBroker = dataBroker;
+ this.graphTopologyIdentifier = InstanceIdentifier.builder(GraphTopology.class).build();
+ }
+
+ /**
+ * Initialization of the Graph Model Server. This method is called through the blueprint.
+ */
+ public void init() {
+ initTransactionChain();
+ initOperationalGraphModel();
+ }
+
+ /**
+ * Reset a transaction chain by closing the current chain and starting a new one.
+ */
+ private synchronized void initTransactionChain() {
+ LOG.debug("Initializing transaction chain for Graph Model Server {}", this);
+ Preconditions.checkState(this.chain == null, "Transaction chain has to be closed before being initialized");
+ this.chain = this.dataBroker.createMergingTransactionChain(this);
+ }
+
+ /**
+ * Initialize GraphModel tree at Data Store top-level.
+ */
+ private synchronized void initOperationalGraphModel() {
+ requireNonNull(this.chain, "A valid transaction chain must be provided.");
+ final WriteTransaction trans = this.chain.newWriteOnlyTransaction();
+ LOG.info("Create Graph Model at top level in Operational DataStore: {}", this.graphTopologyIdentifier);
+ trans.put(LogicalDatastoreType.OPERATIONAL, this.graphTopologyIdentifier,
+ new GraphTopologyBuilder().setGraph(Collections.emptyList()).build());
+ trans.put(LogicalDatastoreType.CONFIGURATION, this.graphTopologyIdentifier,
+ new GraphTopologyBuilder().setGraph(Collections.emptyList()).build());
+ LOG.info("Create Graph Model at top level in Configuration DataStore: {}", this.graphTopologyIdentifier);
+ trans.commit().addCallback(new FutureCallback<CommitInfo>() {
+ @Override
+ public void onSuccess(final CommitInfo result) {
+ LOG.trace("Transaction {} committed successfully", trans.getIdentifier());
+ }
+
+ @Override
+ public void onFailure(final Throwable throwable) {
+ LOG.error("Failed to initialize GraphModel {} (transaction {}) by listener {}",
+ ConnectedGraphServer.this.graphTopologyIdentifier, trans.getIdentifier(),
+ ConnectedGraphServer.this, throwable);
+ }
+ }, MoreExecutors.directExecutor());
+ }
+
+ /**
+ * Destroy the current operational topology data. Note a valid transaction must be provided.
+ */
+ private synchronized FluentFuture<? extends CommitInfo> destroyOperationalGraphModel() {
+ requireNonNull(this.chain, "A valid transaction chain must be provided.");
+ final WriteTransaction trans = this.chain.newWriteOnlyTransaction();
+ trans.delete(LogicalDatastoreType.OPERATIONAL, this.graphTopologyIdentifier);
+ trans.delete(LogicalDatastoreType.CONFIGURATION, this.graphTopologyIdentifier);
+ final FluentFuture<? extends CommitInfo> future = trans.commit();
+ future.addCallback(new FutureCallback<CommitInfo>() {
+ @Override
+ public void onSuccess(final CommitInfo result) {
+ LOG.trace("Operational GraphModel removed {}", ConnectedGraphServer.this.graphTopologyIdentifier);
+ }
+
+ @Override
+ public void onFailure(final Throwable throwable) {
+ LOG.error("Unable to reset operational GraphModel {} (transaction {})",
+ ConnectedGraphServer.this.graphTopologyIdentifier, trans.getIdentifier(), throwable);
+ }
+ }, MoreExecutors.directExecutor());
+
+ /* Clear Connected Graph */
+ for (ConnectedGraph graph : graphs.values()) {
+ ((ConnectedGraphImpl) graph).clear();
+ }
+ return future;
+ }
+
+ /**
+ * Destroy the current transaction chain.
+ */
+ private synchronized void destroyTransactionChain() {
+ if (this.chain != null) {
+ LOG.debug("Destroy transaction chain for GraphModel {}", this);
+ this.chain = null;
+ }
+ }
+
+ /**
+ * Reset the transaction chain only so that the PingPong transaction chain
+ * will become usable again. However, there will be data loss if we do not
+ * apply the previous failed transaction again
+ */
+ protected synchronized void resetTransactionChain() {
+ LOG.debug("Resetting transaction chain for Graph builder");
+ destroyTransactionChain();
+ initTransactionChain();
+ }
+
+ /**
+ * Remove the Operation Graph Model and destroy the transaction chain.
+ */
+ public void close() {
+ destroyOperationalGraphModel();
+ destroyTransactionChain();
+ }
+
+ /**
+ * DataStore Instance Identifier creation for the various Graph components.
+ */
+ private InstanceIdentifier<Graph> getGraphInstanceIdentifier(String name) {
+ GraphKey graphKey = new GraphKey(name);
+ return this.graphTopologyIdentifier.child(Graph.class, graphKey);
+ }
+
+ private InstanceIdentifier<Vertex> getVertexInstanceIdentifier(Graph graph, final Vertex vertex) {
+ return this.graphTopologyIdentifier.child(Graph.class, graph.key()).child(Vertex.class, vertex.key());
+ }
+
+ private InstanceIdentifier<Edge> getEdgeInstanceIdentifier(Graph graph, final Edge edge) {
+ return this.graphTopologyIdentifier.child(Graph.class, graph.key()).child(Edge.class, edge.key());
+ }
+
+ private InstanceIdentifier<Prefix> getPrefixInstanceIdentifier(Graph graph, final Prefix prefix) {
+ return this.graphTopologyIdentifier.child(Graph.class, graph.key()).child(Prefix.class, prefix.key());
+ }
+
+ /**
+ * Add Graph or Graph components to the Data Store.
+ *
+ * @param <T> As a generic method, T must be a Graph, Vertex, Edge or Prefix.
+ * @param id Instance Identifier of the Data Object
+ * @param data Data Object (Graph, Vertex, Edge or Prefix)
+ * @param info Information to be logged
+ */
+ private synchronized <T extends DataObject> void addToDataStore(final InstanceIdentifier<T> id, final T data,
+ final String info) {
+ final ReadWriteTransaction trans = this.chain.newReadWriteTransaction();
+ trans.put(LogicalDatastoreType.OPERATIONAL, id, data);
+ trans.commit().addCallback(new FutureCallback<CommitInfo>() {
+ @Override
+ public void onSuccess(final CommitInfo result) {
+ LOG.info("GraphModel: {} has been published in operational datastore ", info);
+ }
+
+ @Override
+ public void onFailure(final Throwable throwable) {
+ LOG.error("GrahModel: Cannot write {} to the operational datastore (transaction: {})", info,
+ trans.getIdentifier());
+ }
+ }, MoreExecutors.directExecutor());
+ }
+
+ /**
+ * Update Graph components (Vertex, Edge or Prefix ) to the Data Store. Old value identified by its Instance ID
+ * will be remove first before adding the new value.
+ *
+ * @param <T> As a generic method, T must be a Vertex, Edge or Prefix.
+ * @param id Instance Identifier of the Data Object
+ * @param data Data Object (Vertex, Edge or Prefix)
+ * @param old Instance Identifier of the previous version of the Data Object
+ * @param info Information to be logged
+ */
+ private synchronized <T extends DataObject> void updateToDataStore(final InstanceIdentifier<T> id, final T data,
+ final InstanceIdentifier<T> old, final String info) {
+ final ReadWriteTransaction trans = this.chain.newReadWriteTransaction();
+ if (old != null) {
+ trans.delete(LogicalDatastoreType.OPERATIONAL, old);
+ }
+ trans.put(LogicalDatastoreType.OPERATIONAL, id, data);
+ trans.commit().addCallback(new FutureCallback<CommitInfo>() {
+ @Override
+ public void onSuccess(final CommitInfo result) {
+ LOG.info("GraphModel: {} has been published in operational datastore ", info);
+ }
+
+ @Override
+ public void onFailure(final Throwable throwable) {
+ LOG.error("GrahModel: Cannot write {} to the operational datastore (transaction: {})", info,
+ trans.getIdentifier());
+ }
+ }, MoreExecutors.directExecutor());
+ }
+
+ /**
+ * Remove Graph or Graph components to the Data Store.
+ *
+ * @param <T> As a generic method, T must be a Graph, Vertex, Edge or Prefix.
+ * @param id Instance Identifier of the Data Object
+ * @param info Information to be logged
+ */
+ private synchronized <T extends DataObject> void removeFromDataStore(final InstanceIdentifier<T> id,
+ final String info) {
+ final ReadWriteTransaction trans = this.chain.newReadWriteTransaction();
+ trans.delete(LogicalDatastoreType.OPERATIONAL, id);
+ trans.commit().addCallback(new FutureCallback<CommitInfo>() {
+ @Override
+ public void onSuccess(final CommitInfo result) {
+ LOG.info("GraphModel: {} has been deleted in operational datastore ", info);
+ }
+
+ @Override
+ public void onFailure(final Throwable throwable) {
+ LOG.error("GraphModel: Cannot delete {} to the operational datastore (transaction: {})", info,
+ trans.getIdentifier());
+ }
+ }, MoreExecutors.directExecutor());
+ }
+
+ /**
+ * Clear Graph. This method is used by the Connected Graph to clear associated Graph.
+ *
+ * @param graph Graph associated to the Connected Graph
+ */
+ public void clearGraph(Graph graph) {
+ Preconditions.checkArgument(graph != null, "Provided Graph is a null object");
+ removeFromDataStore(getGraphInstanceIdentifier(graph.getName()), "Graph(" + graph.getName() + ")");
+ }
+
+ /**
+ * Add Vertex to existing Graph. Old vertex is remove first. This method is called when a Connected Vertex is
+ * created (See addVertex() method from ConnectedGraph Interface).
+ *
+ * @param graph Graph where the vertex will be stored
+ * @param vertex Vertex to be inserted in the graph
+ * @param old Old vertex when performing an update. Must be null for a simple addition
+ */
+ public void addVertex(Graph graph, Vertex vertex, Vertex old) {
+ Preconditions.checkArgument(graph != null, "Provided Graph is a null object");
+ Preconditions.checkArgument(vertex != null, "Provided Vertex is a null object");
+ InstanceIdentifier<Vertex> oldId = null;
+ /* Remove old Vertex if it exists before storing the new Vertex */
+ if (old != null) {
+ oldId = getVertexInstanceIdentifier(graph, old);
+ }
+ updateToDataStore(getVertexInstanceIdentifier(graph, vertex), vertex, oldId,
+ "Vertex(" + vertex.getName() + ")");
+ }
+
+ /**
+ * Remove Vertex to existing Graph. This method is called when a Connected Vertex is removed (See deleteVertex()
+ * method from ConnectedGraph Interface).
+ *
+ * @param graph Graph where the vertex is stored
+ * @param vertex Vertex to be removed
+ */
+ public void deleteVertex(Graph graph, Vertex vertex) {
+ Preconditions.checkArgument(graph != null, "Provided Graph is a null object");
+ Preconditions.checkArgument(vertex != null, "Provided Vertex is a null object");
+ removeFromDataStore(getVertexInstanceIdentifier(graph, vertex), "Vertex(" + vertex.getName() + ")");
+ }
+
+ /**
+ * Add Edge to existing Graph. Old edge is remove first. This method is called when a Connected Edge is
+ * created (See addEdge() method from ConnectedGraph Interface).
+ *
+ * @param graph Graph where the edge will be stored
+ * @param edge Edge to be inserted in the graph
+ * @param old Old edge when performing an update. Must be null for a simple addition
+ */
+ public void addEdge(Graph graph, Edge edge, Edge old) {
+ Preconditions.checkArgument(graph != null, "Provided Graph is a null object");
+ Preconditions.checkArgument(edge != null, "Provided Edge is a null object");
+ InstanceIdentifier<Edge> oldId = null;
+ /* Remove old Edge if it exists before storing the new Edge */
+ if (old != null) {
+ oldId = getEdgeInstanceIdentifier(graph, old);
+ }
+ updateToDataStore(getEdgeInstanceIdentifier(graph, edge), edge, oldId, "Edge(" + edge.getName() + ")");
+ }
+
+ /**
+ * Remove Edge to existing Graph. This method is called when a Connected Edge is removed (See deleteEdge()
+ * method from ConnectedGraph Interface).
+ *
+ * @param graph Graph where the edge is stored
+ * @param edge Edge to be removed
+ */
+ public void deleteEdge(Graph graph, Edge edge) {
+ Preconditions.checkArgument(graph != null, "Provided Graph is a null object");
+ Preconditions.checkArgument(edge != null, "Provided Edge is a null object");
+ removeFromDataStore(getEdgeInstanceIdentifier(graph, edge), "Edge(" + edge.getName() + ")");
+ }
+
+ /**
+ * Add Prefix to existing Graph. This method is called when a Prefix is added to a Connected Vertex
+ * (See addPrefix() method from ConnectedGraph Interface).
+ *
+ * @param graph Graph where the prefix will be stored
+ * @param prefix Prefix to be interted in the graph
+ */
+ public void addPrefix(Graph graph, Prefix prefix) {
+ Preconditions.checkArgument(graph != null, "Provided Graph is a null object");
+ Preconditions.checkArgument(prefix != null, "Provided Prefix is a null object");
+ addToDataStore(getPrefixInstanceIdentifier(graph, prefix), prefix, "Prefix(" + prefix.getPrefix() + ")");
+ }
+
+ /**
+ * Remove Prefix to existing Graph. This method is called when a Prefix is removed from a Connected Vertex
+ * (See deletePrefix() method from ConnectedGraph Interface).
+ *
+ * @param graph Graph where the prefix is stored
+ * @param prefix Prefix to be removed
+ */
+ public void deletePrefix(Graph graph, Prefix prefix) {
+ Preconditions.checkArgument(graph != null, "Provided Graph is a null object");
+ Preconditions.checkArgument(prefix != null, "Provided Prefix is a null object");
+ removeFromDataStore(getPrefixInstanceIdentifier(graph, prefix), "Prefix(" + prefix.getPrefix() + ")");
+ }
+
+ @Override
+ public final synchronized void onTransactionChainFailed(final TransactionChain transactionChain,
+ final Transaction transaction, final Throwable cause) {
+ LOG.error("GraphModel builder for {} failed in transaction: {} ", this.graphTopologyIdentifier,
+ transaction != null ? transaction.getIdentifier() : null, cause);
+ }
+
+ @Override
+ public final void onTransactionChainSuccessful(final TransactionChain transactionChain) {
+ LOG.info("GraphModel builder for {} shut down", this.graphTopologyIdentifier);
+ }
+
+ @Override
+ public ArrayList<ConnectedGraph> getConnectedGraphs() {
+ return new ArrayList<ConnectedGraph>(this.graphs.values());
+ }
+
+ @Override
+ public ConnectedGraph getConnectedGraph(GraphKey key) {
+ return graphs.get(key);
+ }
+
+ @Override
+ public ConnectedGraph getConnectedGraph(String name) {
+ return graphs.get(new GraphKey(name));
+ }
+
+ @Override
+ public Graph getGraph(GraphKey key) {
+ if (graphs.containsKey(key)) {
+ return graphs.get(key).getGraph();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Graph getGraph(String name) {
+ return getGraph(new GraphKey(name));
+ }
+
+ @Override
+ public ConnectedGraph createConnectedGraph(String name, DomainScope scope) {
+ Graph graph = new GraphBuilder()
+ .setName(name)
+ .setDomainScope(scope)
+ .setEdge(Collections.emptyList())
+ .setVertex(Collections.emptyList())
+ .setPrefix(Collections.emptyList())
+ .build();
+ addToDataStore(getGraphInstanceIdentifier(name), graph, "Graph(" + name + ")");
+ ConnectedGraphImpl cgraph = new ConnectedGraphImpl(graph, this);
+ graphs.put(graph.key(), cgraph);
+ return cgraph;
+ }
+
+ @Override
+ public ConnectedGraph addGraph(Graph graph) {
+ Preconditions.checkArgument(graph != null, "Provided Graph is a null object");
+ addToDataStore(getGraphInstanceIdentifier(graph.getName()), graph, "Graph(" + graph.getName() + ")");
+ ConnectedGraphImpl cgraph = new ConnectedGraphImpl(graph, this);
+ graphs.put(graph.key(), cgraph);
+ return cgraph;
+ }
+
+ @Override
+ public void deleteGraph(GraphKey key) {
+ Preconditions.checkArgument(key != null, "Provided Graph Key is a null object");
+ ConnectedGraphImpl cgraph = graphs.remove(key);
+ /*
+ * Remove the corresponding Connected Graph which will delete the graph
+ * by calling clearGraph() method (see above)
+ */
+ if (cgraph != null) {
+ cgraph.clear();
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 Orange. 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.graph.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.graph.ConnectedEdge;
+import org.opendaylight.graph.ConnectedVertex;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Edge;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Vertex;
+
+/**
+ * This Class implements the Connected Vertex used by the Connected Graph for path computation algorithms.
+ *
+ * @author Olivier Dugeon
+ * @author Philippe Niger
+ */
+
+public class ConnectedVertexImpl implements ConnectedVertex {
+
+ /* Reference to input and output Connected Edge within the Connected Graph */
+ private ArrayList<ConnectedEdgeImpl> input = new ArrayList<>();
+ private ArrayList<ConnectedEdgeImpl> output = new ArrayList<>();
+
+ /* List of Prefixes announced by this Vertex */
+ private ArrayList<Prefix> prefixes = new ArrayList<>();
+
+ /* Reference to the Vertex of the standard Graph associated to the Connected Graph */
+ private Vertex vertex = null;
+
+ /* Connected Vertex Identifier */
+ private Long cvid;
+
+ public ConnectedVertexImpl(@NonNull Long key) {
+ checkArgument(key != 0, "Vertex Key must not be equal to 0");
+ this.cvid = key;
+ this.vertex = null;
+ }
+
+ public ConnectedVertexImpl(@NonNull Vertex vertex) {
+ checkArgument(vertex.getVertexId().longValue() != 0, "Vertex Key must not be equal to 0");
+ this.cvid = vertex.getVertexId().longValue();
+ this.vertex = vertex;
+ }
+
+ /**
+ * When vertex is removed, we must disconnect all Connected Edges.
+ */
+ void close() {
+ this.disconnect();
+ }
+
+ /**
+ * Set associated Vertex to this Connected Vertex.
+ *
+ * @param vertex Vertex
+ */
+ public ConnectedVertexImpl setVertex(Vertex vertex) {
+ this.vertex = vertex;
+ return this;
+ }
+
+ /**
+ * Add Connected Edge as input edge.
+ *
+ * @param edge Connected Edge
+ */
+ public ConnectedVertexImpl addInput(ConnectedEdgeImpl edge) {
+ if (!input.contains(edge)) {
+ input.add(edge);
+ }
+ return this;
+ }
+
+ /**
+ * Add Connected Edge as output edge.
+ *
+ * @param edge Connected Edge
+ */
+ public ConnectedVertexImpl addOutput(ConnectedEdgeImpl edge) {
+ if (!output.contains(edge)) {
+ output.add(edge);
+ }
+ return this;
+ }
+
+ /**
+ * Remove input Connected Edge.
+ *
+ * @param edge Connected Edge
+ */
+ public ConnectedVertexImpl removeInput(ConnectedEdgeImpl edge) {
+ input.remove(edge);
+ return this;
+ }
+
+ /**
+ * Remove output Connected Edge.
+ *
+ * @param edge Connected Edge
+ */
+ public ConnectedVertexImpl removeOutput(ConnectedEdgeImpl edge) {
+ output.remove(edge);
+ return this;
+ }
+
+ /**
+ * Disconnect all input and output Connected Edge.
+ */
+ public void disconnect() {
+ for (ConnectedEdgeImpl edge : input) {
+ edge.disconnectDestination();
+ }
+ for (ConnectedEdgeImpl edge : output) {
+ edge.disconnectSource();
+ }
+ }
+
+ /**
+ * Add Prefix to this Connected Vertex.
+ *
+ * @param prefix Prefix
+ */
+ public ConnectedVertexImpl addPrefix(Prefix prefix) {
+ if (!prefixes.contains(prefix)) {
+ prefixes.add(prefix);
+ }
+ return this;
+ }
+
+ /**
+ * Remove Prefix.
+ *
+ * @param prefix Prefix
+ */
+ public void removePrefix(Prefix prefix) {
+ if (prefixes.contains(prefix)) {
+ prefixes.remove(prefix);
+ }
+ }
+
+ @Override
+ public Long getKey() {
+ return this.cvid;
+ }
+
+ @Override
+ public Vertex getVertex() {
+ return this.vertex;
+ }
+
+ @Override
+ public List<ConnectedEdge> getEdgeTo(Long dstRid) {
+ ArrayList<ConnectedEdge> edgeList = new ArrayList<ConnectedEdge>();
+ for (ConnectedEdge edge : output) {
+ if (edge.getDestination().getKey().equals(dstRid)) {
+ edgeList.add(edge);
+ }
+ }
+ return edgeList;
+ }
+
+ @Override
+ public List<Edge> getInputEdges() {
+ ArrayList<Edge> edgeList = new ArrayList<Edge>();
+ for (ConnectedEdge edge : input) {
+ edgeList.add(edge.getEdge());
+ }
+ return edgeList;
+ }
+
+ @Override
+ public List<ConnectedEdge> getInputConnectedEdges() {
+ return new ArrayList<ConnectedEdge>(this.input);
+ }
+
+ @Override
+ public List<Edge> getOutputEdges() {
+ ArrayList<Edge> edgeList = new ArrayList<Edge>();
+ for (ConnectedEdge edge : output) {
+ edgeList.add(edge.getEdge());
+ }
+ return edgeList;
+ }
+
+ @Override
+ public List<ConnectedEdge> getOutputConnectedEdges() {
+ return new ArrayList<ConnectedEdge>(this.output);
+ }
+
+ @Override
+ public List<Prefix> getPrefixes() {
+ return this.prefixes;
+ }
+
+ /**
+ * Return the name of the associated Vertex if set or the router-id otherwise.
+ *
+ * @return Vertex name or router-id
+ */
+ @Override
+ public String toString() {
+ if (vertex == null) {
+ return "Null";
+ }
+ if (vertex.getName() != null) {
+ return vertex.getName();
+ } else {
+ return vertex.getRouterId().toString();
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2019 Orange. 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.graph.impl;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.Collection;
+import org.opendaylight.graph.ConnectedGraph;
+import org.opendaylight.graph.ConnectedGraphProvider;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.DataObjectModification;
+import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
+import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
+import org.opendaylight.mdsal.binding.api.DataTreeModification;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.GraphTopology;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.Graph;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.GraphKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Edge;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Prefix;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.graph.rev191125.graph.topology.graph.Vertex;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This Class Implements the DataStoreService interface providing the methods required to manage the network
+ * representation elements in the Data Store.
+ *
+ *
+ * @author Olivier Dugeon
+ * @author Philippe Niger
+ */
+
+public class GraphListener implements DataTreeChangeListener<Graph> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(GraphListener.class);
+ private final DataBroker dataBroker;
+ private final InstanceIdentifier<Graph> graphIdentifier;
+ private final ConnectedGraphProvider graphProvider;
+ private ListenerRegistration<GraphListener> listenerRegistration = null;
+
+ public GraphListener(final DataBroker dataBroker, final ConnectedGraphProvider provider) {
+ this.dataBroker = dataBroker;
+ this.graphIdentifier = InstanceIdentifier.builder(GraphTopology.class).child(Graph.class).build();
+ this.graphProvider = provider;
+ LOG.info("Graph Model Listener started");
+ }
+
+ /**
+ * Initialization of the Graph Topology Listener. This method is called through the blueprint.
+ */
+ public void init() {
+ checkState(this.listenerRegistration == null, "Graph Listener has been registered before");
+ final DataTreeIdentifier<Graph> treeId = DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION,
+ graphIdentifier);
+ this.listenerRegistration = this.dataBroker.registerDataTreeChangeListener(treeId, this);
+ LOG.info("Registered listener {} on Graph Model at {}", this, this.graphIdentifier);
+ }
+
+ /**
+ * Close this Listener.
+ */
+ public void close() {
+ if (this.listenerRegistration != null) {
+ LOG.debug("Unregistered listener {} on Graph", this);
+ this.listenerRegistration.close();
+ this.listenerRegistration = null;
+ }
+ }
+
+ /**
+ * Parse Sub Tree modification. This method is called with the Modified Children from
+ * the Data Tree Modification root.This method is necessary as the getModificationType() method returns
+ * SUBTREE_MODIFIED only when Data Object is already present in the Data Store. Thus, this is indication is only
+ * relevant for deletion not for insertion where WRITE modification type is return even if it concerns a child.
+ *
+ * @param cgraph Connected Graph where children Data Object must insert or remove
+ * @param children List of children (Vertex, Edge or Prefix)
+ */
+ private void parseSubTree(ConnectedGraph cgraph,
+ Collection<? extends DataObjectModification<? extends DataObject>> children) {
+ for (DataObjectModification<? extends DataObject> child : children) {
+ DataObject value;
+ switch (child.getModificationType()) {
+ case DELETE:
+ value = child.getDataBefore();
+ if (value instanceof Vertex) {
+ cgraph.deleteVertex(((Vertex )value).key());
+ }
+ if (value instanceof Edge) {
+ cgraph.deleteEdge(((Edge )value).key());
+ }
+ if (value instanceof Prefix) {
+ cgraph.deletePrefix(((Prefix )value).getPrefix());
+ }
+ break;
+ case SUBTREE_MODIFIED:
+ case WRITE:
+ value = child.getDataAfter();
+ if (value instanceof Vertex) {
+ cgraph.addVertex((Vertex )value);
+ }
+ if (value instanceof Edge) {
+ cgraph.addEdge((Edge )value);
+ }
+ if (value instanceof Prefix) {
+ cgraph.addPrefix((Prefix )value);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void onDataTreeChanged(final Collection<DataTreeModification<Graph>> changes) {
+ for (DataTreeModification<Graph> change : changes) {
+ DataObjectModification<Graph> root = change.getRootNode();
+ GraphKey key = change.getRootPath().getRootIdentifier().firstKeyOf(Graph.class);
+ switch (root.getModificationType()) {
+ case DELETE:
+ graphProvider.deleteGraph(key);
+ break;
+ case SUBTREE_MODIFIED:
+ /* getModificationType() returns SUBTREE_MODIFIED only when Data Object is already present in the
+ * Data Store, thus, only for deletion. Thus, to insert children, we must used parseSubTree()
+ * method (See above). This method is called only when the graph already exists.
+ */
+ case WRITE:
+ /* First look if the Graph was not already configured */
+ ConnectedGraph cgraph = this.graphProvider.getConnectedGraph(key);
+ if (cgraph == null) {
+ graphProvider.addGraph(root.getDataAfter());
+ } else {
+ /* Graph exist, process Children */
+ parseSubTree(cgraph, root.getModifiedChildren());
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+}
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2019 Orange. 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
+-->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0">
+
+ <reference id="dataBroker" interface="org.opendaylight.mdsal.binding.api.DataBroker" odl:type="default" />
+
+ <bean id="connectedGraphProvider"
+ class="org.opendaylight.graph.impl.ConnectedGraphServer"
+ destroy-method="close"
+ init-method="init">
+ <argument ref="dataBroker" />
+ </bean>
+
+ <service ref="connectedGraphProvider" interface="org.opendaylight.graph.ConnectedGraphProvider" />
+
+ <bean id="graphListener"
+ class="org.opendaylight.graph.impl.GraphListener"
+ destroy-method="close"
+ init-method="init">
+ <argument ref="dataBroker" />
+ <argument ref="connectedGraphProvider" />
+ </bean>
+
+</blueprint>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (c) 2019 Orange Labs. 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.odlparent</groupId>
+ <artifactId>odlparent-lite</artifactId>
+ <version>6.0.4</version>
+ <relativePath/>
+ </parent>
+
+ <groupId>org.opendaylight.bgpcep</groupId>
+ <artifactId>graph</artifactId>
+ <version>0.14.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+ <description>Graph Network Topology components</description>
+ <name>${project.artifactId}</name>
+
+ <modules>
+ <module>graph-artifacts</module>
+ <module>graph-api</module>
+ <module>graph-impl</module>
+ </modules>
+
+ <properties>
+ <maven.deploy.skip>true</maven.deploy.skip>
+ <maven.install.skip>true</maven.install.skip>
+ </properties>
+</project>
<!-- Subsystems -->
<module>bgp</module>
<module>bmp</module>
+ <module>graph</module>
<module>pcep</module>
<module>programming</module>
<module>rsvp</module>