YANG Push

The YANG Push feature allows data to be sent to a client automatically, using NETCONF notifications.

A separate mechanism for managing dynamic subscriptions is used by YANG Push, which is intended to replace the existing <create-subscription> RPC operation defined in RFC 5277. This new set of RPC operations (defined in RFC 8639) is used for current event stream subscriptions. It is also used for new datastore subscriptions (defined in RFC 8641).

../_images/yang-push-components.png

The YANG Push support will be provided in multiple phases, and is almost complete in the 25.10 release train.

  1. Dynamic subscriptions over NETCONF in XML (23.10)

    1. Periodic subscriptions

    2. Conventional datastore On-Change subscriptions

    3. Simulated On-Change subscriptions for the Operational Datastore

    4. On-Change subscriptions for the Operational Datastore from subsystem events (TBD)

    5. Proprietary support for JSON and CBOR encoding with NETCONF (25.10)

  2. Dynamic subscriptions over RESTCONF in XML or JSON (25.10)

  3. Configured subscriptions for Binary Push support (25.10)

    1. gRPC for native protobuf files (TBD)

    2. gNMI ONCHANGE subscriptions (24.10)

    3. RFC 9254 CBOR+SID encoding over UDP or TCP (25.10)

    4. UDP-Notif Protocol support (25.10)

CLI Parameters for YANG Push

Parameter

Default

Description

--bundle=yang-push

not loaded

The bundle parameter is used to enable or disable the entire YANG Push feature

--max-chunk-size

1400

Control size of message chunks sent to the receiver

--push-max-operational

4

Specifies the maximum number of on-change push subscriptions that can be in use at once for the <operational> datastore

--push-max-periodic

16

Specifies the maximum number of periodic push subscriptions that can be in use at once

--push-min-dampening

100

Specifies the minimum value for the 'dampening-period' parameter that will be accepted for an on-change push subscription. (centiseconds)

--push-min-period

100

Specifies the minimum value for the 'period' parameter that will be accepted for a periodic push subscription. (centiseconds)

--push-simop-enabled

true

Specifies if the simulated on-change push subscriptions should be enabled for the <operational> datastore.

--push-simop-patch-update

true

Specifies the notification message that should be used for a simulated on-change push subscription.

--push-simop-period

500

Specifies the value for the 'period' parameter that will be used for simulated operational on-change push subscription.

--with-notifications

true

Must be 'true' to use YANG Push

--with-yang-cbor

false

Enable or disable the Binary Push modules and features.

--with-yang-push2

true

Enable or disable the YANG Push 2 modules and features.

--yang-sid-mode

sid-file

Select the YANG/CBOR SID assignment mode

YANG Push 2

Warning

  • Many specifications implemented in this feature are based on Internet Drafts that are not stable and subject to change at any time.

  • Backward compatibility with Internet Drafts is not supported

  • Use with caution until the RFCs are published

A large set of new standards are being developed for YANG Push. The 25.10 release train implements many of these Internet Drafts. It is included in the Advanced feature set in the 'yumapro-sdk' and 'yumapro-pthreads' packages. The WITH_YANG_PUSH and WITH_YANG_PUSH2 compiler flags are required to build this feature from source code.

The following yangcli-pro 'show session' summary shows the related YANG modules:

notifications@2013-03-15
yumaworks-yangpush-dev@2019-11-22
ietf-distributed-notif@2026-04-13
ietf-notification-capabilities@2022-02-17
ietf-sid-file@2024-07-31
ietf-subscribed-notif-receivers@2024-02-01
ietf-subscribed-notifications@2019-09-09
  Features:
     configured
     dscp
     encode-json
     encode-xml
     replay
     subtree
     xpath
ietf-system-capabilities@2022-02-17
ietf-udp-client@2025-06-04 (I)
ietf-udp-notif-transport@2025-06-04
  Features:
     encode-cbor
     segmentation
ietf-yang-library@2019-01-04
ietf-yang-patch@2017-02-22
ietf-yang-push@2019-09-09
  Features:
     on-change
  Deviations:
     yumaworks-yangpush-dev
ietf-yang-push-revision@2025-12-07
  Features:
     yang-push-revision-supported
ietf-yang-revisions@2024-06-04 (I)
ietf-yang-semver@2025-01-21 (I)
yumaworks-yang-cbor@2022-05-21

UDP-Notif Protocol

Document: UDP-based Transport for Configured Subscriptions

YANG Module: ietf-udp-notif-transport.yang

This is the only protocol supported for configured subscriptions at this time.

Warning

This protocol is not secure. Data is sent unencrypted using the UDP protocol.

The following features are supported:

  • encode-cbor : RFC 9254 YANG to CBOR encoding is fully supported

  • segmentation : The Segmentation feature is fully supported and should be used to avoid dropped events.

The --max-chunk-size CLI parameter or 'max-segment-size' leaf controls the payload size used when sending messages to a UDP-Notif Collector.

  • If the 'enable-segmentation' leaf is 'true' or not present then the max-segment-size is used for each segment (except perhaps the last segment).

  • If the 'enable-segmentation' leaf is 'false' the max-segment-size is used for the one segment allowed per message.

    • If the message would be too big then the 'excluded-events' counter is incremented for the subscription and receiver.

  • All standard media types are supported (XML, JSON, CBOR)

Distributed Notifications

Document: Subscription to Distributed Notifications

YANG Module: ietf-distributed-notif.yang

This module adds a Publisher ID to subscriptions to identity the source of the event generation. This allows multiple publishers to use the same source IP address.

There is no requirement that all publishers have a unique identifier.

Note

  • The publisher ID for the main server is set to '1'

  • A future release will support additional publisher IDs when subsystems can generate Push updates

Versioning Support in Subscriptions

Document: Support of Versioning in YANG Notifications Subscription

YANG Module: ietf-yang-push-revision.yang

This module adds the ability to check the modules and module revisions that are being used by the server. The client can list module names, revision dates, and/or revision labels that must be supported by the server. If the module or specified revision is not supported then the subscription is rejected.

Usage

  • The 'module-version-subs' list parameter can be used for event stream and datastore subscriptions

  • If a list entry contains only a 'name' key leaf then any revision of that module is required for the subscription to be valid

    <module-version-subs
     xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push-revision">
     <name>ietf-netconf-acm</name>
    </module-version-subs>
    
  • If a list entry contains a key leaf and a 'revision' leaf, then that revision date must match the revision date of the specified module for the subscription to be valid

    <module-version-subs
     xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push-revision">
     <name>ietf-netconf-acm</name>
     <revision>2018-02-14</revision>
    </module-version-subs>
    
  • If a list entry contains a key leaf and a 'revision-version' option leaf, then that revision or a version of the YANG module must be less than or equal to the revision or version label of the specified module for the subscription to be valid. The module must have an IETF Semver extension (ysv:version) defined for a reivsion label to be found.

    <module-version-subs
     xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push-revision">
     <name>ietf-netconf-acm</name>
     <version>1.0.3</version>
    </module-version-subs>
    

Error Examples

If an unknown module name such as 'bad'module' is specified then an error is returned.

Example Request:

 <rpc message-id="4"
  xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <establish-subscription xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
   <encoding
    xmlns:unt="urn:ietf:params:xml:ns:yang:ietf-udp-notif-transport">unt:encode-cbor</encoding>
   <datastore
     xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push"
     xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">ds:operational</datastore>
   <datastore-xpath-filter
     xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">/nacm</datastore-xpath-filter>
   <module-version-subs xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push-revision">
    <name>ietf-netconf-acm</name>
   </module-version-subs>
   <module-version-subs xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push-revision">
    <name>bad-module</name>
   </module-version-subs>
   <periodic xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
    <period>2000</period>
   </periodic>
  </establish-subscription>
 </rpc>

Example Error Reply:

  • The 'operation-failed' error-tag is returned

  • The 'module-not-found' error message is returned

  • The 'error-path' references the bad 'module-version-subs' entry

<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply message-id="4" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
 xmlns:sn="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications"
 xmlns:ypr="urn:ietf:params:xml:ns:yang:ietf-yang-push-revision"
 xmlns:ncx="http://netconfcentral.org/ns/yuma-ncx"
 xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
 <rpc-error>
  <error-type>protocol</error-type>
  <error-tag>operation-failed</error-tag>
  <error-severity>error</error-severity>
  <error-app-tag>data-incomplete</error-app-tag>
  <error-path>/nc:rpc/sn:establish-subscription/ypr:module-version-subs[ypr:name='bad-module']</error-path>
  <error-message xml:lang="en">module not found</error-message>
  <error-info>
   <error-number>236</error-number>
  </error-info>
 </rpc-error>
</rpc-reply>

RFCs and Features Supported

There are multiple ways to do the same thing in YANG Push, so not all of it is implemented at once.

  • The "dynamic subscriptions" functionality is implemented in phase 1.

  • The "configured subscriptions" functionality is now supported, starting in the 25.10 release train. The UDP-Notif Protocol is the only protocol that uses configured subscriptions and receivers.

  • RFC 8639: Subscription to YANG Notifications

  • RFC 8640: Dynamic Subscription to YANG Events and Datastores over NETCONF

  • RFC 8641: Subscription to YANG Notifications for Datastore Updates

    • YANG Module: ietf-yang-push@2019-09-09.yang

    • Supported Features

      • on-change

      • anchor-time parameter is now supported starting in 25.10-1

    • Supported Features in YANG Push 2

      • /subscriptions subtree can be configured with event stream and datastore subscriptions

      • /subscriptions/receiver-instances subtree can be configured with UDP-Notif Collectors

    • Unsupported Features

      • /subscriptions data node is not available for NMDA access to <operational> values of dynamic subscriptions

  • RFC 8650: Dynamic Subscription to YANG Events and Datastores over RESTCONF

YANG Push Tree Diagram

The current set of YANG Push related definitions is shown below.

