Graph modelisation for Path Computation Algorithm 54/86954/31
authorOlivier Dugeon <olivier.dugeon@orange.com>
Thu, 28 Nov 2019 14:40:07 +0000 (15:40 +0100)
committerOlivier Dugeon <olivier.dugeon@orange.com>
Mon, 24 Feb 2020 10:31:57 +0000 (11:31 +0100)
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>
28 files changed:
artifacts/pom.xml
distribution-karaf/pom.xml
docs/graph/graph-user-guide-graph-model.rst [new file with mode: 0644]
docs/graph/graph-user-guide-manage-graph.rst [new file with mode: 0644]
docs/graph/graph-user-guide-running-graph.rst [new file with mode: 0644]
docs/graph/index.rst [new file with mode: 0644]
docs/index.rst
features/graph/features-graph/pom.xml [new file with mode: 0644]
features/graph/odl-bgpcep-graph-api/pom.xml [new file with mode: 0644]
features/graph/odl-bgpcep-graph/pom.xml [new file with mode: 0644]
features/graph/pom.xml [new file with mode: 0644]
features/pom.xml
graph/graph-api/pom.xml [new file with mode: 0644]
graph/graph-api/src/main/java/org/opendaylight/graph/ConnectedEdge.java [new file with mode: 0644]
graph/graph-api/src/main/java/org/opendaylight/graph/ConnectedGraph.java [new file with mode: 0644]
graph/graph-api/src/main/java/org/opendaylight/graph/ConnectedGraphProvider.java [new file with mode: 0644]
graph/graph-api/src/main/java/org/opendaylight/graph/ConnectedVertex.java [new file with mode: 0644]
graph/graph-api/src/main/yang/graph.yang [new file with mode: 0644]
graph/graph-artifacts/pom.xml [new file with mode: 0644]
graph/graph-impl/pom.xml [new file with mode: 0644]
graph/graph-impl/src/main/java/org/opendaylight/graph/impl/ConnectedEdgeImpl.java [new file with mode: 0644]
graph/graph-impl/src/main/java/org/opendaylight/graph/impl/ConnectedGraphImpl.java [new file with mode: 0644]
graph/graph-impl/src/main/java/org/opendaylight/graph/impl/ConnectedGraphServer.java [new file with mode: 0644]
graph/graph-impl/src/main/java/org/opendaylight/graph/impl/ConnectedVertexImpl.java [new file with mode: 0644]
graph/graph-impl/src/main/java/org/opendaylight/graph/impl/GraphListener.java [new file with mode: 0644]
graph/graph-impl/src/main/resources/OSGI-INF/blueprint/graph-server.xml [new file with mode: 0644]
graph/pom.xml [new file with mode: 0644]
pom.xml

index a2f55976794f6713249f58ad0b937a2194f4e7c4..5f4b4294273572bb3923913af927f5ca6e1942df 100644 (file)
                 <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>
index f560c7bd0e545fa1fdb6a4e5266887cd89a493ab..b609fd67560105fc5615e4b46fb9a81b2bf61166 100644 (file)
       <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>
diff --git a/docs/graph/graph-user-guide-graph-model.rst b/docs/graph/graph-user-guide-graph-model.rst
new file mode 100644 (file)
index 0000000..43563cf
--- /dev/null
@@ -0,0 +1,220 @@
+.. _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.
+
diff --git a/docs/graph/graph-user-guide-manage-graph.rst b/docs/graph/graph-user-guide-manage-graph.rst
new file mode 100644 (file)
index 0000000..c4aed50
--- /dev/null
@@ -0,0 +1,382 @@
+.. _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.
+
diff --git a/docs/graph/graph-user-guide-running-graph.rst b/docs/graph/graph-user-guide-running-graph.rst
new file mode 100644 (file)
index 0000000..6b05567
--- /dev/null
@@ -0,0 +1,40 @@
+.. _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
+
+      {}
diff --git a/docs/graph/index.rst b/docs/graph/index.rst
new file mode 100644 (file)
index 0000000..17164f5
--- /dev/null
@@ -0,0 +1,18 @@
+.. _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
index 4fc9abaf5c0c58c65cafc565de223992dee55cbe..234a4e2c30d5e9d847a77e31f9ea93ce1a443162 100644 (file)
@@ -27,3 +27,4 @@ User Guides
    bgp/index
    bmp/index
    pcep/index
+   graph/index
diff --git a/features/graph/features-graph/pom.xml b/features/graph/features-graph/pom.xml
new file mode 100644 (file)
index 0000000..220288f
--- /dev/null
@@ -0,0 +1,37 @@
+<?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>
diff --git a/features/graph/odl-bgpcep-graph-api/pom.xml b/features/graph/odl-bgpcep-graph-api/pom.xml
new file mode 100644 (file)
index 0000000..f86ab16
--- /dev/null
@@ -0,0 +1,42 @@
+<?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>
diff --git a/features/graph/odl-bgpcep-graph/pom.xml b/features/graph/odl-bgpcep-graph/pom.xml
new file mode 100644 (file)
index 0000000..9952349
--- /dev/null
@@ -0,0 +1,42 @@
+<?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>
diff --git a/features/graph/pom.xml b/features/graph/pom.xml
new file mode 100644 (file)
index 0000000..e12863f
--- /dev/null
@@ -0,0 +1,33 @@
+<?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>
index 466207d06e934ee065382d25743199099339025d..15997d31c3385acb9e09906262ae425faf07ad79 100644 (file)
@@ -23,6 +23,7 @@
     <modules>
         <module>bgp</module>
         <module>pcep</module>
