This NETCONF device example shows how NETCONF device is customized to work with topology data inside NETCONF device. Device sends
notifications when topologies are created and deleted. Device is simulator for network topology, so its functionality is implemented
to serve as an example to show how RPCs are called, take input, return output, how to create topologies, edit topologies,
remove topologies, get topologies etc. Device contains topology with id default-topology by default.
Topology requests and notifications are described in network-topology-rpcs yang file which is located in
examples/models/lighty-example-network-topology-device-model. Therefore the name: network topology device.
Device registers rpc processors to handle incoming RPC requests. They each call method of NetworkTopologyRpcsService.
For every RPC in network-topology-rpcs there is created a single processor. Device also registers topology change
listener which listens to the state of the network topology. It sends notifications when changes to the network
topology are made.
Build root project - for more details check: README
Run device
- extract binary distribution in target directory
- run jar file from zip with default parameter
java -jar lighty-network-topology-device-24.0.0-SNAPSHOT.jar
- to run device on specific port it is necessary to add port number as an argument
- run device on specific port
12345(any available port)
java -jar lighty-network-topology-device-24.0.0-SNAPSHOT.jar 12345
Open session
To connect to a device via SSH, run command
ssh admin@127.0.0.1 -p 12345 -s netconf
where
adminis default username of a device with passwordadmin(no other users)127.0.0.1is the local IP address of the machine where device is running-p 12345is port number of running device, default is17830-s netconfoption establishes the NETCONF session as an SSH subsystem, which means that NETCONF can be used in terminal through opened SSH session
To complete connection with a device, it is necessary to initiate handshake by
sending client's model capabilities in hello-message:
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<capabilities>
<capability>urn:ietf:params:netconf:base:1.0</capability>
<capability>urn:tech.pantheon.netconfdevice.network.topology.rpcs?module=network-topology-rpcs;revision=2018-03-20</capability>
</capabilities>
</hello>
]]>]]>
which informs the device which capabilities the client supports. The capabilities tag contains list of capabilities the client supports, e.g.
<hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<capabilities>
<capability>CAPABILITY_1</capabaility>
<capability>CAPABILITY_2</capabaility>
<capability>CAPABILITY_3</capabaility>
...
</capabilities>
</hello>
]]>]]>
If handshake is not completed by sending hello message with client's capabilities and any other message is sent, following error message is received (long text replaced with ...):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<rpc-error>
<error-type>rpc</error-type>
<error-tag>malformed-message</error-tag>
<error-severity>error</error-severity>
<error-message>
java.lang.IllegalStateException: Hello message not received, instead received: ...
</error-message>
<error-info>
<cause>
java.lang.IllegalStateException: Hello message not received, instead received: ...
</cause>
</error-info>
</rpc-error>
</rpc-reply>
]]>]]>
Close session
To properly exit current NETCONF device SSH session, close-session message needs to be send
<rpc message-id="106" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<close-session/>
</rpc>
]]>]]>
ok message will be replied and then closed the session.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="106">
<ok/>
</rpc-reply>
As a NETCONF device, it provides basic NETCONF defined commands (RPCs):
get
returns data from the device's operational datastore
<rpc message-id="nc1" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<get/>
</rpc>
]]>]]>
Reply contains data that are in the device's operational datastore
(to shorten reply, most of available-capabilites were replaced by ...).
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<rpc-reply message-id="nc1" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<data>
<network-topology xmlns="urn:TBD:params:xml:ns:yang:network-topology">
<topology>
<topology-id>test-topology</topology-id>
<node>
<node-id>test-nettopo-node</node-id>
<connection-status xmlns="urn:opendaylight:netconf-node-topology">connected</connection-status>
<port xmlns="urn:opendaylight:netconf-node-topology">17835</port>
<available-capabilities xmlns="urn:opendaylight:netconf-node-topology">
<available-capability>
<capability>(urn:ietf:params:xml:ns:yang:ietf-inet-types?revision=2013-07-15)ietf-inet-types</capability>
<capability-origin>device-advertised</capability-origin>
</available-capability>
...
</available-capabilities>
<unavailable-capabilities xmlns="urn:opendaylight:netconf-node-topology"/>
<host xmlns="urn:opendaylight:netconf-node-topology">127.0.0.1</host>
</node>
<node>
<node-id>test-nettopo-node-2</node-id>
...
</node>
</topology>
<topology>
<topology-id>default-topology</topology-id>
</topology>
</network-topology>
</data>
</rpc-reply>
]]>]]>
get-config
Returns only configuration data from the device datastore, specified in body of request in source parameter.
<rpc message-id="nc2" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<get-config>
<source>
<running/>
</source>
</get-config>
</rpc>
]]>]]>
The returned reply contains data from running type of configuration datastore
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<rpc-reply message-id="nc2" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<data>
<network-topology xmlns="urn:TBD:params:xml:ns:yang:network-topology">
<topology>
<topology-id>test-topology</topology-id>
<node>
<node-id>test-nettopo-node</node-id>
<port xmlns="urn:opendaylight:netconf-node-topology">17835</port>
<schemaless xmlns="urn:opendaylight:netconf-node-topology">false</schemaless>
<host xmlns="urn:opendaylight:netconf-node-topology">127.0.0.1</host>
<tcp-only xmlns="urn:opendaylight:netconf-node-topology">false</tcp-only>
<keepalive-delay xmlns="urn:opendaylight:netconf-node-topology">0</keepalive-delay>
<username xmlns="urn:opendaylight:netconf-node-topology">admin</username>
<password xmlns="urn:opendaylight:netconf-node-topology">admin</password>
</node>
<node>
<node-id>test-nettopo-node-2</node-id>
...
</node>
</topology>
<topology>
<topology-id>default-topology</topology-id>
</topology>
</network-topology>
</data>
</rpc-reply>
]]>]]>
edit-config
RPC to edit configuration data in the device.
<rpc message-id="nc3" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<edit-config>
<target>
<DATASTORE_TYPE/>
</target>
<default-operation>DEFAULT_OPERATION</default-operation>
<config>
<DATA_TO_EDIT...>
<SOME_DATA operation="OPERATION">
...
</config>
</edit-config>
</rpc>
]]>]]>
NETCONF defines several types of operations, which can be used within edit-config RPC:
merge, replace, create, delete, remove
It can also contain default-operation, for requests without operation
specified:
merge, replace, none
Default behaviour for operations is merge.
Example of edit-config RPC message, to change port value of test-nettopo-node2
in topology test-topology in the device's running datastore.
The config tag contains actual data to edit.
<rpc message-id="nc3" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<edit-config>
<target>
<running/>
</target>
<config xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
<network-topology xmlns="urn:TBD:params:xml:ns:yang:network-topology">
<topology>
<topology-id>test-topology</topology-id>
<node>
<node-id>test-nettopo-node</node-id>
<port xmlns="urn:opendaylight:netconf-node-topology" nc:operation="replace">17837</port>
</node>
</topology>
</network-topology>
</config>
</edit-config>
</rpc>
]]>]]>
simple ok message is returned
When operation create is used to edit existing data, device replies by
appropriate error response:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<rpc-reply message-id="nc3" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<rpc-error>
<error-type>rpc</error-type>
<error-tag>data-exists</error-tag>
<error-severity>error</error-severity>
<error-message>data-exists</error-message>
</rpc-error>
</rpc-reply>
]]>]]>
YANG model used by the device is network-topology-rpcs@2018-03-20.yang, which also uses
netconf-node-topology@2015-01-14.yang and network-topology@2013-10-21.yang.
In YANG model, there are defined groupings for node-data and topology-data,
which will be referenced further.
-
node-datacontains list of nodes withnode-idas key and every node has a lot of optional fields that are described in YANG model. -
topology-datacontains list of topologies withtopology-idas key and every topology has a lot of optional fields that are described in YANG model.
Network topology device has defined following RPCs in YANG model and implemented as mentioned in Brief description:
get-node-from-topology-by-id
- takes mandatory
is-config,topology-idandnode-idvalues as an input to RPC is-configis boolean value, which tells if RPC returns configuration or operational datatopology-idis id of topology where to look for node withnode-id
<rpc message-id="rpc1" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<get-node-from-topology-by-id xmlns="urn:tech.pantheon.netconfdevice.network.topology.rpcs">
<is-config>true</is-config>
<topology-id>test-topology</topology-id>
<node-id>test-nettopo-node</node-id>
</get-node-from-topology-by-id>
</rpc>
]]>]]>
- if node is found, returns node-data of searched node
Output example for is-config: true
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<rpc-reply message-id="rpc1" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<node xmlns="urn:tech.pantheon.netconfdevice.network.topology.rpcs">
<node-id>test-nettopo-node</node-id>
<password>admin</password>
<username>admin</username>
<port>17835</port>
<tcp-only>false</tcp-only>
<host>127.0.0.1</host>
<schemaless>false</schemaless>
</node>
</rpc-reply>
]]>]]>
Output example for is-config: false (with node added before calling RPC)
(to shorten reply, most of available-capabilites were replaced by ...)
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<rpc-reply message-id="rpc1" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<node xmlns="urn:tech.pantheon.netconfdevice.network.topology.rpcs">
<node-id>test-nettopo-node</node-id>
<available-capabilities>
<available-capability>
<capability>(urn:ietf:params:xml:ns:yang:ietf-inet-types?revision=2013-07-15)ietf-inet-types</capability>
<capability-origin>device-advertised</capability-origin>
</available-capability>
...
</available-capabilities>
<port>17835</port>
<tcp-only>false</tcp-only>
<host>127.0.0.1</host>
<unavailable-capabilities/>
<connection-status>connected</connection-status>
</node>
</rpc-reply>
]]>]]>
- if node is not found, simple
okmessage is returned
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="rpc1">
<ok/>
</rpc-reply>
get-topology-ids
(has no inputs)
<rpc message-id="rpc2" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<get-topology-ids xmlns="urn:tech.pantheon.netconfdevice.network.topology.rpcs">
</get-topology-ids>
</rpc>
]]>]]>
- returns list of ids of all topologies, which device contains
get-topology-by-id
- takes mandatory
topology-idvalue as an input to RPC topology-idis id of topology to return
<rpc message-id="rpc3" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<get-topology-by-id xmlns="urn:tech.pantheon.netconfdevice.network.topology.rpcs">
<topology-id>default-topology</topology-id>
</get-topology-by-id>
</rpc>
]]>]]>
- if topology is found, returns topology-data for searched topology
get-topologies
(has no inputs)
<rpc message-id="rpc4" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<get-topologies xmlns="urn:tech.pantheon.netconfdevice.network.topology.rpcs">
</get-topologies>
</rpc>
]]>]]>
- returns list of all topologies, which device contains
create-topology
- takes mandatory
topology-idas input value - creates new topology with
topology-idvalue
<rpc message-id="rpc5" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<create-topology xmlns="urn:tech.pantheon.netconfdevice.network.topology.rpcs">
<topology-id>test-topology</topology-id>
</create-topology>
</rpc>
]]>]]>
- returns simple
okmessage
add-node-into-topology
- takes
topology-id(mandatory) andnode-dataas input values - creates new node in topology with
topology-idand providednode-datavalues - only mandatory value in
node-dataisnode-id, because it is a unique key identifier of node in topology - all parameters are described in YANG models mentioned at the beginning of section
- in case of this simulator device, it is not needed to have real device running to connect it as a node into topology
<rpc message-id="rpc6" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<add-node-into-topology xmlns="urn:tech.pantheon.netconfdevice.network.topology.rpcs">
<topology-id>test-topology</topology-id>
<node>
<node-id>test-nettopo-node</node-id>
<host>127.0.0.1</host>
<port>17835</port>
<username>admin</username>
<password>admin</password>
<tcp-only>false</tcp-only>
<keepalive-delay>0</keepalive-delay>
<schemaless>false</schemaless>
</node>
</add-node-into-topology>
</rpc>
]]>]]>
remove-node-from-topology
- takes mandatory
topology-idandnode-idas input values - removes node with
node-idvalue from topology withtopology-idvalue
<rpc message-id="rpc7" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<remove-node-from-topology xmlns="urn:tech.pantheon.netconfdevice.network.topology.rpcs">
<topology-id>test-topology</topology-id>
<node-id>test-nettopo-node</node-id>
</remove-node-from-topology>
</rpc>
]]>]]>
- returns simple
okmessage
remove-topology
- takes mandatory
topology-idas input value - removes topology with
topology-idvalue
<rpc message-id="rpc8" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<remove-topology xmlns="urn:tech.pantheon.netconfdevice.network.topology.rpcs">
<topology-id>test-topology</topology-id>
</remove-topology>
</rpc>
]]>]]>
- returns simple
okmessage
remove-all-topologies
(has no inputs)
<rpc message-id="rpc9" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<remove-all-topologies xmlns="urn:tech.pantheon.netconfdevice.network.topology.rpcs">
</remove-all-topologies>
</rpc>
]]>]]>
- returns simple
okmessage
After each of the upper RPC calls, appropriate info message can be seen in device logs.
Example of log info for create-topology RPC:
INFO [nioEventLoopGroup-2-3] (NetworkTopologyServiceImpl.java:186) - Creating topology Uri{_value=test-topology}
INFO [pool-6-thread-1] (TopologyDataTreeChangeListener.java:65) - Data has been created
contains information with what parameters was RPC called:
_value: test-topology and notification from TopologyDataTreeChangeListener
that data has been created on device.
Example of successful reply message:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<rpc-reply message-id="id" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"/>
]]>]]>
where message-id corresponds with message-id which RPC was called with, so for
request with message-id rpc1 the response will contain same message-id rpc1.
Example of unsuccessful reply contains appropriate error message (e.g. illegal negative value on field with only positive values allowed)
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<rpc-reply message-id="rpc6" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<rpc-error>
<error-type>application</error-type>
<error-tag>operation-failed</error-tag>
<error-severity>error</error-severity>
<error-message>Unexpected error</error-message>
<error-info>
<ERROR>java.lang.UnsupportedOperationException:
java.lang.NumberFormatException:
Illegal leading minus sign on unsigned string -1.
</ERROR>
</error-info>
</rpc-error>
</rpc-reply>
]]>]]>
Preconfigured data Before device starts, it reads initial data from XML configuration files
initial-network-topo-config-datastore.xmlinitial-network-topo-operational-datastore.xmleach corresponding toconfigurationandoperational datastore. If it is needed to preconfigure device with initial data, XML files have to be modified to contain those particular data.
Example of XML file for configuration datastore,
when device needs to be started with topology init-topology-A, which contains
node init-node-A, in configuration datastore:
<?xml version='1.0' encoding='UTF-8'?>
<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<network-topology xmlns="urn:TBD:params:xml:ns:yang:network-topology">
<topology>
<topology-id>default-topology</topology-id>
</topology>
<topology>
<topology-id>init-topology-A</topology-id>
<node>
<node-id>init-node-A</node-id>
<port xmlns="urn:opendaylight:netconf-node-topology">12345</port>
<schemaless xmlns="urn:opendaylight:netconf-node-topology">false</schemaless>
<host xmlns="urn:opendaylight:netconf-node-topology">127.0.0.1</host>
<tcp-only xmlns="urn:opendaylight:netconf-node-topology">false</tcp-only>
<keepalive-delay xmlns="urn:opendaylight:netconf-node-topology">0</keepalive-delay>
<username xmlns="urn:opendaylight:netconf-node-topology">admin</username>
<password xmlns="urn:opendaylight:netconf-node-topology">admin</password>
</node>
</topology>
</network-topology>
</data>
This device also supports notifications.
Subscription to get notifications is done by
sending create-subscription message:
<rpc message-id="rpc10" xmlns ="urn:ietf:params:xml:ns:netconf:base:1.0">
<create-subscription xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
</create-subscription>
</rpc>
]]>]]>
when subscription is created, simple ok message is returned.
Notifications for this device are defined in network-topology-rpcs YANG model,
and there are two type of them:
new-topology-created
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
<eventTime>2020-08-31T20:08:04Z</eventTime>
<new-topology-created xmlns="urn:tech.pantheon.netconfdevice.network.topology.rpcs">
<topology-id>test-topology-for-notification</topology-id>
</new-topology-created>
</notification>
]]>]]>
This notification is sent, when new topology is created on device. It contains information about topology created, and the time event occurred.
topology-deleted
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
<eventTime>2020-08-31T20:10:04Z</eventTime>
<topology-deleted xmlns="urn:tech.pantheon.netconfdevice.network.topology.rpcs">
<topology-ids>test-topology-for-notification</topology-ids>
</topology-deleted>
</notification>
]]>]]>
This notification is sent, when topology was deleted from device. It contains information about topology deleted, and the time event occurred.
This NETCONF device simulator supports persistence, allowing data to be stored and reloaded between sessions. Persistence can be manually enabled or disabled in the application's initial arguments.
-
Directory for Persistence Files: Specify the directory for storing and loading persisted data using the -i JVM argument.
Example:-i /home/user/config -
Required Datastore Files: The directory must contain the following files:
initial-network-topo-config-datastore.xml
initial-network-topo-operational-datastore.xml
Note: Using the -i and -o path for the same directory will result in persistence (data will be rewritten when application closes). -
Default Behavior: When -i argument is not set, persistence is disabled by default:
Example Startup Command:
java -jar lighty-network-topology-device-24.0.0-SNAPSHOT.jar -i path/to/persistence/directory -o path/to/persistence/directory