module: ietf-subscribed-notifications
  +--ro streams
  |  +--ro stream* [name]
  |     +--ro name                        string
  |     +--ro description?                string
  |     +--ro replay-support?             empty {replay}?
  |     +--ro replay-log-creation-time    yang:date-and-time {replay}?
  |     +--ro replay-log-aged-time?       yang:date-and-time {replay}?
  +--rw filters
  |  +--rw stream-filter* [name]
  |  |  +--rw name                           string
  |  |  +--rw (filter-spec)?
  |  |     +--:(stream-subtree-filter)
  |  |     |  +--rw stream-subtree-filter?   <anydata> {subtree}?
  |  |     +--:(stream-xpath-filter)
  |  |        +--rw stream-xpath-filter?     yang:xpath1.0 {xpath}?
  |  +--rw yp:selection-filter* [filter-id]
  |     +--rw yp:filter-id                         string
  |     +--rw (yp:filter-spec)?
  |        +--:(yp:datastore-subtree-filter)
  |        |  +--rw yp:datastore-subtree-filter?   <anydata> {sn:subtree}?
  |        +--:(yp:datastore-xpath-filter)
  |           +--rw yp:datastore-xpath-filter?     yang:xpath1.0 {sn:xpath}?
  +--rw subscriptions
     +--rw subscription* [id]
     |  +--rw id                                               subscription-id
     |  +--rw (target)
     |  |  +--:(stream)
     |  |  |  +--rw (stream-filter)?
     |  |  |  |  +--:(by-reference)
     |  |  |  |  |  +--rw stream-filter-name                   stream-filter-ref
     |  |  |  |  +--:(within-subscription)
     |  |  |  |     +--rw (filter-spec)?
     |  |  |  |        +--:(stream-subtree-filter)
     |  |  |  |        |  +--rw stream-subtree-filter?         <anydata> {subtree}?
     |  |  |  |        +--:(stream-xpath-filter)
     |  |  |  |           +--rw stream-xpath-filter?           yang:xpath1.0 {xpath}?
     |  |  |  +--rw stream                                     stream-ref
     |  |  |  +--ro replay-start-time?                         yang:date-and-time {replay}?
     |  |  |  +--rw configured-replay?                         empty {configured,replay}?
     |  |  +--:(yp:datastore)
     |  |     +--rw yp:datastore                               identityref
     |  |     +--rw (yp:selection-filter)?
     |  |        +--:(yp:by-reference)
     |  |        |  +--rw yp:selection-filter-ref              selection-filter-ref
     |  |        +--:(yp:within-subscription)
     |  |           +--rw (yp:filter-spec)?
     |  |              +--:(yp:datastore-subtree-filter)
     |  |              |  +--rw yp:datastore-subtree-filter?   <anydata> {sn:subtree}?
     |  |              +--:(yp:datastore-xpath-filter)
     |  |                 +--rw yp:datastore-xpath-filter?     yang:xpath1.0 {sn:xpath}?
     |  +--rw stop-time?                                       yang:date-and-time
     |  +--rw dscp?                                            inet:dscp {dscp}?
     |  +--rw weighting?                                       uint8 {qos}?
     |  +--rw dependency?                                      subscription-id {qos}?
     |  +--rw transport?                                       transport {configured}?
     |  +--rw encoding?                                        encoding
     |  +--rw purpose?                                         string {configured}?
     |  +--rw (notification-message-origin)? {configured}?
     |  |  +--:(interface-originated)
     |  |  |  +--rw source-interface?                          if:interface-ref {interface-designation}?
     |  |  +--:(address-originated)
     |  |     +--rw source-vrf?                                -> /ni:network-instances/network-instance/name {supports-vrf}?
     |  |     +--rw source-address?                            inet:ip-address-no-zone
     |  +--ro configured-subscription-state?                   enumeration {configured}?
     |  +--rw receivers
     |  |  +--rw receiver* [name]
     |  |     +--rw name                         string
     |  |     +--ro sent-event-records?          yang:zero-based-counter64
     |  |     +--ro excluded-event-records?      yang:zero-based-counter64
     |  |     +--ro state                        enumeration
     |  |     +---x reset {configured}?
     |  |     |  +--ro output
     |  |     |     +--ro time    yang:date-and-time
     |  |     +--rw snr:receiver-instance-ref?   -> /sn:subscriptions/snr:receiver-instances/receiver-instance/name
     |  +--rw (yp:update-trigger)?
     |  |  +--:(yp:periodic)
     |  |  |  +--rw yp:periodic!
     |  |  |     +--rw yp:period         centiseconds
     |  |  |     +--rw yp:anchor-time?   yang:date-and-time
     |  |  +--:(yp:on-change) {on-change}?
     |  |     +--rw yp:on-change!
     |  |        +--rw yp:dampening-period?   centiseconds
     |  |        +--rw yp:sync-on-start?      boolean
     |  |        +--rw yp:excluded-change*    change-type
     |  +--ro dn:message-publisher-id*                         uint32
     |  +--rw ypr:module-version-config* [module-name] {yang-push-revision-supported}?
     |     +--rw ypr:module-name       yang:yang-identifier
     |     +--rw ypr:revision?         rev:revision-date
     |     +--rw ypr:version?   ysver:version
     +--rw snr:receiver-instances
        +--rw snr:receiver-instance* [name]
           +--rw snr:name                        string
           +--rw (snr:transport-type)
              +--:(unt:udp-notif)
                 +--rw unt:udp-notif-receiver
                    +--rw unt:remote-address         inet:host
                    +--rw unt:remote-port            inet:port-number
                    +--rw unt:local-address?         inet:ip-address {local-binding}?
                    +--rw unt:local-port?            inet:port-number {local-binding}?
                    +--rw unt:dtls! {dtls}?
                    +--rw unt:enable-segmentation?   boolean
                    +--rw unt:max-segment-size?      uint16

  rpcs:
    +---x establish-subscription
    |  +---w input
    |  |  +---w (target)
    |  |  |  +--:(stream)
    |  |  |  |  +---w (stream-filter)?
    |  |  |  |  |  +--:(by-reference)
    |  |  |  |  |  |  +---w stream-filter-name                   stream-filter-ref
    |  |  |  |  |  +--:(within-subscription)
    |  |  |  |  |     +---w (filter-spec)?
    |  |  |  |  |        +--:(stream-subtree-filter)
    |  |  |  |  |        |  +---w stream-subtree-filter?         <anydata> {subtree}?
    |  |  |  |  |        +--:(stream-xpath-filter)
    |  |  |  |  |           +---w stream-xpath-filter?           yang:xpath1.0 {xpath}?
    |  |  |  |  +---w stream                                     stream-ref
    |  |  |  |  +---w replay-start-time?                         yang:date-and-time {replay}?
    |  |  |  +--:(yp:datastore)
    |  |  |     +---w yp:datastore                               identityref
    |  |  |     +---w (yp:selection-filter)?
    |  |  |        +--:(yp:by-reference)
    |  |  |        |  +---w yp:selection-filter-ref              selection-filter-ref
    |  |  |        +--:(yp:within-subscription)
    |  |  |           +---w (yp:filter-spec)?
    |  |  |              +--:(yp:datastore-subtree-filter)
    |  |  |              |  +---w yp:datastore-subtree-filter?   <anydata> {sn:subtree}?
    |  |  |              +--:(yp:datastore-xpath-filter)
    |  |  |                 +---w yp:datastore-xpath-filter?     yang:xpath1.0 {sn:xpath}?
    |  |  +---w stop-time?                                       yang:date-and-time
    |  |  +---w dscp?                                            inet:dscp {dscp}?
    |  |  +---w weighting?                                       uint8 {qos}?
    |  |  +---w dependency?                                      subscription-id {qos}?
    |  |  +---w encoding?                                        encoding
    |  |  +---w (yp:update-trigger)?
    |  |  |  +--:(yp:periodic)
    |  |  |  |  +---w yp:periodic!
    |  |  |  |     +---w yp:period    centiseconds
    |  |  |  +--:(yp:on-change) {on-change}?
    |  |  |     +---w yp:on-change!
    |  |  |        +---w yp:dampening-period?   centiseconds
    |  |  |        +---w yp:sync-on-start?      boolean
    |  |  |        +---w yp:excluded-change*    change-type
    |  |  +---w ypr:module-version-config* [module-name] {yang-push-revision-supported}?
    |  |     +---w ypr:module-name       yang:yang-identifier
    |  |     +---w ypr:revision?         rev:revision-date
    |  |     +---w ypr:version?          ysver:version
    |  +--ro output
    |     +--ro id                            subscription-id
    |     +--ro replay-start-time-revision?   yang:date-and-time {replay}?
    +---x modify-subscription
    |  +---w input
    |     +---w id                                               subscription-id
    |     +---w (target)
    |     |  +--:(stream)
    |     |  |  +---w (stream-filter)?
    |     |  |     +--:(by-reference)
    |     |  |     |  +---w stream-filter-name                   stream-filter-ref
    |     |  |     +--:(within-subscription)
    |     |  |        +---w (filter-spec)?
    |     |  |           +--:(stream-subtree-filter)
    |     |  |           |  +---w stream-subtree-filter?         <anydata> {subtree}?
    |     |  |           +--:(stream-xpath-filter)
    |     |  |              +---w stream-xpath-filter?           yang:xpath1.0 {xpath}?
    |     |  +--:(yp:datastore)
    |     |     +---w yp:datastore?                              identityref
    |     |     +---w (yp:selection-filter)?
    |     |        +--:(yp:by-reference)
    |     |        |  +---w yp:selection-filter-ref              selection-filter-ref
    |     |        +--:(yp:within-subscription)
    |     |           +---w (yp:filter-spec)?
    |     |              +--:(yp:datastore-subtree-filter)
    |     |              |  +---w yp:datastore-subtree-filter?   <anydata> {sn:subtree}?
    |     |              +--:(yp:datastore-xpath-filter)
    |     |                 +---w yp:datastore-xpath-filter?     yang:xpath1.0 {sn:xpath}?
    |     +---w (yp:update-trigger)?
    |     |  +--:(yp:periodic)
    |     |  |  +---w yp:periodic!
    |     |  |     +---w yp:period    centiseconds
    |     |  +--:(yp:on-change) {on-change}?
    |     |     +---w yp:on-change!
    |     |        +---w yp:dampening-period?   centiseconds
    |     +---w ypr:module-version-config* [module-name] {yang-push-revision-supported}?
    |        +---w ypr:module-name       yang:yang-identifier
    |        +---w ypr:revision?         rev:revision-date
    |        +---w ypr:version?          ysver:version
    +---x delete-subscription
    |  +---w input
    |     +---w id    subscription-id
    +---x kill-subscription
       +---w input
          +---w id    subscription-id

  notifications:
    +---n replay-completed {replay}?
    |  +--ro id    subscription-id
    +---n subscription-completed {configured}?
    |  +--ro id    subscription-id
    +---n subscription-modified
    |  +--ro id                                               subscription-id
    |  +--ro (target)
    |  |  +--:(stream)
    |  |  |  +--ro (stream-filter)?
    |  |  |  |  +--:(by-reference)
    |  |  |  |  |  +--ro stream-filter-name                   stream-filter-ref
    |  |  |  |  +--:(within-subscription)
    |  |  |  |     +--ro (filter-spec)?
    |  |  |  |        +--:(stream-subtree-filter)
    |  |  |  |        |  +--ro stream-subtree-filter?         <anydata> {subtree}?
    |  |  |  |        +--:(stream-xpath-filter)
    |  |  |  |           +--ro stream-xpath-filter?           yang:xpath1.0 {xpath}?
    |  |  |  +--ro stream                                     stream-ref
    |  |  |  +--ro replay-start-time?                         yang:date-and-time {replay}?
    |  |  +--:(yp:datastore)
    |  |     +--ro yp:datastore                               identityref
    |  |     +--ro (yp:selection-filter)?
    |  |        +--:(yp:by-reference)
    |  |        |  +--ro yp:selection-filter-ref              selection-filter-ref
    |  |        +--:(yp:within-subscription)
    |  |           +--ro (yp:filter-spec)?
    |  |              +--:(yp:datastore-subtree-filter)
    |  |              |  +--ro yp:datastore-subtree-filter?   <anydata> {sn:subtree}?
    |  |              +--:(yp:datastore-xpath-filter)
    |  |                 +--ro yp:datastore-xpath-filter?     yang:xpath1.0 {sn:xpath}?
    |  +--ro stop-time?                                       yang:date-and-time
    |  +--ro dscp?                                            inet:dscp {dscp}?
    |  +--ro weighting?                                       uint8 {qos}?
    |  +--ro dependency?                                      subscription-id {qos}?
    |  +--ro transport?                                       transport {configured}?
    |  +--ro encoding?                                        encoding
    |  +--ro purpose?                                         string {configured}?
    |  +--ro (yp:update-trigger)?
    |  |  +--:(yp:periodic)
    |  |  |  +--ro yp:periodic!
    |  |  |     +--ro yp:period         centiseconds
    |  |  |     +--ro yp:anchor-time?   yang:date-and-time
    |  |  +--:(yp:on-change) {on-change}?
    |  |     +--ro yp:on-change!
    |  |        +--ro yp:dampening-period?   centiseconds
    |  |        +--ro yp:sync-on-start?      boolean
    |  |        +--ro yp:excluded-change*    change-type
    |  +--ro dn:message-publisher-id*                         uint32
    |  +--ro ypr:module-version* [module-name] {yang-push-revision-supported}?
    |  |  +--ro ypr:module-name       yang:yang-identifier
    |  |  +--ro ypr:revision          rev:revision-date
    |  |  +--ro ypr:version?          ysver:version
    |  +--ro ypr:yang-library-content-id?                     -> /yanglib:yang-library/content-id {yang-push-revision-supported}?
    +---n subscription-resumed
    |  +--ro id    subscription-id
    +---n subscription-started {configured}?
    |  +--ro id                                               subscription-id
    |  +--ro (target)
    |  |  +--:(stream)
    |  |  |  +--ro (stream-filter)?
    |  |  |  |  +--:(by-reference)
    |  |  |  |  |  +--ro stream-filter-name                   stream-filter-ref
    |  |  |  |  +--:(within-subscription)
    |  |  |  |     +--ro (filter-spec)?
    |  |  |  |        +--:(stream-subtree-filter)
    |  |  |  |        |  +--ro stream-subtree-filter?         <anydata> {subtree}?
    |  |  |  |        +--:(stream-xpath-filter)
    |  |  |  |           +--ro stream-xpath-filter?           yang:xpath1.0 {xpath}?
    |  |  |  +--ro stream                                     stream-ref
    |  |  |  +--ro replay-start-time?                         yang:date-and-time {replay}?
    |  |  |  +--ro replay-previous-event-time?                yang:date-and-time {replay}?
    |  |  +--:(yp:datastore)
    |  |     +--ro yp:datastore                               identityref
    |  |     +--ro (yp:selection-filter)?
    |  |        +--:(yp:by-reference)
    |  |        |  +--ro yp:selection-filter-ref              selection-filter-ref
    |  |        +--:(yp:within-subscription)
    |  |           +--ro (yp:filter-spec)?
    |  |              +--:(yp:datastore-subtree-filter)
    |  |              |  +--ro yp:datastore-subtree-filter?   <anydata> {sn:subtree}?
    |  |              +--:(yp:datastore-xpath-filter)
    |  |                 +--ro yp:datastore-xpath-filter?     yang:xpath1.0 {sn:xpath}?
    |  +--ro stop-time?                                       yang:date-and-time
    |  +--ro dscp?                                            inet:dscp {dscp}?
    |  +--ro weighting?                                       uint8 {qos}?
    |  +--ro dependency?                                      subscription-id {qos}?
    |  +--ro transport?                                       transport {configured}?
    |  +--ro encoding?                                        encoding
    |  +--ro purpose?                                         string {configured}?
    |  +--ro (yp:update-trigger)?
    |  |  +--:(yp:periodic)
    |  |  |  +--ro yp:periodic!
    |  |  |     +--ro yp:period         centiseconds
    |  |  |     +--ro yp:anchor-time?   yang:date-and-time
    |  |  +--:(yp:on-change) {on-change}?
    |  |     +--ro yp:on-change!
    |  |        +--ro yp:dampening-period?   centiseconds
    |  |        +--ro yp:sync-on-start?      boolean
    |  |        +--ro yp:excluded-change*    change-type
    |  +--ro dn:message-publisher-id*                         uint32
    |  +--ro ypr:module-version* [module-name] {yang-push-revision-supported}?
    |  |  +--ro ypr:module-name       yang:yang-identifier
    |  |  +--ro ypr:revision          rev:revision-date
    |  |  +--ro ypr:version?          ysver:version
    |  +--ro ypr:yang-library-content-id?                     -> /yanglib:yang-library/content-id {yang-push-revision-supported}?
    +---n subscription-suspended
    |  +--ro id        subscription-id
    |  +--ro reason    identityref
    +---n subscription-terminated
       +--ro id        subscription-id
       +--ro reason    identityref

