Skip to the content.

YumaPro SDK from YumaWorks

Introduction

YumaWorks is a company that offers a suite of network management and control plane automation tools, with a focus on YANG, NETCONF, and RESTCONF.

Their product YumaPro SDK (Software Development Kit), also referred to as the multi-protocol network management server toolkit or simply the multi-protocol server, is a network automation management platform that provides developers a framework for developing device management interfaces.

YumaPro SDK consists of the following components:

YumaPro SDK Components

YumaPro SDK is available in binary and in source code.

YumaPro SDK Basic offers a subset of the YumaPro SDK features and can be used for free for internal use subject to restrictions (see the license document for details):

YumaPro SDK Basic Components

YumaPro SDK Feature Comparison

In this tutorial we will be using the basic version.

Documentation

The YumaPro SDK documentation is online here.

Installation

The installation steps described below are based on the YumaWorks installation guide but deviate in some small details.

Install the dependencies

Install the dependencies:

sudo apt-get update
sudo apt-get install -y libxml2-dev
sudo apt-get install -y openssh-server
sudo apt-get install -y openssl
sudo apt-get install -y libssl-dev
sudo apt-get install -y libcurl4-gnutls-dev
sudo apt-get install -y libfcgi-dev
sudo apt-get install -y libssh2-1-dev
sudo apt-get install -y libncurses5-dev
sudo apt-get install -y zlib1g-dev

Download YumaPro SDK

Download the YumaPro SDK Basic software and documentation from the download page It is available for several Linux distributions; we use Ubuntu 22.04 LTS.

As of 28 June 2023, this downloads file yumapro-sdk-basic-21.10-12.u2204.amd64.deb.

Install YumaPro SDK

Install the YumaPro SDK Basic software package:

sudo dpkg -i yumapro-sdk-basic-21.10-12.u2204.amd64.deb

Verify that YumaPro SDK has been installed:

$ /usr/sbin/netconfd-pro --version

Starting netconfd-pro...
Copyright (c) 2008-2012, Andy Bierman, All Rights Reserved.
Copyright (c) 2012-2022, YumaWorks, Inc., All Rights Reserved.

netconfd-pro version 21.10-12-1fcb

Configure SSH

Edit sshd_config, for example using vi:

sudo vi /etc/ssh/sshd_config

The installation guide instructs you to add the following lines:

Port 22
Port 830
Subsystem netconf /usr/sbin/netconf-subsystem-pro

Using the following Subsystem configuration instead will allow you to view the XML messages that are exchanged over the SSH system (this cannot easily be done with normal packet capture tools such as Wireshark because they cannot easily decode the encrypted SSH session):

Subsystem netconf "/bin/sh -c 'tee /tmp/netconf-rx.txt | /usr/sbin/netconf-subsystem-pro | tee /tmp/netconf-tx.txt'"

The NETCONF server will write all received XML messages to file /tmp/netconf-rx.txt and all sent XML messages to file /tmp/netconf-tx.txt.

The multitail program is handy to monitor both files at the same time.

Install multitail:

sudo apt-get install -y multitail

Monitor both files at the same time using different colors:

multitail -ci magenta /tmp/netconf-rx.txt -ci green /tmp/netconf-tx.txt

Press F1 to get help on the interactive keys that multitail supports. Some handy keys are B to scroll back and N to clear the window.

Configure SSH

TODO: Are we actually using a key? It seems that we are using username/password below.

Use ssh-keygen to generate a public-private key pair (accept defaults for all prompts):

$ ssh-keygen -t ed25519
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/ubuntu/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/ubuntu/.ssh/id_ed25519
Your public key has been saved in /home/ubuntu/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:e59bSBR6oP/pO+NjJwauL9S1cXQ+8pLa6vPLvLGsoD8 ubuntu@ip-172-31-28-171
The key's randomart image is:
+--[ED25519 256]--+
|          . .    |
|         . o .. .|
|        . . o. o |
|         . oo....|
|        S....++ .|
|        ..oo.= . |
|       ..o..*.o  |
|        oEo=@++  |
|       .o=+B%^o  |
+----[SHA256]-----+

