NETCONF Call Home
-----------------
-.. important::
-
- The call home feature is experimental and will change in a future
- release. In particular, the Yang models will change to those specified
- in the `RFC 8071 <https://tools.ietf.org/html/rfc8071>`__
-
Call Home Installation
~~~~~~~~~~~~~~~~~~~~~~
.. note::
- In order to test Call Home functionality we recommend Netopeer.
- See `Netopeer Call Home <https://github.com/CESNET/netopeer/wiki/CallHome>`__ to learn how to enable call-home on Netopeer.
+ In order to test Call Home functionality we recommend Netopeer or
+ Netopeer2. See `Netopeer Call Home <https://github.com/CESNET/netopeer/wiki/CallHome>`__
+ or `Netopeer2 <https://github.com/CESNET/netopeer2>`__ to learn how to
+ enable call-home on Netopeer.
Northbound Call-Home API
~~~~~~~~~~~~~~~~~~~~~~~~
Global Configuration
^^^^^^^^^^^^^^^^^^^^
+.. important::
+ The global configuration is not a part of the `RFC 8071
+ <https://tools.ietf.org/html/rfc8071>`__ and, therefore, subject to change.
+
Configuring global credentials
''''''''''''''''''''''''''''''
-ODL Call-Home server allows user to configure global credentials, which
-will be used for devices which does not have device-specific credentials
-configured.
+ODL Call-Home server allows user to configure global credentials, which will be
+used for connected over SSH transport protocol devices which does not have
+device-specific credentials configured.
This is done by creating
``/odl-netconf-callhome-server:netconf-callhome-server/global/credentials``
*Configuring global username & passwords to try*
-.. code-block:: none
+.. code-block::
PUT
/restconf/config/odl-netconf-callhome-server:netconf-callhome-server/global/credentials HTTP/1.1
security issue, this also causes the Call-Home Server to drastically increase its output
to the log.
-.. code-block:: none
+.. code-block::
POST
/restconf/config/odl-netconf-callhome-server:netconf-callhome-server/global HTTP/1.1
Device-Specific Configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Allowing Device & Configuring Name
-''''''''''''''''''''''''''''''''''
+Netconf Call Home server supports both of the secure transports used
+by the Network Configuration Protocol (NETCONF) - Secure Shell (SSH),
+and Transport Layer Security (TLS).
+
+Configure device to connect over SSH protocol
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Netconf Call Home Server uses device provided SSH server key (host key)
to identify device. The pairing of name and server key is configured in
immediately. In either case, the device that connects to the Call home server
leaves a record of its presence in the operational store.
+Configuring Device with Device-specific Credentials
+'''''''''''''''''''''''''''''''''''''''''''''''''''
+
+Adding specific device to the allowed list is done by creating
+``/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices/device/{device}``
+with device-id and connection parameters inside the ssh-client-params container.
+
+*Configuring Device with Credentials*
+
+.. code-block::
+
+ PUT
+ /restconf/config/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices/device/example HTTP/1.1
+ Content-Type: application/json
+ Accept: application/json
+
+.. code-block:: json
+
+ {
+ "device": {
+ "unique-id": "example",
+ "ssh-client-params": {
+ "credentials": {
+ "username": "example",
+ "passwords": [ "password" ]
+ },
+ "ssh-host-key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDHoH1jMjltOJnCt999uaSfc48ySutaD3ISJ9fSECe1Spdq9o9mxj0kBTTTq+2V8hPspuW75DNgN+V/rgJeoUewWwCAasRx9X4eTcRrJrwOQKzb5Fk+UKgQmenZ5uhLAefi2qXX/agFCtZi99vw+jHXZStfHm9TZCAf2zi+HIBzoVksSNJD0VvPo66EAvLn5qKWQD4AdpQQbKqXRf5/W8diPySbYdvOP2/7HFhDukW8yV/7ZtcywFUIu3gdXsrzwMnTqnATSLPPuckoi0V2jd8dQvEcu1DY+rRqmqu0tEkFBurlRZDf1yhNzq5xWY3OXcjgDGN+RxwuWQK3cRimcosH"
+ }
+ }
+ }
+
+Configuring Device with Global Credentials
+'''''''''''''''''''''''''''''''''''''''''''''''''''
+
+It is possible to omit 'username' and 'password' for ssh-client-params,
+in such case values from global credentials will be used.
+
*Example of configuring device*
-.. code-block:: none
+.. code-block::
+
+ PUT
+ /restconf/config/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices/device/example HTTP/1.1
+ Content-Type: application/json
+ Accept: application/json
+
+.. code-block:: json
+
+ {
+ "device": {
+ "unique-id": "example",
+ "ssh-client-params": {
+ "host-key": "AAAAB3NzaC1yc2EAAAADAQABAAABAQDHoH1jMjltOJnCt999uaSfc48ySutaD3ISJ9fSECe1Spdq9o9mxj0kBTTTq+2V8hPspuW75DNgN+V/rgJeoUewWwCAasRx9X4eTcRrJrwOQKzb5Fk+UKgQmenZ5uhLAefi2qXX/agFCtZi99vw+jHXZStfHm9TZCAf2zi+HIBzoVksSNJD0VvPo66EAvLn5qKWQD4AdpQQbKqXRf5/W8diPySbYdvOP2/7HFhDukW8yV/7ZtcywFUIu3gdXsrzwMnTqnATSLPPuckoi0V2jd8dQvEcu1DY+rRqmqu0tEkFBurlRZDf1yhNzq5xWY3OXcjgDGN+RxwuWQK3cRimcosH"
+ }
+ }
+ }
+
+Deprecated configuration models for devices accessed with SSH protocol
+''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
+
+With `RFC 8071 <https://tools.ietf.org/html/rfc8071>`__ alignment and adding
+support for TLS transport following configuration models has been marked
+deprecated.
+
+Configuring Device with Global Credentials
+'''''''''''''''''''''''''''''''''''''''''''''''''''
+
+*Example of configuring device*
+
+.. code-block::
PUT
/restconf/config/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices/device/example HTTP/1.1
*Configuring Device with Credentials*
-.. code-block:: none
+.. code-block::
PUT
/restconf/config/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices/device/example HTTP/1.1
}
}
+Configure device to connect over TLS protocol
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Netconf Call Home Server allows devices to use TLS transport protocol to
+establish a connection towards the NETCONF device. This communication
+requires proper setup to make two-way TLS authentication possible for client
+and server.
+
+The initial step is to configure certificates and keys for two-way TLS by
+storing them within the netconf-keystore.
+
+*Adding a client private key credential to the netconf-keystore*
+
+.. code-block::
+
+ POST
+ /rests/operations/netconf-keystore:add-keystore-entry HTTP/1.1
+ Content-Type: application/json
+ Accept: application/json
+
+.. code-block:: json
+
+ {
+ "input": {
+ "key-credential": [
+ {
+ "key-id": "example-client-key-id",
+ "private-key": "base64encoded-private-key",
+ "passphrase": "passphrase"
+ }
+ ]
+ }
+ }
+
+*Associate a private key with a client and CA certificates chain*
+
+.. code-block::
+
+ POST
+ /rests/operations/netconf-keystore:add-private-key HTTP/1.1
+ Content-Type: application/json
+ Accept: application/json
+
+.. code-block:: json
+
+ {
+ "input": {
+ "private-key": [
+ {
+ "name": "example-client-key-id",
+ "data": "key-data",
+ "certificate-chain": [
+ "certificate-data"
+ ]
+ }
+ ]
+ }
+ }
+
+*Add a list of trusted CA and server certificates*
+
+.. code-block::
+
+ POST
+ /rests/operations/netconf-keystore:add-trusted-certificate HTTP/1.1
+ Content-Type: application/json
+ Accept: application/json
+
+.. code-block:: json
+
+ {
+ "input": {
+ "trusted-certificate": [
+ {
+ "name": "example-ca-certificate",
+ "certificate": "ca-certificate-data"
+ },
+ {
+ "name": "example-server-certificate",
+ "certificate": "server-certificate-data"
+ }
+ ]
+ }
+ }
+
+In a second step, it is required to create an allowed device associated with
+a server certificate and client key. The server certificate will be used to
+identify and pin the NETCONF device during SSL handshake and should be unique
+among the allowed devices.
+
+*Add device configuration for TLS protocol to allowed devices list*
+
+.. code-block::
+
+ PUT
+ /restconf/config/odl-netconf-callhome-server:netconf-callhome-server/allowed-devices/device/example-device HTTP/1.1
+ Content-Type: application/json
+ Accept: application/json
+
+.. code-block:: json
+
+ {
+ "device": {
+ "unique-id": "example-device",
+ "tls-client-params": {
+ "key-id": "example-client-key-id",
+ "certificate-id": "example-server-certificate"
+ }
+ }
+ }
+
Operational Status
^^^^^^^^^^^^^^^^^^
The device **must** initiate the connection and the server will not try to re-establish the
connection in case of a drop. By requirement, the server cannot assume it has connectivity
to the device due to NAT or firewalls among others.
+
+Reading data with selected fields
+---------------------------------
+
+Overview
+~~~~~~~~
+
+If user would like to read only selected fields from NETCONF device, it is possible to use
+fields query parameter that is described by RFC-8040. RESTCONF parses content of query
+parameter into format that is accepted by NETCONF subtree filtering - filtering of data is done
+on NETCONF server, not on NETCONF client side. This approach optimizes network traffic load,
+because data in which user doesn't have interest, is not transferred over network.
+
+Next advantages:
+
+* using single RESTCONF request and single NETCONF RPC for reading multiple subtrees
+* possibility to read only selected fields under list node across multiple hierarchies
+ (it cannot be done without proper selection API)
+
+.. note::
+
+ More information about fields query parameter: `RFC 8071 <https://tools.ietf.org/html/rfc8040#section-4.8.3>`__
+
+Preparation of data
+~~~~~~~~~~~~~~~~~~~
+
+Mounting NETCONF device that runs on NETCONF testtool:
+
+.. code-block:: bash
+
+ curl --location --request PUT 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=testtool' \
+ --header 'Authorization: Basic YWRtaW46YWRtaW4=' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "node": [
+ {
+ "node-id": "testtool",
+ "netconf-node-topology:host": "127.0.0.1",
+ "netconf-node-topology:port": 36000,
+ "netconf-node-topology:keepalive-delay": 100,
+ "netconf-node-topology:tcp-only": false,
+ "netconf-node-topology:username": "admin",
+ "netconf-node-topology:password": "admin"
+ }
+ ]
+ }'
+
+Setting initial configuration on NETCONF device:
+
+.. code-block:: bash
+
+ curl --location --request PUT 'http://127.0.0.1:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=testtool/yang-ext:mount/test-module:root' \
+ --header 'Authorization: Basic YWRtaW46YWRtaW4=' \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "root": {
+ "simple-root": {
+ "leaf-a": "asddhg",
+ "leaf-b": "ffffff",
+ "ll": [
+ "str1",
+ "str2",
+ "str3"
+ ],
+ "nested": {
+ "sample-x": true,
+ "sample-y": false
+ }
+ },
+ "list-root": {
+ "branch-ab": 5,
+ "top-list": [
+ {
+ "key-1": "ka",
+ "key-2": "kb",
+ "next-data": {
+ "switch-1": [
+ null
+ ],
+ "switch-2": [
+ null
+ ]
+ },
+ "nested-list": [
+ {
+ "identifier": "f1",
+ "foo": 1
+ },
+ {
+ "identifier": "f2",
+ "foo": 10
+ },
+ {
+ "identifier": "f3",
+ "foo": 20
+ }
+ ]
+ },
+ {
+ "key-1": "kb",
+ "key-2": "ka",
+ "next-data": {
+ "switch-1": [
+ null
+ ]
+ },
+ "nested-list": [
+ {
+ "identifier": "e1",
+ "foo": 1
+ },
+ {
+ "identifier": "e2",
+ "foo": 2
+ },
+ {
+ "identifier": "e3",
+ "foo": 3
+ }
+ ]
+ },
+ {
+ "key-1": "kc",
+ "key-2": "ke",
+ "next-data": {
+ "switch-2": [
+ null
+ ]
+ },
+ "nested-list": [
+ {
+ "identifier": "q1",
+ "foo": 13
+ },
+ {
+ "identifier": "q2",
+ "foo": 14
+ },
+ {
+ "identifier": "q3",
+ "foo": 15
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }'
+
+Examples
+--------
+
+1. Reading whole leaf-list 'll' and leaf 'nested/sample-x' under 'simple-root' container.
+
+RESTCONF request:
+
+.. code-block:: bash
+
+ curl --location --request GET 'http://localhost:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=testtool/yang-ext:mount/test-module:root/simple-root?content=config&fields=ll;nested/sample-x' \
+ --header 'Authorization: Basic YWRtaW46YWRtaW4=' \
+ --header 'Cookie: JSESSIONID=node01h4w82eorc1k61866b71qjgj503.node0'
+
+Generated NETCONF RPC request:
+
+.. code-block:: xml
+
+ <rpc message-id="m-18" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <get-config>
+ <source>
+ <running/>
+ </source>
+ <filter xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:type="subtree">
+ <root xmlns="urn:ietf:params:xml:ns:yang:test-model">
+ <simple-root>
+ <ll/>
+ <nested>
+ <sample-x/>
+ </nested>
+ </simple-root>
+ </root>
+ </filter>
+ </get-config>
+ </rpc>
+
+.. note::
+
+ Using fields query parameter it is also possible to read whole leaf-list or list without
+ necessity to specify value / key predicate (without reading parent entity). Such scenario
+ is not permitted in RFC-8040 paths alone - fields query parameter can be used as
+ workaround for this case.
+
+RESTCONF response:
+
+.. code-block:: json
+
+ {
+ "test-module:simple-root": {
+ "ll": [
+ "str3",
+ "str1",
+ "str2"
+ ],
+ "nested": {
+ "sample-x": true
+ }
+ }
+ }
+
+2. Reading all identifiers of 'nested-list' under all elements of 'top-list'.
+
+RESTCONF request:
+
+.. code-block:: bash
+
+ curl --location --request GET 'http://localhost:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=testtool/yang-ext:mount/test-module:root/list-root?content=config&fields=top-list(nested-list/identifier)' \
+ --header 'Authorization: Basic YWRtaW46YWRtaW4=' \
+ --header 'Cookie: JSESSIONID=node01h4w82eorc1k61866b71qjgj503.node0'
+
+Generated NETCONF RPC request:
+
+.. code-block:: xml
+
+ <rpc message-id="m-27" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <get-config>
+ <source>
+ <running/>
+ </source>
+ <filter xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:type="subtree">
+ <root xmlns="urn:ietf:params:xml:ns:yang:test-model">
+ <list-root>
+ <top-list>
+ <nested-list>
+ <identifier/>
+ </nested-list>
+ <key-1/>
+ <key-2/>
+ </top-list>
+ </list-root>
+ </root>
+ </filter>
+ </get-config>
+ </rpc>
+
+.. note::
+
+ NETCONF client automatically fetches values of list keys since they are required for correct
+ deserialization of NETCONF response and at the end serialization of response to RESTCONF
+ response (JSON/XML).
+
+RESTCONF response:
+
+.. code-block:: json
+
+ {
+ "test-module:list-root": {
+ "top-list": [
+ {
+ "key-1": "ka",
+ "key-2": "kb",
+ "nested-list": [
+ {
+ "identifier": "f3"
+ },
+ {
+ "identifier": "f2"
+ },
+ {
+ "identifier": "f1"
+ }
+ ]
+ },
+ {
+ "key-1": "kb",
+ "key-2": "ka",
+ "nested-list": [
+ {
+ "identifier": "e3"
+ },
+ {
+ "identifier": "e2"
+ },
+ {
+ "identifier": "e1"
+ }
+ ]
+ },
+ {
+ "key-1": "kc",
+ "key-2": "ke",
+ "nested-list": [
+ {
+ "identifier": "q3"
+ },
+ {
+ "identifier": "q2"
+ },
+ {
+ "identifier": "q1"
+ }
+ ]
+ }
+ ]
+ }
+ }
+
+3. Reading value of leaf 'branch-ab' and all values of leaves 'switch-1' that are placed
+ under 'top-list' list elements.
+
+RESTCONF request:
+
+.. code-block:: bash
+
+ curl --location --request GET 'http://localhost:8181/rests/data/network-topology:network-topology/topology=topology-netconf/node=testtool/yang-ext:mount/test-module:root/list-root?content=config&fields=branch-ab;top-list/next-data/switch-1' \
+ --header 'Authorization: Basic YWRtaW46YWRtaW4=' \
+ --header 'Cookie: JSESSIONID=node01jx6o5thwae9t1ft7c2zau5zbz4.node0'
+
+Generated NETCONF RPC request:
+
+.. code-block:: xml
+
+ <rpc message-id="m-42" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <get-config>
+ <source>
+ <running/>
+ </source>
+ <filter xmlns:ns0="urn:ietf:params:xml:ns:netconf:base:1.0" ns0:type="subtree">
+ <root xmlns="urn:ietf:params:xml:ns:yang:test-model">
+ <list-root>
+ <branch-ab/>
+ <top-list>
+ <next-data>
+ <switch-1/>
+ </next-data>
+ <key-1/>
+ <key-2/>
+ </top-list>
+ </list-root>
+ </root>
+ </filter>
+ </get-config>
+ </rpc>
+
+RESTCONF response:
+
+.. code-block:: json
+
+ {
+ "test-module:list-root": {
+ "branch-ab": 5,
+ "top-list": [
+ {
+ "key-1": "ka",
+ "key-2": "kb",
+ "next-data": {
+ "switch-1": [
+ null
+ ]
+ }
+ },
+ {
+ "key-1": "kb",
+ "key-2": "ka",
+ "next-data": {
+ "switch-1": [
+ null
+ ]
+ }
+ },
+ {
+ "key-1": "kc",
+ "key-2": "ke"
+ }
+ ]
+ }
+ }