module: ietf-system-capabilities
  +--ro system-capabilities
     +--ro datastore-capabilities* [datastore]
     |  +--ro datastore                -> /yanglib:yang-library/datastore/name
     |  +--ro per-node-capabilities* []
     |     +--ro (node-selection)?
     |     |  +--:(node-selector)
     |     |     +--ro node-selector?              nacm:node-instance-identifier
     |     +--ro notc:subscription-capabilities
     |        +--ro notc:max-nodes-per-update?               uint32
     |        +--ro notc:periodic-notifications-supported?   notification-support
     |        +--ro (notc:update-period)?
     |        |  +--:(notc:minimum-update-period)
     |        |  |  +--ro notc:minimum-update-period?        uint32
     |        |  +--:(notc:supported-update-period)
     |        |     +--ro notc:supported-update-period*      uint32
     |        +--ro notc:on-change-supported?                notification-support {yp:on-change}?
     |        +--ro notc:minimum-dampening-period?           uint32 {yp:on-change}?
     |        +--ro notc:supported-excluded-change-type*     union {yp:on-change}?
     +--ro notc:subscription-capabilities
        +--ro notc:max-nodes-per-update?                 uint32
        +--ro notc:periodic-notifications-supported?     notification-support
        +--ro (notc:update-period)?
        |  +--:(notc:minimum-update-period)
        |  |  +--ro notc:minimum-update-period?          uint32
        |  +--:(notc:supported-update-period)
        |     +--ro notc:supported-update-period*        uint32
        +--ro notc:on-change-supported?                  notification-support {yp:on-change}?
        +--ro notc:minimum-dampening-period?             uint32 {yp:on-change}?
        +--ro notc:supported-excluded-change-type*       union {yp:on-change}?
        +--ro ypr:yang-push-module-revision-supported?   boolean

module: ietf-yang-push

  rpcs:
    +---x resync-subscription {on-change}?
       +---w input
          +---w id    sn:subscription-id

  notifications:
    +---n push-update
    |  +--ro id?                        sn:subscription-id
    |  +--ro datastore-contents?        <anydata>
    |  +--ro incomplete-update?         empty
    |  +--ro dn:message-publisher-id?   uint32
    +---n push-change-update {on-change}?
       +--ro id?                        sn:subscription-id
       +--ro datastore-changes
       |  +--ro yang-patch
       |     +--ro patch-id    string
       |     +--ro comment?    string
       |     +--ro edit* [edit-id]
       |        +--ro edit-id      string
       |        +--ro operation    enumeration
       |        +--ro target       target-resource-offset
       |        +--ro point?       target-resource-offset
       |        +--ro where?       enumeration
       |        +--ro value?       <anydata>
       +--ro incomplete-update?         empty
       +--ro dn:message-publisher-id?   uint32