Restart SSH to make the keys take effect:

sudo service ssh restart

Set a password

For this demo, we will be using username and password authentication.

If you are using an AWS Ubuntu instance, user ubuntu does not have a password by default. Set a password as follows:

$ sudo su -
$ passwd ubuntu
New password: topsecret
Retype new password: topsecret
passwd: password updated successfully

Start the NETCONF server

Start the netconfd-pro server (with maximum debug logging; use debug instead of debug4 to reduce the verbosity):

$ netconfd-pro --log-level=debug4 --access-control=off

Starting netconfd-pro...
Copyright (c) 2008-2012, Andy Bierman, All Rights Reserved.
Copyright (c) 2012-2022, YumaWorks, Inc., All Rights Reserved.

...lots of output...

netconfd-pro init OK, ready for sessions

Running netconfd-pro server (21.10-12-1fcb)

Binding to AF_LOCAL socket /tmp/ncxserver.sock

agt_ncxserver: listen ncxsock fd: 3

Start the command line interface (CLI) client

In a separate Terminal window, start the yangcli-pro client:

$ yangcli-pro

  yangcli-pro version 21.10-12
  libssh2 version 1.8.0

  Copyright (c) 2008-2012, Andy Bierman, All Rights Reserved.
  Copyright (c) 2012-2022, YumaWorks, Inc., All Rights Reserved.

...more output...

parallels@localhost>

Connect the CLI client to the NETCONF server

Enter the following command in the CLI to connect to the server (use your Linux username and password, and put the password in quotes if it contains a question mark):

parallels@localhost> connect server=localhost user=<username> password=<password></b>

NETCONF 1.1 session established for parallels on localhost

Client Session Id: 1
Server Session Id: 4

...more output...

Protocol version set to: RFC 6241 (base:1.1)
Default target set to: 
Save operation mapped to: commit
Default with-defaults behavior: explicit
Additional with-defaults behavior: trim,report-all,report-all-tagged
YANG library set to: 1.0 (RFC 7895)
module-set-id: 4269
</pre>

## View the NETCONF messages

In the `multitail` window that we had started in an earlier step, we can see the NETCONF messages
that are being exchanged between the NETCONF client and server.

The client sends a `hello`:

```xml

  
    urn:ietf:params:netconf:base:1.0
    urn:ietf:params:netconf:base:1.1
  

```

Note: throughout these examples, we have used the `xmllint` program to pretty-print the XML in
the NETCONF messages. One side-effect of this is that the XML elements and attributes may appear
in a different order.

The server responds with a `hello`:

```xml

  
    urn:ietf:params:netconf:base:1.0
    urn:ietf:params:netconf:base:1.1
    urn:ietf:params:netconf:capability:candidate:1.0
    urn:ietf:params:netconf:capability:confirmed-commit: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.0
    urn:ietf:params:netconf:capability:validate:1.1
    urn:ietf:params:netconf:capability:url:1.0?scheme=file
    urn:ietf:params:netconf:capability:xpath:1.0
    urn:ietf:params:netconf:capability:notification:1.0
    urn:ietf:params:netconf:capability:interleave:1.0
    urn:ietf:params:netconf:capability:partial-lock:1.0
    urn:ietf:params:netconf:capability:with-defaults:1.0?basic-mode=explicit&also-supported=trim,report-all,report-all-tagged
    urn:yumaworks:params:xml:ns:netconf:config-id?id=13
    urn:ietf:params:xml:ns:netconf:base:1.0?module=ietf-netconf&revision=2011-06-01&features=candidate,confirmed-commit,rollback-on-error,validate,url,xpath
    urn:ietf:params:xml:ns:yang:iana-crypt-hash?module=iana-crypt-hash&revision=2014-08-06&features=crypt-hash-md5,crypt-hash-sha-256,crypt-hash-sha-512
    urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2013-07-15
    urn:ietf:params:xml:ns:yang:ietf-netconf-acm?module=ietf-netconf-acm&revision=2018-02-14
    ...
    http://yumaworks.com/ns/yumaworks-types?module=yumaworks-types&revision=2021-05-15
    urn:ietf:params:netconf:capability:yang-library:1.0?revision=2016-06-21&module-set-id=4269
  
  5

```