+        <module>graph</module>
         <module>bgpcep-extras</module>
         <module>bmp</module>
         <module>rsvp</module>
diff --git a/graph/graph-api/pom.xml b/graph/graph-api/pom.xml
new file mode 100644 (file)
index 0000000..ed8571d
--- /dev/null
@@ -0,0 +1,48 @@
+<?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>
diff --git a/graph/graph-api/src/main/java/org/opendaylight/graph/ConnectedEdge.java b/graph/graph-api/src/main/java/org/opendaylight/graph/ConnectedEdge.java
new file mode 100644 (file)
index 0000000..96065d3
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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();
+
+}
diff --git a/graph/graph-api/src/main/java/org/opendaylight/graph/ConnectedGraph.java b/graph/graph-api/src/main/java/org/opendaylight/graph/ConnectedGraph.java
new file mode 100644 (file)
index 0000000..f163c34
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * 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();
+
+}
diff --git a/graph/graph-api/src/main/java/org/opendaylight/graph/ConnectedGraphProvider.java b/graph/graph-api/src/main/java/org/opendaylight/graph/ConnectedGraphProvider.java
new file mode 100644 (file)
index 0000000..8f21828
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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);
+
+}
diff --git a/graph/graph-api/src/main/java/org/opendaylight/graph/ConnectedVertex.java b/graph/graph-api/src/main/java/org/opendaylight/graph/ConnectedVertex.java
new file mode 100644 (file)
index 0000000..014c2ca
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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();
+
+}
diff --git a/graph/graph-api/src/main/yang/graph.yang b/graph/graph-api/src/main/yang/graph.yang
new file mode 100644 (file)
index 0000000..9ec4504
--- /dev/null
@@ -0,0 +1,291 @@
+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;
+            }
+        }
+    }
+}
+
diff --git a/graph/graph-artifacts/pom.xml b/graph/graph-artifacts/pom.xml
new file mode 100644 (file)
index 0000000..d280cfc
--- /dev/null
@@ -0,0 +1,61 @@
+<?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>
diff --git a/graph/graph-impl/pom.xml b/graph/graph-impl/pom.xml
new file mode 100644 (file)
index 0000000..2df190d
--- /dev/null
@@ -0,0 +1,65 @@
+<?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>
diff --git a/graph/graph-impl/src/main/java/org/opendaylight/graph/impl/ConnectedEdgeImpl.java b/graph/graph-impl/src/main/java/org/opendaylight/graph/impl/ConnectedEdgeImpl.java
new file mode 100644 (file)
index 0000000..682a4be
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * 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";
+    }
+}
diff --git a/graph/graph-impl/src/main/java/org/opendaylight/graph/impl/ConnectedGraphImpl.java b/graph/graph-impl/src/main/java/org/opendaylight/graph/impl/ConnectedGraphImpl.java
new file mode 100644 (file)
index 0000000..8e356b5
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * 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();
+    }
+}
diff --git a/graph/graph-impl/src/main/java/org/opendaylight/graph/impl/ConnectedGraphServer.java b/graph/graph-impl/src/main/java/org/opendaylight/graph/impl/ConnectedGraphServer.java
new file mode 100644 (file)
index 0000000..0ae34ca
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * 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();
+        }
+    }
+}
diff --git a/graph/graph-impl/src/main/java/org/opendaylight/graph/impl/ConnectedVertexImpl.java b/graph/graph-impl/src/main/java/org/opendaylight/graph/impl/ConnectedVertexImpl.java
new file mode 100644 (file)
index 0000000..49a36aa
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * 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();
+        }
+    }
+}
diff --git a/graph/graph-impl/src/main/java/org/opendaylight/graph/impl/GraphListener.java b/graph/graph-impl/src/main/java/org/opendaylight/graph/impl/GraphListener.java
new file mode 100644 (file)
index 0000000..5e66e29
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * 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;
+            }
+        }
+    }
+
+}
+
diff --git a/graph/graph-impl/src/main/resources/OSGI-INF/blueprint/graph-server.xml b/graph/graph-impl/src/main/resources/OSGI-INF/blueprint/graph-server.xml
new file mode 100644 (file)
index 0000000..beee762
--- /dev/null
@@ -0,0 +1,31 @@
+<?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>
diff --git a/graph/pom.xml b/graph/pom.xml
new file mode 100644 (file)
index 0000000..d9fc15e
--- /dev/null
@@ -0,0 +1,37 @@
+<?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>
diff --git a/pom.xml b/pom.xml
index 7ec3698c3b085140a09fe7af5bfb1cc0c98ce68c..729e847c74a29850b4ef685362ccbd1c32593bf7 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -42,6 +42,7 @@
         <!-- Subsystems -->
         <module>bgp</module>
         <module>bmp</module>
+        <module>graph</module>
         <module>pcep</module>
         <module>programming</module>
         <module>rsvp</module>