module: yumaworks-yang-cbor
  +--ro yang-sid-info!
     +--ro sid-set-id?          sid-set-id
     +--ro yang-sid-mode?       ywt:yang-sid-mode
     +--ro lsid-size?           ywt:lsid-size
     +--ro current-sid-max?     sid:sid
     +--ro current-sid-count?   uint64

  rpcs:
    +---x get-yang-sid-data
       +---w input
       |  +---w lower-bound?   sid:sid
       |  +---w upper-bound?   sid:sid
       +--ro output
          +--ro current-set-id?   sid-set-id
          +--ro data
             +--ro sid-item* [sid]
                +--ro sid            sid:sid
                +--ro namespace?     enumeration
                +--ro module-name?   string
                +--ro identifier?    union

Configuring YANG Push

There is no CLI parameter to turn YANG Push on or off. Instead, then --bundle parameter is used.

  • A bundle named "yang-push" is used:

  • yang-push is a reserved library name in the server.

  • The SIL library (libyang-push.so) contains the RPC operation callbacks for YANG Push. The "agt" directory contains the server implementation code.

  • The server does not need to support or enable NMDA to use YANG Push. If the --with-nmda parameter is set to ‘false’ then the <operational> datastore will consist of config=false data nodes and their ancestor lists, list keys, and containers.

  • The source code must be built using WITH_YANG_PUSH=1 or EVERYTHING=1 make flag in order for the YANG Push code to be included in the target binaries.

Command line example:

netconfd-pro  --bundle=yang-push

Config file example;

netconfd-pro {
  bundle yang-push
}

Configuring Named Filters

The /filters container and /filters/stream-filter list are defined in RFC 8639.

+--rw filters
|  +--rw stream-filter* [name]
|  |  +--rw name                           string
|  |  +--rw (filter-spec)?
|  |     +--:(stream-subtree-filter)
|  |     |  +--rw stream-subtree-filter?   <anydata> {subtree}?
|  |     +--:(stream-xpath-filter)
|  |        +--rw stream-xpath-filter?     yang:xpath1.0 {xpath}?
|  +--rw yp:selection-filter* [filter-id]
|     +--rw yp:filter-id                         string
|     +--rw (yp:filter-spec)?
|        +--:(yp:datastore-subtree-filter)
|        |  +--rw yp:datastore-subtree-filter?   <anydata> {sn:subtree}?
|        +--:(yp:datastore-xpath-filter)
|           +--rw yp:datastore-xpath-filter?     yang:xpath1.0 {sn:xpath}?

Named filters are fully supported, using the /filters subtree:

  • An event stream subscription can use the "stream-filter" list

  • A datastore subscriptions can use the selection-filter list.

  • Even though the contents of each list are similar, the content of the filters is not.

  • A "stream-filter" is a notification filter, and the content is exactly like the <filter> element used in the "create-subscription" operation.

  • A "selection-filter" is a retrieval filter, and the content is exactly like the <filter> element used in the "get" operation.

Filter Configuration Restrictions

  • A filter can be created at any time.

  • A filter can be modified at any time. If any subscriptions are using the filter then they will updated to use the new filter as soon as possible. This is usually as soon as any current message on that session is completed.

    • If the new filter is not acceptable for a subscription using the filter then that subscription will be terminated. Use caution when modifying a filter that is in use.

  • A filter can only be deleted if no subscription is using it.

  • An empty filter is allowed, which means only a key leaf was provided and not a filter leaf. This allows placeholders to be used. It is not recommended to use this feature. An empty filter is the same as no filter, and if that is not allowed for a subscription, then it will be rejected (or deleted if already active).

  • Sending anydata for a subtree filter, or an xpath1.0 leaf for an XPath filter can be complex or even unsupported in the client. XPath filters will be accepted without prefixed identifiers. If prefixes are used, then they must be properly mapped to a module namespace URI using an "xmlns" attribute. If multiple nodes match the same local name then prefixes are required to pick only one of them.

Filter Examples

A subtree filter for an event stream that selects the "netconf-session-end" event:

<filters xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
  <stream-filter>
    <name>filter1</name>
    <stream-subtree-filter>
      <netconf-session-end xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications" />
    </stream-subtree-filter>
  </stream-filter>
</filters>

An XPath filter for an event stream that selects the "netconf-session-start" event:

<filters xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
  <stream-filter>
    <name>filter2</name>
    <stream-xpath-filter xmlns:n="urn:ietf:params:xml:ns:yang:ietf-netconf-notifications"
       >/n:netconf-session-start</stream-xpath-filter>
  </stream-filter>
</filters>

A subtree filter for a datastore that selects the /nacm/groups subtree.

<filters xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
  <selection-filter xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
    <filter-id>filter2</filter-id>
    <datastore-subtree-filter>
      <nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
        <groups />
      </nacm>
    </datastore-subtree-filter>
  </selection-filter>
</filters>

An XPath filter for a datastore that selects the /nacm/groups subtree:

<filters xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
  <selection-filter xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
    <filter-id>filter3</filter-id>
    <datastore-xpath-filter
      xmlns:n="urn:ietf:params:xml:ns:yang:ietf-netconf-acm"
      >/n:nacm/n:groups</datastore-xpath-filter>
  </selection-filter>
</filters>

YANG Push RPC Operations

The following RPC Operations are supported

  • establish-subscription

  • modify-subscription

  • delete-subscription

  • kill-subscription

  • resync-subscription

YANG Push Notification Events

The following Notifications are supported:

  • push-update

  • push-change-update

  • replay-completed

  • subscription-modified

  • subscription-resumed

  • subscription-suspended

  • subscription-terminated

Periodic Subscriptions

A periodic push subscription request that is granted will cause the specified data to be pushed at a specified interval.

The data is sent whether it changed or not. Every interval, a push-update notification with the specified data will be sent to the subscription.

The --push-max-periodic CLI parameter controls the number of these push subscriptions that can be enabled at once. This is the server total, so one subscription could use up all the subscriptions. The server does not prevent a session from establishing multiple subscriptions.

Use the <establish-subscription> operation to start a periodic subscription. The "datastore", and "period" parameters must be provided.

There are no filter restrictions for a periodic subscription. Any filter that is allowed for a <get> operation may be used for a periodic subscription. If a named filter is used then it can be modified while a periodic subscription is active. The subscription output will be updated as soon as possible after a filter reference in use is modified.

The datastore parameter can be set to "candidate", "operational", or "running". It must be set to "operational" to monitor config=false data nodes.

Example: Retrieve the /interfaces-state/interface entry for interface "lo" every 30 seconds.

The client might send this request:

<?xml version="1.0" encoding="UTF-8"?>
<rpc message-id="2" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <establish-subscription xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
    <datastore xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push"
      xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">ds:operational</datastore>
    <datastore-subtree-filter xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
      <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
        <interface>
          <name>lo</name>
        </interface>
      </interfaces-state>
    </datastore-subtree-filter>
    <periodic xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
      <period>3000</period>
    </periodic>
  </establish-subscription>
</rpc>

The server sends the subscription-id in the reply if the subscription was accepted.

This is important since multiple subscriptions per session are allowed. The <push-update> and <push-change-update> notifications each contain an <id> leaf that matches the value returned in the <rpc-reply> for the <establish-subscription> request.

<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply message-id="2" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <id xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">1</id>
</rpc-reply>

The server will send an initial "push-update" notification right away, and then periodically every 30 seconds

<?xml version="1.0" encoding="UTF-8"?>
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
  <eventTime>2020-10-11T19:02:59Z</eventTime>
  <push-update xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
    <id>1</id>
    <datastore-contents>
      <interfaces-state xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
        <interface>
          <name>lo</name>
          <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type"
            >ianaift:softwareLoopback</type>
          <admin-status>up</admin-status>
          <oper-status>up</oper-status>
          <if-index>1</if-index>
          <phys-address>00:00:00:00:00:00</phys-address>
          <speed>0</speed>
          <statistics>
            <in-octets>163797125</in-octets>
            <in-unicast-pkts>866265</in-unicast-pkts>
            <in-multicast-pkts>0</in-multicast-pkts>
            <in-discards>0</in-discards>
            <in-errors>0</in-errors>
            <out-octets>163797125</out-octets>
            <out-unicast-pkts>866265</out-unicast-pkts>
            <out-discards>0</out-discards>
            <out-errors>0</out-errors>
          </statistics>
        </interface>
      </interfaces-state>
    </datastore-contents>
  </push-update>
</notification>

Conventional On-Change Subscriptions

A conventional on-change subscription request that is granted will cause the specified data to be pushed when the data has changed. The "candidate" and "running" datastores can be monitored.

There is no internal overhead such as polling to support this subscription type. The server will check these subscriptions when a successful commit to the target datastore has been completed. Error operations are not reported to the subscription.

If the sync-on-start option is selected then a <push-update> will be sent when the subscription starts. After that, only <push-change-update> events will usually be sent. The resync-subscription operation will cause a new <push-update> notification to be generated as soon as possible.

The "on-change" presence container must be provided, and a "dampening-period" parameter must be provided. This must be greater or equal to the --push-min-dampening CLI parameter value.

The filter parameter is restricted. Two modes of operation are provided:

  1. object monitoring mode: The filter must represent one configuration data node. All instances of that one object will be monitored.

  2. datastore replication mode: No filter at all is used

Example: Object Monitoring Mode

Retrieve the /nacm/groups/group entry from <running> if any group is edited

Assume the client has created a named filter called "nacm-group"

<config>
  <filters xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
    <selection-filter xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
      <filter-id>nacm-group</filter-id>
      <datastore-xpath-filter
        xmlns:n="urn:ietf:params:xml:ns:yang:ietf-netconf-acm"
        >/n:nacm/n:groups/n:group</datastore-xpath-filter>
    </selection-filter>
  </filters>
</config>