The client issues a `get` filtering on subtree `ietf-yang-library`
to retrieve the details of the modules that the server supports
(see [RFC8525](https://datatracker.ietf.org/doc/rfc8525/) for details)
(output truncated):

```xml

  
    
      
    
  

```

The server responds with the requested information (output truncated):

```xml

  
    
      4269
      
        ietf-netconf
        2011-06-01
        urn:ietf:params:xml:ns:netconf:base:1.0
        candidate
        confirmed-commit
        rollback-on-error
        validate
        url
        xpath
        implement
      
      
        iana-crypt-hash
        2014-08-06
        http://localhost/restconf/yang/iana-crypt-hash/2014-08-06
        urn:ietf:params:xml:ns:yang:iana-crypt-hash
        crypt-hash-md5
        crypt-hash-sha-256
        crypt-hash-sha-512
        implement
      
      
        ietf-inet-types
        2013-07-15
        http://localhost/restconf/yang/ietf-inet-types/2013-07-15
        urn:ietf:params:xml:ns:yang:ietf-inet-types
        import
      
      
        ietf-netconf-acm
        2018-02-14
        http://localhost/restconf/yang/ietf-netconf-acm/2018-02-14
        urn:ietf:params:xml:ns:yang:ietf-netconf-acm
        implement
      
      ...
      
        yumaworks-types
        2021-05-15
        http://localhost/restconf/yang/yumaworks-types/2021-05-15
        http://yumaworks.com/ns/yumaworks-types
        import
      
    
  

```

## Issue a command in the CLI client

In the CLI client, the `show modules` command can be used to view the YANG modules that the
server reports:

parallels@localhost> show modules

  ianach:iana-crypt-hash@2014-08-06
  inet:ietf-inet-types@2013-07-15
  nacm:ietf-netconf-acm@2018-02-14
  ncm:ietf-netconf-monitoring@2010-10-04
  ncn:ietf-netconf-notifications@2012-02-06
  pl:ietf-netconf-partial-lock@2009-10-19
  ncwd:ietf-netconf-with-defaults@2011-06-01
  rc:ietf-restconf@2017-01-26
  rcmon:ietf-restconf-monitoring@2017-01-26
  yanglib:ietf-yang-library@2016-06-21
  ypatch:ietf-yang-patch@2017-02-22
  sx:ietf-yang-structure-ext@2020-06-17
  yang:ietf-yang-types@2013-07-15
  manageEvent:nc-notifications@2008-07-14
  ncEvent:notifications@2013-03-15
  yd:yang-data-ext@2017-07-03
  appcmn:yuma-app-common@2017-07-25
  ncx:yuma-ncx@2015-10-16
  nc:yuma-netconf@2015-04-30
  timefilter:yuma-time-filter@2012-11-15
  yt:yuma-types@2019-11-29
  ywapp:yumaworks-app-common@2021-08-24
  ef:yumaworks-event-filter@2014-02-09
  ywes:yumaworks-event-stream@2021-05-15
  ywx:yumaworks-extensions@2021-12-14
  ybulk:yumaworks-getbulk@2021-08-07
  yid:yumaworks-ids@2014-07-12
  yrc:yumaworks-restconf@2017-07-03
  yss:yumaworks-support-save@2017-07-27
  ysys:yumaworks-system@2022-03-08
  ytemp:yumaworks-templates@2017-02-20
  ytm:yumaworks-term-msg@2019-05-05
  ywt:yumaworks-types@2021-05-15
## Retrieve the (empty) configuration In the CLI client, issue a `get-config` command to retrieve the running configuration:
parallels@localhost> get-config source=running

RPC Data Reply 10 for session 4 [default]:

rpc-reply {
  data {
  }
}
In this example, there is no configuration yet (we will add some configuration below). The client sends a `get-config`: ```xml </source> ``` The server responds with the requested configuration: ```xml ``` ## Retrieve a subtree of the operational state In the CLI client, issue an `sget` command to retrieve operational state for the `/netconf-state/sessions` subtree of the operational state tree (use `/` if you want to see the whole tree):
parallels@localhost> sget /netconf-state/sessions

Filling container /netconf-state/sessions:
RPC Data Reply 2 for session 4 [default]:

rpc-reply {
  data {
    netconf-state {
      sessions {
        session  4 {
          session-id 4
          transport ncm:netconf-ssh
          username parallels
          source-host 127.0.0.1
          login-time 2022-09-08T14:09:15Z
          in-rpcs 1
          in-bad-rpcs 0
          out-rpc-errors 0
          out-notifications 0
        }
      }
    }
  }
}
The client sends a `get` with the filter for the subtree: ```xml ``` The server responds with the requested operational state: ```xml 5 ncm:netconf-ssh parallels 127.0.0.1 2022-09-09T15:07:13Z 2 0 0 0 ``` ## Retrieve the YANG schema for a module In the CLI client, issue the `get-schema` command to retrieve the YANG schema for a specific module from the server:
parallels@localhost> get-schema identifier=ietf-netconf-notifications

RPC Data Reply 10 for session 5 [default]:

rpc-reply {
  data '
module ietf-netconf-notifications {

   namespace
     "urn:ietf:params:xml:ns:yang:ietf-netconf-notifications";

   prefix ncn;

   import ietf-inet-types { prefix inet; }
   import ietf-netconf { prefix nc; }

   organization
     "IETF NETCONF (Network Configuration Protocol) Working Group";

   contact
     "WG Web:   <http://tools.ietf.org/wg/netconf/>
      WG List:  <mailto:netconf@ietf.org>

      WG Chair: Bert Wijnen
                <mailto:bertietf@bwijnen.net>

      WG Chair: Mehmet Ersue
                <mailto:mehmet.ersue@nsn.com>

      Editor:   Andy Bierman
                <mailto:andy@netconfcentral.org>";

   description
     "This module defines a YANG data model for use with the
      NETCONF protocol that allows the NETCONF client to
      receive common NETCONF base event notifications.

      Copyright (c) 2012 IETF Trust and the persons identified as
      the document authors.  All rights reserved.

      Redistribution and use in source and binary forms, with or
      without modification, is permitted pursuant to, and subject
      to the license terms contained in, the Simplified BSD License
      set forth in Section 4.c of the IETF Trust's Legal Provisions
      Relating to IETF Documents
      (http://trustee.ietf.org/license-info).

      This version of this YANG module is part of RFC 6470; see
      the RFC itself for full legal notices.";

   revision "2012-02-06" {
     description
       "Initial version. Errata 3957 added.";
     reference
       "RFC 6470: NETCONF Base Notifications";
   }

  grouping common-session-parms {
    description
      "Common session parameters to identify a
       management session.";

    leaf username {
      type string;
      mandatory true;
      description
        "Name of the user for the session.";
    }

    leaf session-id {
      type nc:session-id-or-zero-type;
      mandatory true;
      description
        "Identifier of the session.
         A NETCONF session MUST be identified by a non-zero value.
         A non-NETCONF session MAY be identified by the value zero.";
    }

    ...

    leaf timeout {
      when
        "../confirm-event = 'start' or ../confirm-event = 'extend'";
      type uint32;
      units "seconds";
      description
        "The configured timeout value if the event type
         is 'start' or 'extend'.  This value represents
         the approximate number of seconds from the event
         time when the 'timeout' event might occur.";
    }
  } // notification netconf-confirmed-commit

}
'
}
The client sends a `get-schema` for the module: ```xml ietf-netconf-notifications ``` The server responds with the requested schema: ```xml module ietf-netconf-notifications { namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-notifications"; prefix ncn; import ietf-inet-types { prefix inet; } import ietf-netconf { prefix nc; } organization "IETF NETCONF (Network Configuration Protocol) Working Group"; contact "WG Web: <http://tools.ietf.org/wg/netconf/> WG List: <mailto:netconf@ietf.org> WG Chair: Bert Wijnen <mailto:bertietf@bwijnen.net> WG Chair: Mehmet Ersue <mailto:mehmet.ersue@nsn.com> Editor: Andy Bierman <mailto:andy@netconfcentral.org>"; description "This module defines a YANG data model for use with the NETCONF protocol that allows the NETCONF client to receive common NETCONF base event notifications. Copyright (c) 2012 IETF Trust and the persons identified as the document authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, is permitted pursuant to, and subject to the license terms contained in, the Simplified BSD License set forth in Section 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info). This version of this YANG module is part of RFC 6470; see the RFC itself for full legal notices."; revision "2012-02-06" { description "Initial version. Errata 3957 added."; reference "RFC 6470: NETCONF Base Notifications"; } grouping common-session-parms { description "Common session parameters to identify a management session."; leaf username { type string; mandatory true; description "Name of the user for the session."; } leaf session-id { type nc:session-id-or-zero-type; mandatory true; description "Identifier of the session. A NETCONF session MUST be identified by a non-zero value. A non-NETCONF session MAY be identified by the value zero."; } ... leaf timeout { when "../confirm-event = 'start' or ../confirm-event = 'extend'"; type uint32; units "seconds"; description "The configured timeout value if the event type is 'start' or 'extend'. This value represents the approximate number of seconds from the event time when the 'timeout' event might occur."; } } // notification netconf-confirmed-commit } ``` ## Exit from the CLI client Exit from the CLI client:
parallels@localhost> quit
## Adding a plugin for your own data model We will now add a plugin for our example YANG data model: [interfaces.yang](/yang-tutorial/interfaces.yang), following the instructions in the [YumaPro Developer Manual](https://www.yumaworks.com/pub/latest/dev/yumapro-dev-manual.html) . If you haven't already done so, clone the `yang-tutorial` repo:
$ cd ~
$ git clone https://github.com/brunorijsman/yang-tutorial.git
By default YumaPro SDK expects the YANG data models to be installed in `~/modules`. Copy the example YANG data model [interfaces.yang](/yang-tutorial/interfaces.yang) into `~/modules`:
$ mkdir ~/modules
$ cd ~/modules
$ cp ~/yang-tutorial/interfaces.yang .
YumaPro SDK support a few different flavors of plugins. We will use the SIL flavor, which is dynamically linked into the NETCONF server and which uses synchronous callbacks. We will put our plugin code in the `~/plugins` directory:
$ mkdir ~/plugins
$ cd ~/plugins
Run the YumaWorks `make_sil_dir_pro` script to generate the C stub code from the YANG data model:
$ make_sil_dir_pro interfaces --sil-get2 --sil-edit2
If all goes well, this generates the following directories and files:
$ tree interfaces
interfaces/
├── bin
├── lib
├── Makefile
└── src
    ├── Makefile
    ├── u_interfaces.c
    ├── u_interfaces.h
    ├── y_interfaces.c
    └── y_interfaces.h
The files starting with `u_` (for user) can be edited to customize the behavior of the plugin. We will edit the stub C code that YumaPro SDK generated to provide values for the operational state attributes. There are many other callbacks that can be edited in the stub code, for example to do something when an interface is added or removed, when an IPv4 address is set, changed, or removed, etc. For a complete list of all the callbacks that can be customized see the [YumaPro Developers Manual](https://www.yumaworks.com/pub/latest/dev/yumapro-dev-manual.html#) . For now, we will keep it as simple as possible and only implement the callback for providing packet counter values. Edit the generated stub file `u_interfaces.c`:
$ vi ~/plugins/interfaces/src/u_interfaces.c
Edit function `u_intf_sent_packets_get`: ```c status_t u_intf_sent_packets_get ( getcb_get2_t *get2cb, const xmlChar *k_intf_name) { ... } ``` Change the following lines: ```c /* check if the requested node exists; determined by the * SIL or SIL-SA callback based on instances in the system * CHANGE node_exists TO TRUE WHEN VALUE CODE FILLED IN */ boolean node_exists = FALSE; if (!node_exists) { return ERR_NCX_NO_INSTANCE; } obj_template_t *obj = GETCB_GET2_OBJ(get2cb); status_t res = NO_ERR; /* get the real value from the system somehow */ uint64 v_sent_packets = 0; ``` Into the following lines (to keep things as simple as possible, we return a random value for the number of sent packets counter): ```c /* check if the requested node exists; determined by the * SIL or SIL-SA callback based on instances in the system * CHANGE node_exists TO TRUE WHEN VALUE CODE FILLED IN */ boolean node_exists = TRUE; // <<< Changed this line if (!node_exists) { return ERR_NCX_NO_INSTANCE; } obj_template_t *obj = GETCB_GET2_OBJ(get2cb); status_t res = NO_ERR; /* get the real value from the system somehow */ uint64 v_sent_packets = rand() % 1000; // <<< Changed this line ``` Make a similar change in the function `u_intf_received_packets_get`: ```c /* check if the requested node exists; determined by the * SIL or SIL-SA callback based on instances in the system * CHANGE node_exists TO TRUE WHEN VALUE CODE FILLED IN */ boolean node_exists = TRUE; if (!node_exists) { return ERR_NCX_NO_INSTANCE; } obj_template_t *obj = GETCB_GET2_OBJ(get2cb); status_t res = NO_ERR; /* get the real value from the system somehow */ uint64 v_received_packets = rand() % 1000; ``` Save the changes. Build and install the plugin (the `make` step generates some warnings about unused parameters which you can ignore for now):
$ cd interfaces
$ make
$ sudo make install
Go back to the CLI client which we started earlier in this tutorial and issue the following command to instruct the NETCONF server to load the new YANG module:
parallels@localhost> load interfaces

RPC Data Reply 5 for session 4 [default]:

rpc-reply {
  mod-revision 2022-03-12
}
We separate need to load the YANG module into the CLI client:
parallels@localhost> mgrload interfaces

Load module 'interfaces' OK
Note: instead of issuing CLI commands to load the YANG module into the server and the client, we can also start the server with a `--module` command line option:
$ netconfd-pro --log-level=debug4 --access-control=off --module=interfaces
Still in the CLI client, configure a couple of interfaces:
parallels@localhost> config term
parallels@localhost# interfaces
parallels@localhost(interfaces)# interface eth0
parallels@localhost(interface)# ipv4-address 1.1.1.1
parallels@localhost(interface)# exit
parallels@localhost(interfaces)# interface eth1
parallels@localhost(interface)# ipv4-address 2.2.2.2
parallels@localhost(interface)# exit
parallels@localhost(interfaces)# exit
parallels@localhost# exit
parallels@localhost> commit
RPC OK Reply 7 for session 4 [default]:
Get the configuration to double check:
parallels@localhost> sget-config source=running /interfaces

Filling container /interfaces:
RPC Data Reply 3 for session 5 [default]:

rpc-reply {
  data {
    interfaces {
      interface  eth0 {
        name eth0
        ipv4-address 1.1.1.1
      }
      interface  eth1 {
        name eth1
        ipv4-address 2.2.2.2
      }
    }
  }
}
Get the operational state for the interfaces; we get random values for the packet counters:
parallels@localhost> sget /interfaces

Filling container /interfaces:
RPC Data Reply 29 for session 3 [default]:

rpc-reply {
  data {
    interfaces {
      interface  eth0 {
        name eth0
        ipv4-address 1.1.1.1
        sent-packets 383
        received-packets 886
      }
      interface  eth1 {
        name eth1
        ipv4-address 2.2.2.2
        sent-packets 777
        received-packets 915
      }
    }
  }
}