14 minutes
Using NETCONF to Configure a Switch
This blog post shows how to configure a switch using NETCONF command line clients. As an example, we read and set the hostname of a NETCONF capable switch.
Two command line clients are explored: netopeer2-cli, included in the Netopeer2 NETCONF project, and netconf-client, which is a Python client and library.
NETCONF Server we use Infix, but any NETCONF capable network switch should suffice.
Hints on installing the NETCONF clients on Linux as well as Infix as a virtual switch on the same Linux PC (GNS3 or Qeneth) are provided further below.
Using a NETCONF Client
We wish to read and set system hostname via NETCONF (ietf-system.yang).
.----. .42 .1 .--------.
| PC +---------------------+ Switch |
'----' 10.0.1.0/24 '--------'
NETCONF NETCONF
Client Server
Preparation
First you need the NETCONF login credentials for your NETCONF Server (the switch). In case you use Infix1, the default credentials are (user/pass): admin/admin
It is assumed you have installed your NETCONF client2.
Update config with netopeer2-cli
Start netopeer2-cli
and connect to the server (the Switch)
~$ netopeer2-cli
> connect --host 10.0.1.1 --login admin
The authenticity of the host '10.0.1.1' cannot be established.
ssh-rsa key fingerprint is e5:78:fe:c0:38:14:d2:9e:fa:32:1d:ff:06:63:42:14:7b:0f:d8:b3.
Are you sure you want to continue connecting (yes/no)? yes
admin@10.0.1.1 password: admin
We can read the whole running config with get-config --source running
,
but for easier overview, we filter out everything except the config related
to ietf-system.yang.
> get-config --source running --filter-xpath /system
DATA
<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<system xmlns="urn:ietf:params:xml:ns:yang:ietf-system">
<hostname>infix</hostname>
</system>
</data>
To change the hostname on the switch to foo, create a file on the PC, e.g., hostname.xml with the following input:
<system xmlns="urn:ietf:params:xml:ns:yang:ietf-system">
<hostname>foo</hostname>
</system>
Now we can set the config using edit-config
, read-out the
configuration to verify, and disconnect.
> edit-config --target running --config=/path/to/hostname.xml
OK
> get-config --source running --filter-xpath /system
DATA
<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<system xmlns="urn:ietf:params:xml:ns:yang:ietf-system">
<hostname>foo</hostname>
</system>
</data>
> disconnect
>
Update config with netconf-client
netconf-client works more in the request-response manner since it requires host with user and password combination with each request. One of the simplest requests that can be sent to server is to fetch all available configuration data:
~$ netconf-client --host 10.0.1.1 -u admin -p admin --get
Which returns the output similar to the below one:
<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
...
...
...
<system xmlns="urn:ietf:params:xml:ns:yang:ietf-system">
<hostname>infix</hostname>
</system>
It is also possible to edit configuration, in a similar way as it is done
with netopeer2-cli above. The only difference is that the hostname.xml
file needs to be wrapped inside <config ... </config>
as follows:
<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<system xmlns="urn:ietf:params:xml:ns:yang:ietf-system">
<hostname>foo</hostname>
</system>
</config>
Then we issue the following netconf-cli commands to set and read configuration:
~$ netconf-client --host 10.0.1.1 -u admin -p admin --edit-config -i /path/to/hostname.xml
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:message-id="0">
<ok/>
</rpc-reply>
~$ netconf-client --host 10.0.1.1 -u admin -p admin --get-config
<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
...
...
...
<system xmlns="urn:ietf:params:xml:ns:yang:ietf-system">
<hostname>foo</hostname>
</system>
</data>
Installation of NETCONF client
To set-up a NETCONF client two different packages are proposed in this section: netopeer2-cli and netconf-client.
netopeer2-cli
The netopeer2-cli
program is a part of the Netopeer2 project. See
their GitHub page for more information.
It should be possible to install netopeer2 as every other Ubuntu
package by running apt install netopeer2
.
~$ sudo apt install netopeer2
The following packages will be INSTALLED:
netopeer2
0 packages upgraded, 1 newly installed, 0 reinstalled, 0 to remove and 10 not upgraded.
Need to get 212 kB of archives. After unpacking 0 B will be used.
Get: 1 http://ftp.acc.umu.se/ubuntu jammy/universe amd64 netopeer2 amd64 2.0.35-1ubuntu1 [212 kB]
Fetched 212 kB in 0s (1 807 kB/s)
(Reading database ... 671332 files and directories currently installed.)
Preparing to unpack .../netopeer2_2.0.35-1ubuntu1_amd64.deb ...
Unpacking netopeer2 (2.0.35-1ubuntu1) over (2.0.35-1ubuntu1) ...
Setting up netopeer2 (2.0.35-1ubuntu1) ...
sysrepoctl error: Invalid option or missing argument: -a
For more details you may try to increase the verbosity up to "-v3".
dpkg: error processing package netopeer2 (--configure):
installed netopeer2 package post-installation script subprocess returned error exit status 1
Processing triggers for man-db (2.10.2-1) ...
Errors were encountered while processing:
netopeer2
E: Sub-process /usr/bin/dpkg returned an error code (1)
Setting up netopeer2 (2.0.35-1ubuntu1) ...
sysrepoctl error: Invalid option or missing argument: -a
For more details you may try to increase the verbosity up to "-v3".
dpkg: error processing package netopeer2 (--configure):
installed netopeer2 package post-installation script subprocess returned error exit status 1
Errors were encountered while processing:
netopeer2
~$
If the package is not available, it is possible to clone its repository and install it in that way:
~$ git clone https://github.com/CESNET/netopeer2.git
~$ cd netopeer2
~$ mkdir build && cd build && cmake .. && make && make install
There could be some missing dependencies so before installing netopeer2, it is recommended to check and/or install the following packages:
~$ sudo apt-get update
~$ sudo apt-get install git cmake build-essential bison flex libpcre3-dev \
libev-dev libavl-dev libprotobuf-c-dev protobuf-c-compiler \
swig python-dev lua5.2 pkg-config libpcre++-dev openssl \
libssl-dev libcrypto++-dev zlib1g-dev
As you could see there are some error messages returned after the installation. It is important to highlight that the package is successfully installed and can be used, but the warnings persist in the package system. More instructions on how to get around this can be found in the last section of this blog.
Python-based NETCONF client
Since the package is based on Python, as a prerequisite it is needed to install Python PIP package and then use the same to install netconf.
~$ apt install python3-pip
Then we can use pip
to install the client locally:
~$ pip install netconf
For more information, see the associated project page at GitHub, and their excellent documentation.
Hints on installation of Infix as NETCONF server
Infix is a great alternative if you do not have access to NETCONF capable switch. It enables you to make the following setup virtually within your Linux PC.
.----. .42 .1 .--------.
| PC +---------------------+ Switch |
'----' 10.0.1.0/24 '--------'
NETCONF NETCONF
Client Server
Please see the README in the Infix GitHub Repo. It contains guidelines for installing Infix and running virtually using Qeneth or GNS3.
Note, use the x86_64 version of Infix, NOT the x86_64_classic version, as the latter does not include NETCONF server support
Infix on GNS3
After installing GNS3 to your device, it is required to import Infix as an appliance, as explained on Infix GitHub page:
Download the latest build of the x86_64, or x86_64_classic flavor. Unpack in a dedicated directory and use Import Appliance to install the .gns3a file into GNS3. Infix (x86_64) is in the “Router” category, it has 10 interfaces available by default for use as switch ports or routing. The classic build only has one interface by default, geared more towards acting as an end device.
It is important to mention that for this purpose it is required to install Infix version without the “classic” tag in the name since those versions don’t support NETCONF.
After the Infix is added to GNS3, it is possible to create a simple setup as below:
.--.-.
( ( )__
(_, \ ) ,_) NAT1
'-'--`--'
|
|
(⇅)
Infix
By default, the Infix device gets an IPv6 address assigned, which can be
used for setting-up the NETCONF communication. The only requirement is
to have a tap-interface defined to connect between the host device and
Infix device. This is an example of IPv6 address to be used:
fe80::ff:fe00:0%tap-infix
In case we want to use IPv4 address, it is only left to assing an IP address to the Infix device and since the NAT interface is in use, we obtain one from DHCP server by running:
> udhcpc -i eth0
The assigned IP address is in form 192.168.122.y, therefore we can update the system overview and use this IP address while setting up client-to-server connection:
.----. .x .y .--------.
| PC +---------------------+ Switch |
'----' 192.168.122.0/24 '--------'
NETCONF NETCONF
Client Server
Infix on qeneth
Follow the instructions on the github page to install qeneth on your machine.
The major difference as compared to the tutorial is that the x86_64 Infix version should be used (rather than x86_64_classic). Thus, as compared to Host Interaction Tutorial you should:
- download infix-x86_64.tar.gz (see below)
- and modify the ‘topology.dot.in’ accordingly
Create a separate working directory in which you want to run your qeneth topology and download the Infix image for installing the server, for example:
~$ mkdir tutorial
~$ cd tutorial/
~/tutorial$ wget -q https://github.com/kernelkit/infix/releases/download/latest/infix-x86_64.tar.gz
~/tutorial$ tar xf infix-x86_64.tar.gz infix-x86_64/infix-x86_64.img
~/tutorial$ mv infix-x86_64/infix-x86_64.img .
~/tutorial$ rmdir infix-x86_64/
~/tutorial$ rm infix-x86_64.tar.gz
After that it is required to create a topology file, i.e.: ~/tutorial/topology.dot.in.
In this case we only need an Infix instance connected to the host system, so the input of topology file is as simple as this:
graph "host-net" {
node [shape=record];
qn_template="infix-x86_64";
host [label="host | { <tap0> tap0 }"];
infix [label="infix | { <eth0> eth0 | <eth1> eth1 }"];
host:"tap0" -- infix:eth0;
}
On your PC, you will get a tap0 interface, connected to the eth0 of Infix (running virtually on the PC).
.----. .42 .1 .--------.
| PC +-----------------------+ Infix |
'----'tap0 10.0.1.0/24 eth0'--------'
NETCONF NETCONF
Client Server
The next step is to generate topology and start qeneth. After that it is only left to set some IP addresses to the TAP interface and to the Infix instance (setting IPv4 address to the Infix device is not mandatory since IPv6 address is assigned to it automatically and can be used for NETCONF communication).
If you decide to work with IPv6 address, you can find it inside the infix device:
root@infix-00-00-00:~$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group iface qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 02:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
inet 10.10.10.2/24 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::ff:fe00:0/64 scope link
valid_lft forever preferred_lft forever
Or you can find it by pinging the remote Infix device behind the tap interface and reading the address from reply by running:
~$ ping -6Lc1 ff02::1%eth0 | awk '/64 bytes from/{sub(/:$/, "", $4); print $4}'
fe80::ff:fe00:0%tap0
On the other hand, if you decide to first set an IPv4 address:
~/tutorial$ qeneth generate && qeneth start
Info: Generating topology
Info: Generating node YAML
gvpr: warning: Using value of uninitialized edge attribute "qn_headport" of "host--infix"
Info: Generating executables
Info: Launching infix
~/tutorial$ ip -br link | grep tap
tap0 DOWN ce:fe:82:f8:cd:19 <BROADCAST,MULTICAST>
~/tutorial$ ip addr add 10.0.1.42/24 dev tap0
~/tutorial$ qeneth console infix
Infix by KernelKit (console)
infix login: admin
Password: admin
Note: use help, show, and setup commands to set up and diagnose the system.
admin@infix:~# ip addr add 10.0.1.1/24 dev eth0
admin@infix:~# ping -c 3 10.0.1.42
PING 10.0.1.1 (10.0.1.1): 56 data bytes
64 bytes from 10.0.1.42: seq=0 ttl=64 time=0.241 ms
64 bytes from 10.0.1.42: seq=1 ttl=64 time=0.474 ms
64 bytes from 10.0.1.42: seq=2 ttl=64 time=0.504 ms
--- 10.0.1.42 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.241/0.406/0.504 ms
admin@infix:~#
telnet> q
Connection closed.
Known issues and workarounds
Errors and warnings after installing netopeer2
After installing netopeer2 you may see some errors as the ones below.
~$ sudo apt install netopeer2
The following packages will be INSTALLED:
netopeer2
0 packages upgraded, 1 newly installed, 0 reinstalled, 0 to remove and 10 not upgraded.
Need to get 212 kB of archives. After unpacking 0 B will be used.
Get: 1 http://ftp.acc.umu.se/ubuntu jammy/universe amd64 netopeer2 amd64 2.0.35-1ubuntu1 [212 kB]
Fetched 212 kB in 0s (1 807 kB/s)
(Reading database ... 671332 files and directories currently installed.)
Preparing to unpack .../netopeer2_2.0.35-1ubuntu1_amd64.deb ...
Unpacking netopeer2 (2.0.35-1ubuntu1) over (2.0.35-1ubuntu1) ...
Setting up netopeer2 (2.0.35-1ubuntu1) ...
sysrepoctl error: Invalid option or missing argument: -a
For more details you may try to increase the verbosity up to "-v3".
dpkg: error processing package netopeer2 (--configure):
installed netopeer2 package post-installation script subprocess returned error exit status 1
Processing triggers for man-db (2.10.2-1) ...
Errors were encountered while processing:
netopeer2
E: Sub-process /usr/bin/dpkg returned an error code (1)
Setting up netopeer2 (2.0.35-1ubuntu1) ...
sysrepoctl error: Invalid option or missing argument: -a
For more details you may try to increase the verbosity up to "-v3".
dpkg: error processing package netopeer2 (--configure):
installed netopeer2 package post-installation script subprocess returned error exit status 1
Errors were encountered while processing:
netopeer2
The netopeer2-cli is usable after this, but the warnings persist in the package system.
To disable warnings from the package manager follow the next workaround:
- Edit the file /var/lib/dpkg/info/netopeer2.postinst
~$ sudo vim /var/lib/dpkg/info/netopeer2.postinst
- Add exit 0 at the very top of the file, so it looks something like this:
#!/bin/sh
# postinst script for netopeer2
#
# see: dh_installdeb(1)
# addiva: /usr/share/netopeer2/setup.sh is not updated in this release
# addiva: so it tries using old syntax for sysrepoctl that fails.
# addiva: With this early `exit 0` we skip the server setup.
exit 0
set -e
- Tell the package manager to try to fix the broken package(s):
~$ sudo apt-get -f install
Note: this only fixes the package manager issue, so the server side of the netopeer2 package is still broken. But it works for our purposes since the server side is on Infix anyway and we only really need the CLI.
Deinstallation Issues With Netopeer2
Besides installation errors, netopeer2 also returns errors when being removed. Therefore, it’s impossible to remove the package by just
sudo apt remove netopeer2
In order to completely uninstall netopeer2 and avoid future warnings, it is needed to forcefully remove it:
~$ sudo mkdir /usr/share/netopeer2
~$ sudo mg /usr/share/netopeer2/remove.sh
~$ sudo chmod +x /usr/share/netopeer2/remove.sh
~$ sudo dpkg --remove --force-all netopeer2
Connection Errors with Netopeer2
After the first-time connection with NETCONF server on Infix is closed (either by disconnecting regularly or forcefully), you might experience issues with connecting again to the same Infix instance.
> disconnect
> connect --host infix.local --login admin
nc ERROR: Starting the SSH session failed (kex error :
no match for method server host key algo:
server [rsa-sha2-512,rsa-sha2-256],
client [ssh-rsa,ssh-ed25519,ecdsa-sha2-nistp521,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256,ssh-dss]).
cmd_connect: Connecting to the infix.local:830 as user "admin" failed.
Currently, the only workaround for this is to remove the Infix instance
from the ~/.ssh/known_hosts
file on the client side.
Qeneth Limitations
The current version of qeneth allows only one topology to be run at a time. If you try to run a second instance it will not be possible to provide the needed ports and start qeneth. In that case you might see something as following:
~$ qeneth status
NODE PID CNSOL MONTR
infix lost 10000 10001
~$ ./infix
qemu-system-x86_64: -monitor telnet::10001,server=on,wait=off
Failed to find an available port: Address already in use
Therefore, it is important to make sure that all previously running topoligies are closed, before starting Infix server on qeneth. Since qeneth runs qemu it is easy to explore if there is a running instance in the background by running
ss -ltp
To return PID numbers of running qemu instances run
pidof qemu-system-x86_64
After that you need to make sure that you’re not running qemu in other programs and to kill only the ones that are associated with qeneth:
kill <pid>
Overview of Netopeer2 CLI commands
~$ netopeer2-cli
> help
Available commands:
auth Manage SSH authentication options
knownhosts Manage the user knownhosts file
cert Manage trusted or your own certificates
crl Manage Certificate Revocation List directory
outputformat Set the output format of all the data
searchpath Set the search path for models
verb Change verbosity
version Print Netopeer2 CLI version
disconnect Disconnect from a NETCONF server
status Display information about the current NETCONF session
connect Connect to a NETCONF server
listen Wait for a Call Home connection from a NETCONF server
quit Quit the program
help Display commands description
editor Set the text editor for working with XML data
cancel-commit ietf-netconf <cancel-commit> operation
commit ietf-netconf <commit> operation
copy-config ietf-netconf <copy-config> operation
delete-config ietf-netconf <delete-config> operation
discard-changes ietf-netconf <discard-changes> operation
edit-config ietf-netconf <edit-config> operation
get ietf-netconf <get> operation
get-config ietf-netconf <get-config> operation
kill-session ietf-netconf <kill-session> operation
lock ietf-netconf <lock> operation
unlock ietf-netconf <unlock> operation
validate ietf-netconf <validate> operation
subscribe notifications <create-subscription> operation
get-schema ietf-netconf-monitoring <get-schema> operation
get-data ietf-netconf-nmda <get-data> operation
edit-data ietf-netconf-nmda <edit-data> operation
establish-sub ietf-subscribed-notifications <establish-subscription> operation
modify-sub ietf-subscribed-notifications <modify-subscription> operation
delete-sub ietf-subscribed-notifications <delete-subscription> operation
kill-sub ietf-subscribed-notifications <kill-subscription> operation
establish-push ietf-subscribed-notifications <establish-subscription> operation with ietf-yang-push augments
modify-push ietf-subscribed-notifications <modify-subscription> operation with ietf-yang-push augments
resync-sub ietf-yang-push <resync-subscription> operation
user-rpc Send your own content in an RPC envelope
timed Time all the commands (that communicate with a server) from issuing an RPC to getting a reply
? Display commands description
exit Quit the program
> connect --host 10.0.1.1--login admin
The authenticity of the host '10.0.1.1' cannot be established.
ssh-rsa key fingerprint is 6f:9a:5c:02:70:88:ec:19:76:1a:89:73:9b:74:83:95:b0:44:7b:00.
Are you sure you want to continue connecting (yes/no)? yes
admin@10.0.1.1 password: admin
> status
Current NETCONF session:
ID : 1
Host : 10.0.1.1
Port : 830
Transport : SSH
Capabilities:
urn:ietf:params:netconf:base:1.0
urn:ietf:params:netconf:base:1.1
urn:ietf:params:netconf:capability:writable-running:1.0
urn:ietf:params:netconf:capability:candidate:1.0
urn:ietf:params:netconf:capability:confirmed-commit:1.1
urn:ietf:params:netconf:capability:rollback-on-error:1.0
urn:ietf:params:netconf:capability:validate:1.1
urn:ietf:params:netconf:capability:startup:1.0
urn:ietf:params:netconf:capability:xpath:1.0
urn:ietf:params:netconf:capability:with-defaults:1.0?basic-mode=explicit&also-supported=report-all,report-all-tagged,trim,explicit
urn:ietf:params:netconf:capability:notification:1.0
urn:ietf:params:netconf:capability:interleave:1.0
urn:ietf:params:netconf:capability:url:1.0?scheme=http,https,ftp,ftps,file
urn:ietf:params:xml:ns:yang:ietf-yang-metadata?module=ietf-yang-metadata&revision=2016-08-05
urn:ietf:params:xml:ns:yang:1?module=yang&revision=2022-06-16
urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2013-07-15
urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2013-07-15
urn:ietf:params:xml:ns:yang:ietf-netconf-acm?module=ietf-netconf-acm&revision=2018-02-14
urn:ietf:params:netconf:capability:yang-library:1.1?revision=2019-01-04&content-id=8
urn:sysrepo:plugind?module=sysrepo-plugind&revision=2022-08-26
urn:ietf:params:xml:ns:netconf:base:1.0?module=ietf-netconf&revision=2013-09-29&features=writable-running,candidate,confirmed-commit,rollback-on-error,validate,startup,url,xpath
urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults?module=ietf-netconf-with-defaults&revision=2011-06-01
urn:ietf:params:xml:ns:yang:ietf-netconf-notifications?module=ietf-netconf-notifications&revision=2012-02-06
urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04
urn:ietf:params:xml:ns:netmod:notification?module=nc-notifications&revision=2008-07-14
urn:ietf:params:xml:ns:netconf:notification:1.0?module=notifications&revision=2008-07-14
urn:ietf:params:xml:ns:yang:ietf-x509-cert-to-name?module=ietf-x509-cert-to-name&revision=2014-12-10
urn:ietf:params:xml:ns:yang:iana-crypt-hash?module=iana-crypt-hash&revision=2014-08-06
urn:ietf:params:xml:ns:yang:iana-if-type?module=iana-if-type&revision=2023-01-26
urn:ietf:params:xml:ns:yang:ietf-system?module=ietf-system&revision=2014-08-06&features=ntp,ntp-udp-port,timezone-name&deviations=kernelkit-infix-deviations
> disconnect