The client might send this request using a "selection-filter-ref" instead of an inline filter:

The dampening period is set to 10 seconds in this example.

<rpc message-id="5" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <establish-subscription xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
    <datastore xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push"
      xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">ds:running</datastore>
    <selection-filter-ref
      xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">nacm-group</selection-filter-ref>
    <on-change xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
      <dampening-period>1000</dampening-period>
      <excluded-change>move</excluded-change>
      <sync-on-start>true</sync-on-start>
    </on-change>
  </establish-subscription>
</rpc>

Assume the server sent an <id> response with a value of "1" like the example above.

If the "sync-on-start" parameter is set to "true" (the default) then the server will send a <push-update> notification as soon as the subscription starts:

<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
  <eventTime>2020-10-11T19:39:21Z</eventTime>
  <push-update xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
    <id>1</id>
    <datastore-contents>
      <nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
        <groups>
          <group>
            <name>test1</name>
          </group>
        </groups>
      </nacm>
    </datastore-contents>
  </push-update>
</notifications>

The server will send a <push-change-update> notification when the targeted entry is changed

<?xml version="1.0" encoding="UTF-8"?>
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
  <eventTime>2020-10-11T19:42:01Z</eventTime>
  <push-change-update xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
    <id>1</id>
    <datastore-changes>
      <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
        <patch-id>0</patch-id>
        <edit>
          <edit-id>E1</edit-id>
          <operation>create</operation>
          <target>/ietf-netconf-acm:nacm/groups/group=monitor</target>
          <value>
            <group xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
              <name>monitor</name>
              <user-name>admin1</user-name>
              <user-name>admin2</user-name>
            </group>
          </value>
        </edit>
      </yang-patch>
    </datastore-changes>
  </push-change-update>
</notification>

Example: Datastore Replication Mode

Retrieve the patch for <running> if any config is edited

The dampening period is set to 10 seconds in this example.

The client might send this request without any filter parameter:

<?xml version="1.0" encoding="UTF-8"?>
<rpc message-id="2" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <establish-subscription xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
    <datastore xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push"
           xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">ds:running</datastore>
     <on-change xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
       <dampening-period>1000</dampening-period>
     </on-change>
  </establish-subscription>
</rpc>

The server sends an <rpc-reply> with a new subscription ID, since another is in progress:

<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply message-id="2" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <id xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">2</id>
</rpc-reply>

The server will send the initial <push-update> notification right away

<?xml version="1.0" encoding="UTF-8"?>
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
  <eventTime>2020-10-11T19:50:29Z</eventTime>
  <push-update xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
    <id>2</id>
    <datastore-contents>
      <filters xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
        <selection-filter xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
          <filter-id>nacm-group</filter-id>
          <datastore-xpath-filter xmlns:n="urn:ietf:params:xml:ns:yang:ietf-netconf-acm"
            >/n:nacm/n:groups/n:group</datastore-xpath-filter>
        </selection-filter>
      </filters>
      <nacm xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
        <groups>
          <group>
            <name>test1</name>
          </group>
          <group>
            <name>monitor</name>
            <user-name>admin1</user-name>
            <user-name>admin2</user-name>
          </group>
        </groups>
      </nacm>
    </datastore-contents>
  </push-update>
</notification>

If the <running> datastore changes at all the server will send a <push-change-update> notification:

In this example, the /nacm/rule-list entry is edited:

<?xml version="1.0" encoding="UTF-8"?>
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
  <eventTime>2020-10-11T20:03:37Z</eventTime>
  <push-change-update xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
    <id>2</id>
    <datastore-changes>
      <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
        <patch-id>1</patch-id>
        <edit>
          <edit-id>E1</edit-id>
          <operation>create</operation>
          <target>/ietf-netconf-acm:nacm/rule-list=allow-nacm-read</target>
          <value>
            <rule-list xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-acm">
              <name>allow-nacm-read</name>
              <group>monitor</group>
              <rule>
                <name>r1</name>
                <module-name>ietf-netconf-acm</module-name>
                <access-operations>read</access-operations>
                <action>permit</action>
                <comment>allow monitor group to read nacm</comment>
              </rule>
            </rule-list>
          </value>
        </edit>
      </yang-patch>
    </datastore-changes>
  </push-change-update>
</notification>

Simulated Operational On-Change Subscriptions

A simulated operational on-change subscription request that is granted will cause the specified data to be pushed when the data has changed. The "operational" datastore can be monitored. These subscriptions are only allowed if the --push-simop-enabled parameter is set to ‘true’.

There is an internal polling and processing overhead required to support this subscription type. The server will check these subscriptions when the --push-simop-period interval expires. If the "dampening-period" parameter is provided then the maximum of these two parameters is used for the internal polling interval, when dampening is required.

If the sync-on-start option is selected then a <push-update> will be sent when the subscription starts. After that, only <push-change-update> Event notifications will usually be sent. The <resync-subscription> operation will cause a new <push-update> Event notification to be generated as soon as possible.

The "on-change" presence container must be provided, and a "dampening-period" parameter must be provided. This must be greater or equal to the --push-min-dampening CLI parameter value.

There are no filter restrictions for a simulated operational subscription. Any filter that is allowed for a <get> operation may be used for a simulated operational subscription. If a named filter is used then it can be modified while a subscription is active. The subscription output will be updated as soon as possible after a filter reference in use is modified.

Example: Retrieve the /netconf-state/backup-files subtree if it changes

In this example, the <datastore-xpath-filter> does not use any prefixes. The server will accept this filter and find the correct data nodes even if the prefixes are missing.

In this example, the dampening period is 1 second.

<?xml version="1.0" encoding="UTF-8"?>
<rpc message-id="9" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <establish-subscription xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
    <datastore xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push"
      xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">ds:operational</datastore>
    <datastore-xpath-filter xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push"
      >/netconf-state/backup-files</datastore-xpath-filter>
    <on-change xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
      <dampening-period>100</dampening-period>
    </on-change>
  </establish-subscription>
</rpc>

The server will send a <push-update> notification right away for this filter:

<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
  <eventTime>2020-10-11T20:20:21Z</eventTime>
  <push-update xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
    <id>4</id>
    <datastore-contents>
      <netconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
        <backup-files xmlns="http://yumaworks.com/ns/yumaworks-system">
          <backup-file>
            <name>push1.xml</name>
            <backup-time>2020-08-29T20:10:23Z</backup-time>
          </backup-file>
          <backup-file>
            <name>push2.xml</name>
            <backup-time>2020-08-29T20:50:35Z</backup-time>
          </backup-file>
        </backup-files>
      </netconf-state>
    </datastore-contents>
  </push-update>
</notification>

If any backup file changes then the entire <backup-files> container is returned in the <push-change-update> notification:

Note that the operation will always be "replace" for a simulated operational on-change subscription.

<?xml version="1.0" encoding="UTF-8"?>
<notification xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
  <eventTime>2020-10-11T20:25:35Z</eventTime>
  <push-change-update xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
    <id>4</id>
    <datastore-changes>
      <yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
        <patch-id>0</patch-id>
        <comment>simop</comment>
        <edit>
          <edit-id>E1</edit-id>
          <operation>replace</operation>
          <target>/</target>
          <value>
            <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
              <netconf-state xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring">
                <backup-files xmlns="http://yumaworks.com/ns/yumaworks-system">
                  <backup-file>
                    <name>push1.xml</name>
                    <backup-time>2020-08-29T20:10:23Z</backup-time>
                  </backup-file>
                  <backup-file>
                    <name>push2.xml</name>
                    <backup-time>2020-08-29T20:50:35Z</backup-time>
                  </backup-file>
                  <backup-file>
                    <name>test-snap.xml</name>
                    <backup-time>2020-10-11T20:25:34Z</backup-time>
                  </backup-file>
                </backup-files>
              </netconf-state>
            </data>
          </value>
        </edit>
      </yang-patch>
    </datastore-changes>
  </push-change-update>
</notification>

Operational On-Change Subscriptions

An operational on-change subscription request that is granted will cause the specified data to be pushed when the subsystem responsible for pushing object updates sends a push-update to the main server. This mode is not yet implemented.

Data Synchronization With anchor-time

A periodic datastore subscription can specific an 'anchor-time' parameter to cause the first periodic update to occur at an interval based on the anchor-time. YANG Push subscriptions across multiple devices can be setup to start at the same time, so time series databases can be populated with related data samples.

anchor-time Usage

The anchor-time parameter is not well defined in RFC 8641. The implementation supported by the server is restricted.

The date-and-time format is used as follows for anchor-time:

YYYY-MM-DDTHH:MM:SSZ

There are multiple parts:

  • The date field 'YYYY-MM-DD' must be present and can be any valid date. This field is ignored.

  • The letter T must follow the date field

  • The time field 'HH:MM:SS' must be present

  • The letter Z must follow the time field. This field is ignored.

The time field is the only field used, as follows:

  • Only one part in the 'time' field can be used (hours, minutes, or seconds)

  • If multiple fields are set, then the first non-zero field is used for the anchor interval.

  • 'HH': hours value from '00' to '23'

  • 'MM': minutes value from '00' to '59'

  • 'SS': seconds value from '00' to '59'

  • If the seconds field has a fractional part (e.g., 30.1234) then the fractional part is ignored.

  • If the timezone field is present (e.g., +03:00) then it is ignored.

Example:

  • Start the collection at the next minute.

  • Wait between 0 and 59 seconds for the next start of the interval.

2025-01-01T00:01:00Z

Example:

  • Start the collection at the next 5 minute interval.

  • Wait between 0 and 299 seconds for the next start of the interval.

2025-01-01T00:05:00Z

Example:

  • Start the collection at the next 30 second interval.

  • Wait between 0 and 29 seconds for the next start of the interval.

2025-01-01T00:00:30Z

Example:

  • Start the collection at the next one hour interval.

  • Wait between 0 and 3599 seconds for the next start of the interval.

2025-01-01T01:00:00Z

Example: Full client request

  • Monitor the /interfaces-state/interface list

  • Start on a 1 minute interval

  • Send an update every 30 seconds

The client might send the following request:

<?xml version="1.0" encoding="UTF-8"?>
<rpc message-id="2"
 xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
 <establish-subscription
    xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
  <datastore xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push"
    xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">ds:operational</datastore>
  <datastore-xpath-filter xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">/interfaces-state/interface</datastore-xpath-filter>
  <periodic xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
   <period>3000</period>
   <anchor-time>2025-01-01T00:01:00Z</anchor-time>
  </periodic>
 </establish-subscription>
</rpc>

The server log should show the anchor-time handling, if the --log-level setting is debug2 or higher.

agt_not: Convert anchor-time '2025-01-01T00:01:00Z' to hr: 0 min: 1 sec: 0
Time now: 2025-09-18T18:50:10Z
Got wait time 50 seconds for interval 60
agt_not: Activated Push subscription 1 for session '3'
agt_rpc: sending data <rpc-reply> for ses 3 msg '2'

Note that the server will send an 'rpc-reply' message right away, even though the subscription is waiting for the anchor-time interval.

YANG Push UDP-Notif Deployment with NetGauze and Kafka

This section describes how to deploy YANG Push using configured subscriptions on netconfd-pro with either yangcli-pro or NetGauze as the UDP-Notif collector. It also describes the optional Kafka integration path.

The deployment covered by this section uses configured subscriptions. Configured subscriptions are created by editing the /subscriptions subtree. This is different from NETCONF dynamic subscriptions, which are created with the <establish-subscription> RPC and deliver events over the same NETCONF session.

End-to-End Test Procedure

This onboarding section describes the complete end-to-end validation workflow for YANG Push over UDP Notif using netconfd-pro, NetGauze, and an optional Kafka-compatible message broker.

The goal of the test is to confirm that netconfd-pro can operate as a YANG Push Publisher, send configured subscription notifications over UDP Notif, and that NetGauze can receive, decode, validate, and optionally publish the resulting JSON telemetry records to Kafka.

The procedure validates the full data path:

netconfd-pro -> UDP Notif -> NetGauze -> Kafka topic -> consumer

The following sections describe each step in detail:

  1. Start Kafka or Redpanda. Kafka Setup for NetGauze

  2. Create the udp-notif-json topic. Kafka Setup for NetGauze

  3. Start NetGauze with the provided YAML configuration. Using NetGauze as the YANG Push Collector

  4. Start netconfd-pro with the yang-push bundle enabled.

  5. Configure the UDP Notif receiver instance on netconfd-pro. Configure the UDP-Notif Receiver Instance

  6. Configure a periodic or on-change configured subscription on netconfd-pro. Configure a Periodic YANG Push Subscription

  7. Confirm that NetGauze logs show UDP Notif and YANG Push activity.

  8. Confirm that the Publisher sends <subscription-started>, followed by <push-update> or <push-change-update> notifications.

  9. Confirm that Kafka receives records on the udp-notif-json topic.

  10. Retrieve the /subscriptions subtree from netconfd-pro and confirm receiver state, subscription state, and event counters.

At the end of this procedure, the deployment is considered functional when NetGauze receives UDP Notif messages, the Publisher counters increase, and Kafka receives JSON telemetry records when the Kafka publisher is enabled.

Architecture

../_images/yang_push_netgauze_architecture.png

In this deployment model, netconfd-pro acts as the YANG Push Publisher. A configured subscription is created in the server configuration datastore. The subscription references a receiver instance that defines the UDP-Notif collector address and port.

After the configured subscription becomes active, the Publisher sends a <subscription-started> notification to the configured receiver. After that, periodic subscriptions send <push-update> notifications, and on-change subscriptions send <push-change-update> notifications when the selected data changes.

Note

A <subscription-started> notification is expected for configured subscriptions. It is not expected for a dynamic <establish-subscription> subscription over NETCONF.

The collector can be one of the following:

  • yangcli-pro UDP-Notif Collector

  • NetGauze UDP-Notif / YANG Push Collector

When NetGauze is used, the collector can optionally publish normalized output to Kafka. Downstream consumers can then retrieve the messages from Kafka and, if configured, validate them against schemas retrieved through a YANG Schema Registry.

NetGauze is not only a raw UDP receiver. In the YANG Push workflow, it also uses NETCONF access to the Publisher to retrieve schema context, YANG Library data, and subscription metadata. This information is used to validate and normalize received messages.

netconfd-pro Build and Startup

The yang-push bundle must be available and loaded by netconfd-pro. The WITH_YANG_PUSH and WITH_YANG_PUSH2 compiler flags are required when building this feature from source code.

When CBOR/SID-encoded telemetry is used, build and enable the YANG-CBOR feature by using the WITH_YANG_CBOR compiler flag.

Example startup command:

netconfd-pro \
  --bundle=yang-push \
  --with-notifications=true \
  --with-yang-push2=true

Equivalent configuration file fragment:

netconfd-pro {
  bundle yang-push
  with-notifications true
  with-yang-push2 true
}

Refer to CLI Parameters for YANG Push for additional configuration options.

Recommended verification from yangcli-pro:

> connect server=127.0.0.1 user=<user> password=<password>
> show session

Notification Capabilities:
 Old Subscriptions (RFC 5277): yes
   Interleave: yes
   Replay: yes
 New Subscriptions (RFC 8639): yes
   Dynamic: yes
   Configured: yes
   Filters: yes
 YANG Push (RFC 8641): yes
   On-Change: yes
   Encodings: XML JSON

The session summary should show the YANG Push and UDP-Notif modules and the related features, including configured, encode-json, encode-xml, on-change, and the UDP-Notif segmentation feature when available.

Using yangcli-pro as a YANG Push Collector

yangcli-pro can be used as a local validation Collector before introducing NetGauze or Kafka.

Start yangcli-pro with the Collector enabled, refer to UDP-Notif Collector for more details and configuration options:

yangcli-pro \
  --collector-enabled=true \
  --collector-address=127.0.0.1 \
  --collector-port=9999

Alternatively, start the Collector from inside yangcli-pro:

> connect server=127.0.0.1 user=tony password=<password>
> collector start collector-address=127.0.0.1 collector-port=9999
> collector status

Collector Enabled: true
Collector Active: true
Collector Publishers: 1
Collector Messages: 0

The NETCONF session is important because the Collector needs access to the Publisher's YANG modules and YANG Library context in order to decode received UDP-Notif messages.

Note

Do not rely on the default collector port in examples. Set collector-port explicitly and use the same port in the configured udp-notif-receiver.

Kafka Setup for NetGauze

The Kafka publisher is optional. NetGauze can receive and validate UDP Notif messages without Kafka. Kafka is only required when the NetGauze publishers section is enabled and JSON telemetry output must be written to a Kafka-compatible message broker.

For local end-to-end testing, Redpanda is the recommended broker because it is Kafka API compatible, runs as a single container, and includes the rpk command-line tool inside the container. This avoids installing the full Apache Kafka toolchain only to create and inspect one test topic.

The example below starts a single-node Redpanda broker and exposes the Kafka API on 127.0.0.1:19092. This port matches the NetGauze configuration value:

bootstrap.servers: 127.0.0.1:19092

Start the local Redpanda broker:

docker run -d --name redpanda-udpnotif \
  -p 19092:19092 \
  -p 9644:9644 \
  docker.redpanda.com/redpandadata/redpanda:latest \
  redpanda start \
  --overprovisioned \
  --smp 1 \
  --memory 1G \
  --reserve-memory 0M \
  --node-id 0 \
  --check=false \
  --kafka-addr PLAINTEXT://0.0.0.0:19092 \
  --advertise-kafka-addr PLAINTEXT://127.0.0.1:19092

Verify that the broker container is running:

docker ps --filter name=redpanda-udpnotif

Create the Kafka topic used by the NetGauze JSON publisher:

docker exec -it redpanda-udpnotif \
  rpk topic create udp-notif-json \
  --brokers 127.0.0.1:19092

Verify that the topic exists:

docker exec -it redpanda-udpnotif \
  rpk topic list \
  --brokers 127.0.0.1:19092

Start a consumer to inspect messages published by NetGauze:

docker exec -it redpanda-udpnotif \
  rpk topic consume udp-notif-json \
  --brokers 127.0.0.1:19092

After the broker and topic are available, start NetGauze with the Kafka publisher enabled. When UDP Notif messages are received and processed, NetGauze should publish JSON telemetry records to the udp-notif-json topic.

Note

If NetGauze reports BrokerTransportFailure or Connection refused, the Kafka-compatible broker is not reachable at the configured bootstrap.servers address. Verify that the Redpanda container is running, that port 19092 is published to the host, and that the NetGauze YAML file uses the same broker address.

Note

This single-node Redpanda setup is intended for local development and interoperability testing. Production deployments should use the operational Kafka or Redpanda deployment model required by the target environment.

Using NetGauze as the YANG Push Collector

Refer to the official NetGauze documentation for more details and installation steps.

Before starting NetGauze, create the cache directory used for the YANG Library and schema context cache:

sudo mkdir -p /tmp/netgauze-udpnotif-cache
sudo chown -R user:user /tmp/netgauze-udpnotif-cache
chmod 700 /tmp/netgauze-udpnotif-cache

For persistent deployments, use a cache directory outside /tmp, such as /var/cache/netgauze/udpnotif.

The following command starts NetGauze with the local YAML configuration file:

cd ~/swdev/yangpush2/NetGauze
cargo run -p netgauze-collector --release -- /etc/yumapro/config.yaml

Example configuration:

runtime:
  threads: 4

logging:
  level: netgauze_collector=trace,netgauze_udp_notif_service=trace,netgauze_yang_push=trace,info
  ansi: true

telemetry:
  url: http://localhost:4317/v1/metrics
  id: netgauze-udpnotif-telemetry
  exporter_timeout: 3000
  reader_interval: 60000
  reader_timeout: 3000

udp_notif:
  subscriber_timeout: 100
  listeners:
    - address: 0.0.0.0:10000
      workers: 1

  cache_location: /tmp/netgauze-udpnotif-cache

  # NetGauze uses NETCONF-side information to retrieve schema context,
  # YANG Library data, and subscription metadata required for validation.
  netconf:
    username: user
    private_key_path: /home/user/.ssh/id_ed25519
    port: 830
    # max_retries: 3
    # max_backoff_secs: 5

  publishers:
    debug-kafka:
      buffer_size: 1000
      endpoints:
        udp-json: !TelemetryKafkaJson
          topic: udp-notif-json
          producer_config:
            bootstrap.servers: 127.0.0.1:19092
            message.timeout.ms: "60000"
            queue.buffering.max.messages: "1000"
          writer_id: netgauze-udpnotif-json

Configuration notes:

  • listeners must match the remote-address and remote-port configured on the Publisher. For a local test, the Publisher can send to 127.0.0.1:10000 and NetGauze can listen on 0.0.0.0:10000.

  • cache_location stores NetGauze's YANG-Push/YANG Library cache. Clear this directory when testing incompatible schema or draft changes.

  • The netconf section must allow NetGauze to reach the Publisher on port 830 and authenticate with the configured SSH key.

  • The publishers section is optional. If it is enabled, the Kafka broker configured in bootstrap.servers must be reachable before NetGauze starts.

  • The example Kafka endpoint publishes JSON messages to the udp-notif-json topic on 127.0.0.1:19092.

Note

For collector-only validation, omit or comment out the publishers section. If the Kafka publisher is enabled while no broker is listening on the configured address, NetGauze can start the UDP listener successfully but then report a Kafka BrokerTransportFailure or Connection refused error.

Configure the UDP-Notif Receiver Instance

The receiver instance defines where the Publisher sends UDP-Notif messages. The following example configures a NetGauze or yangcli-pro collector listening on UDP port 10000.

Replace 127.0.0.1 with the Collector host address when the Collector is not running on the same host as netconfd-pro.

The edit-config request for this scenario is shown below:

<edit-config>
   <target>
      <running/>
   </target>
   <config>
     <subscriptions xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
         <receiver-instances xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notif-receivers">
            <receiver-instance>
               <name>netgauze</name>
               <udp-notif-receiver xmlns="urn:ietf:params:xml:ns:yang:ietf-udp-notif-transport">
                  <remote-address>127.0.0.1</remote-address>
                  <remote-port>10000</remote-port>
                  <enable-segmentation>false</enable-segmentation>
               </udp-notif-receiver>
            </receiver-instance>
         </receiver-instances>
     </subscriptions>
   </config>
</edit-config>

Note

Segmentation is disabled in this example to keep the initial interoperability test simple. For larger notifications, enable segmentation and configure max-segment-size when both the Publisher and Collector support segmented UDP Notif messages.

Subscription ID Range -- Important, Frequently Missed Constraint

Note

The id key of /subscriptions/subscription is shared between dynamic and configured subscriptions on netconfd-pro. Dynamic subscriptions (establish-subscription) have existed for years and clients generally expect low integer IDs starting at 1. Consequently, current YumaPro releases reserve IDs 1-1000 for dynamic subscriptions and require configured subscriptions to use IDs in the range 1001-2000; a configured subscription outside that range is rejected. IDs 100 and 101, as sometimes shown in generic tutorials, will fail on such a release. The examples below use 1501 and 1502 accordingly.

Configure a Periodic YANG Push Subscription

The following example configures a periodic subscription for the running datastore. The selected data is sent to the netgauze receiver instance by using UDP-Notif transport and JSON encoding.

The period value is in centiseconds. In this example, 1000 means 10 seconds.

The <edit-config> request for this scenario is shown below:

<edit-config>
   <target>
      <running/>
   </target>
   <config>
      <subscriptions xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
         <subscription>
            <id>1502</id>
            <datastore xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push" xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">ds:running</datastore>
            <datastore-xpath-filter xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
                /top-config-list/config-cont
            </datastore-xpath-filter>
            <module-version-subs xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push-revision">
               <name>get2-test</name>
               <revision>2022-03-02</revision>
            </module-version-subs>
            <transport xmlns:unt="urn:ietf:params:xml:ns:yang:ietf-udp-notif-transport">unt:udp-notif</transport>
            <encoding>encode-json</encoding>
            <receivers>
               <receiver>
                  <name>netgauze</name>
                  <receiver-instance-ref xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notif-receivers">netgauze</receiver-instance-ref>
                  </receiver>
               </receivers>
               <periodic xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
                  <period>1000</period>
               </periodic>
         </subscription>
      </subscriptions>
   </config>
</edit-config>

Note

The datastore-xpath-filter examples above /top-config-list/config-cont target the get2-test module, which is a YumaWorks internal regression module bundled with netconfd-pro test suites. It is used here because it produces a deterministic, reproducible dataset for the captured log output. The XPath filter, the referenced module name and revision in module-version-subs, and the namespace declarations should be replaced with the equivalent production YANG module (for example, ietf-interfaces) before this configuration is applied outside of a lab environment.

Expected Publisher behavior after the commit:

  1. The configured subscription is validated.

  2. The receiver state is initialized.

  3. The Publisher sends <subscription-started> to the receiver.

  4. The Publisher sends the first <push-update>.

  5. The Publisher continues to send <push-update> notifications at the configured period.

The server log for the <subscription-started> notification may look like this:

agt_udp_notif: write msg OK ses=5 siz=724
ses: Invoking Send Hook Fn for finish msg ses:5
End UDP-Notif Msg 1 for rcvr netgauze
agt_not: Sent <subscription-started> on datastore subscription '1502' for session '5'
Notification contents:
  ncEvent:notification {
    eventTime 2026-07-10T21:05:29.464048Z
    sn:subscription-started {
      id 1502
      yp:datastore ds:running
      yp:datastore-subtree-filter {
        get2test:top-config-list {
          config-cont (not set)
        }
      }
      encoding sn:encode-json
      yp:periodic {
        period 1000
        anchor-time 2026-07-10T21:05:29Z
      }
      dn:message-publisher-id 1
      ypr:module-version  get2-test {
        name get2-test
        revision 2022-03-02
      }
      ypr:yang-library-content-id 8519
    }
  }

agt_push: Process periodic push_cb: P=1000 tdiff=1000 subid=1502 sid=0
agt_push: Start send Periodic push for subid 1502
ses: Invoking Send Hook Fn for start msg ses:5
Start UDP-Notif Msg 2 for rcvr netgauze
agt_tree_process_val: enter filval: datastore-subtree-filter curval: config curobj: config oper_curval: none
agt_tree: process_val empty return
Send UDP-Notif for rcvr netgauze
udpnotif: HDR: enc=json hdrlen=12 msglen=236 pubid=1 msgid=2
Write UDP-Notif Buff 2 for rcvr netgauze datalen=224
{
 "ietf-notification:notification": {
  "eventTime":"2026-07-10T21:05:39.138199Z",
  "ietf-yang-push:push-update": {
   "id":1502,
   "ietf-distributed-notif:message-publisher-id":1,
   "datastore-contents": {
   }
  }
 }
}

agt_udp_notif: write msg OK ses=5 siz=236
ses: Invoking Send Hook Fn for finish msg ses:5
End UDP-Notif Msg 2 for rcvr netgauze

Note

The datastore-contents object is empty in this <push-update> notification because the target data node has not been created yet.

Note

The field ietf-distributed-notif:message-publisher-id, present in every <push-update> and <push-change-update> payload shown above, originates from draft-ietf-netconf-distributed-notif (Distributed Notification Delivery). It identifies which Publisher instance generated a given notification, which matters when a single logical device exports telemetry from more than one internal publishing process, or when messages from several Publishers are aggregated in a shared Kafka topic and must be attributed back to their source.

Assume the target node is created with the following <edit-config> request:

<edit-config>
 <target>
  <running/>
 </target>
 <config>
  <top-config-list xmlns="http://yumaworks.com/ns/get2-test">
   <id>11</id>
   <config-cont>
    <config-leaf
     xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"
     nc:operation="merge">test3</config-leaf>
   </config-cont>
  </top-config-list>
 </config>
</edit-config>

After the data exists, the <push-update> notification in the netconfd-pro server log may look like this:

Send UDP-Notif for rcvr netgauze
udpnotif: HDR: enc=json hdrlen=12 msglen=373 pubid=1 msgid=2
Write UDP-Notif Buff 2 for rcvr netgauze datalen=361
{
 "ietf-notification:notification": {
  "eventTime":"2026-07-10T21:07:13.140983Z",
  "ietf-yang-push:push-update": {
   "id":1502,
   "ietf-distributed-notif:message-publisher-id":1,
   "datastore-contents": {
    "get2-test:top-config-list": [
      {
       "id":11,
       "config-cont": {
        "config-leaf":"test3"
       }
      }
     ]
   }
  }
 }
}

The NetGauze logging after the subscription is configured may look as follows:

TRACE netgauze_udp_notif_service::actor: [Actor 0-0.0.0.0:10000] decoded udp-notif packet peer=127.0.0.1:38198 message_id=2 publisher_id=1
TRACE netgauze_udp_notif_service::actor: [Actor 0-0.0.0.0:10000] sending udp-notif packet received to all subscribers peer=127.0.0.1:38198 message_id=2 publisher_id=1 subscriber_count=1
TRACE netgauze_udp_notif_service::actor: [Actor 0-0.0.0.0:10000] sent udp-notif message to actor subscriber peer=127.0.0.1:38198 message_id=2 publisher_id=1 actor_subscriber_id=1
TRACE netgauze_yang_push::validation: Decoded UDP-Notif payload, starting the validation step peer=127.0.0.1:38198 message_id=2 publisher_id=1 notification_type="YangPushChangeUpdate"
TRACE netgauze_yang_push::validation: Successfully send UDP-Notif message for the next actor to process peer=127.0.0.1:38198 message_id=2 publisher_id=1 subscription_id=1502 router_content_id="EMPTY" target={ datastore: EMPTY, datastore-xpath-filter: EMPTY } cached_content_id="" notification_type="YangPushChangeUpdate"
TRACE netgauze_collector::yang_push::enrichment: Received Yang Push Change Update Message peer=127.0.0.1:38198 message_id=2 publisher_id=1 subscription_id=1502 router_content_id="EMPTY" target={ datastore: EMPTY, datastore-xpath-filter: EMPTY } notification_type="YangPushChangeUpdate" cached_content_id=""
TRACE netgauze_collector::publishers: Message delivered successfully to kafka

Configure an On-Change YANG Push Subscription

The following example configures an on-change subscription for the running datastore. sync-on-start requests an initial <push-update> when the subscription starts. After that, the Publisher sends <push-change-update> notifications when the selected data changes.

The <edit-config> request for this scenario is shown below:

<edit-config>
   <target>
      <running/>
   </target>
   <config>
     <subscriptions xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
       <subscription>
         <id>1501</id>
         <datastore
           xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push"
           xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">ds:running</datastore>
         <datastore-xpath-filter xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
             /top-config-list/config-cont
         </datastore-xpath-filter>
         <transport xmlns:unt="urn:ietf:params:xml:ns:yang:ietf-udp-notif-transport">unt:udp-notif</transport>
         <encoding>encode-json</encoding>
         <receivers>
           <receiver>
             <name>netgauze</name>
             <receiver-instance-ref
               xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notif-receivers">netgauze</receiver-instance-ref>
           </receiver>
         </receivers>
         <on-change xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push">
           <dampening-period>500</dampening-period>
           <sync-on-start>true</sync-on-start>
         </on-change>
       </subscription>
     </subscriptions>
   </config>
</edit-config>

Note

Operational on-change behavior depends on the server implementation and the enabled YANG Push mode. For simulated operational on-change testing, keep the --push-simop-enabled parameter set to true and use a dampening value that is not smaller than the server's configured minimum.

Whenever the target node is updated, the server sends a <push-change-update> notification to the collector. The server log may look like this:

agt_push: Process on-change push_cb: DP=500 tdiff=800 subid=1501 sid=0
ses: Invoking Send Hook Fn for start msg ses:5
Start UDP-Notif Msg 2 for rcvr netgauze
Send UDP-Notif for rcvr netgauze
udpnotif: HDR: enc=json hdrlen=12 msglen=632 pubid=1 msgid=2
Write UDP-Notif Buff 2 for rcvr netgauze datalen=620
{
 "ietf-notification:notification": {
  "eventTime":"2026-07-10T21:13:41.529318Z",
  "ietf-yang-push:push-change-update": {
   "id":1501,
   "ietf-distributed-notif:message-publisher-id":1,
   "datastore-changes": {
    "ietf-yang-push:yang-patch": {
     "patch-id":"0",
     "edit": [
      {
       "edit-id":"E1",
       "operation":"create",
       "target":"/get2-test:top-config-list=11",
       "value": {
        "get2-test:top-config-list": [
         {
          "id":11,
          "config-cont": {
           "config-leaf":"test3"
          }
         }
        ]
       }
      }
     ]
    }
   }
  }
 }
}

agt_udp_notif: write msg OK ses=5 siz=632
ses: Invoking Send Hook Fn for finish msg ses:5
End UDP-Notif Msg 2 for rcvr netgauze

Retrieve Configured Subscriptions and Receiver Counters

Use a NETCONF <get> request to inspect the current subscription state, configured receiver instances, and UDP Notif delivery counters.

This request is useful after a configured subscription is committed because it shows both the configured subscription data and the operational state that the Publisher maintains for active receivers. The returned data can be used to confirm that the subscription exists, the receiver reference is resolved, and the Publisher is attempting to send notifications to the expected collector.

Use <get> instead of <get-config> for this check because counters and receiver state are operational data.

<get xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <filter type="subtree">
    <subscriptions xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications"/>
  </filter>
</get>

The response may look as follows:

{
    "ietf-subscribed-notifications:subscriptions": {
        "subscription": [
            {
                "id": 1502,
                "ietf-yang-push:datastore": "ietf-datastores:running",
                "ietf-yang-push:datastore-xpath-filter": "/top-config-list/config-cont",
                "transport": "ietf-udp-notif-transport:udp-notif",
                "encoding": "encode-json",
                "configured-subscription-state": "valid",
                "receivers": {
                    "receiver": [
                        {
                            "name": "netgauze",
                            "sent-event-records": "0",
                            "excluded-event-records": "0",
                            "state": "active",
                            "ietf-subscribed-notif-receivers:receiver-instance-ref": "netgauze"
                        }
                    ]
                },
                "ietf-yang-push:on-change": {
                    "dampening-period": 500,
                    "sync-on-start": true
                },
                "ietf-distributed-notif:message-publisher-id": [
                    1
                ],
                "ietf-yang-push-revision:module-version-subs": [
                    {
                        "name": "get2-test",
                        "revision": "2022-03-02"
                    }
                ]
            }
        ],
        "ietf-subscribed-notif-receivers:receiver-instances": {
            "receiver-instance": [
                {
                    "name": "netgauze",
                    "ietf-udp-notif-transport:udp-notif-receiver": {
                        "remote-address": "127.0.0.1",
                        "remote-port": 9999,
                        "enable-segmentation": false
                    }
                }
            ]
        }
    }
}

Delete a Configured Subscription

A configured subscription is removed by deleting the corresponding /subscription list entry from the running datastore. The subscription identifier in the delete request must match the configured subscription that should be stopped.

Deleting the subscription stops the Publisher from sending UDP-Notif messages for that subscription. The receiver instance is not deleted by this operation. This allows the same receiver instance to be reused by other configured subscriptions.

The following example deletes configured subscription 1502:

<edit-config>
   <target>
      <running/>
   </target>
   <config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
      <subscriptions xmlns="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
         <subscription nc:operation="delete"
            xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
            <id>1502</id>
         </subscription>
      </subscriptions>
   </config>
</edit-config>

After the deletion, the netconfd-pro server log may look like this:

***** start commit phase on running for session 7, transaction 906423 *****

Start full commit of transaction 906423: 1 edit on running config
Start invoking commit SIL callback for delete on ietf-subscribed-notifications:subscription
Start key walk for subscription
End key walk for subscription:  retkey:

  id 1502
Enter subscription_edit callback for commit phase
Enter u_sn_subscription_edit callback for commit phase
  id=1502
  update=none
agt_not: Removed live subscription for configured
agt_not: Start delete-subscription callback for subscription 1502
agt_push: Mark subscription 1502 for deletion

UDP-Notif Troubleshooting

No UDP Packets Are Received

This issue usually means that the Publisher is not sending UDP Notif messages, the receiver address or port is incorrect, or packets are blocked before they reach the collector.

Check the following items first:

  • Confirm that the configured remote-address points to the collector host.

  • Confirm that the configured remote-port matches the collector listener.

  • Confirm that the collector is actually listening on the expected UDP port.

  • Confirm that the configured subscription was committed successfully.

  • Confirm that the subscription is present under /subscriptions/subscription.

  • Use tcpdump to confirm whether packets leave the Publisher host or arrive on the collector host.

Example packet capture command:

sudo tcpdump -i any -nn -s 0 -vv udp port 10000

If packets are visible on the Publisher host but not on the collector host, the issue is likely network routing, firewall, container networking, or an incorrect destination address.

If no packets are visible on the Publisher host, the issue is likely the configured subscription, receiver configuration, or subscription activation state.

<subscription-started> Is Not Observed

The <subscription-started> notification is expected when a configured subscription becomes active. It confirms that the Publisher accepted the configured subscription and initialized delivery to the configured receiver.

Check the following items:

  • Confirm that the subscription was created under /subscriptions by using <edit-config>.

  • Confirm that the subscription is a configured subscription, not a dynamic <establish-subscription> request.

  • Confirm that the receiver instance exists and that the subscription references the correct receiver-instance-ref value.

  • Confirm that the configured receiver is not suspended or stuck in a failed delivery state.

  • Check the netconfd-pro server log for subscription validation errors.

  • If the collector was started after the subscription was created, delete and recreate the configured subscription so that startup delivery can be tested from a clean state.

  • Verify the correct subscription ID, must be 1001+ value. Refer to this section: Subscription ID Range -- Important, Frequently Missed Constraint

Dynamic NETCONF subscriptions created with <establish-subscription> are not validated in the same way as configured UDP Notif subscriptions. For this test, the expected path is the configured /subscriptions datastore path.

NetGauze Receives UDP Packets but Cannot Decode or Validate Them

  • Confirm that NetGauze can open a NETCONF session to the Publisher.

  • Confirm the SSH key path and username in the NetGauze config.

  • Confirm that the Publisher exposes YANG Library data and required modules.

  • Remove the NetGauze cache directory after changing YANG modules, draft revisions, SID files, or message encoding.

Example:

rm -rf /tmp/netgauze-udpnotif-cache

This issue usually means that UDP delivery is working, but NetGauze cannot build the correct YANG schema context for the received messages.

NetGauze is not only a UDP listener. In this workflow, it also uses NETCONF access to the Publisher to retrieve YANG Library data, YANG modules, subscription metadata, and schema context. If that NETCONF-side lookup fails, NetGauze may receive packets but fail to decode or validate the message content.

Example cache reset command:

rm -rf /tmp/netgauze-udpnotif-cache
mkdir -p /tmp/netgauze-udpnotif-cache
chmod 700 /tmp/netgauze-udpnotif-cache

For persistent deployments, use a cache directory outside /tmp, such as /var/cache/netgauze/udpnotif.