Internet-Draft YANG-Push v2 October 2026
Wilton, et al. Expires 2 May 2027 [Page]
Workgroup:
Network Configuration
Internet-Draft:
draft-ietf-netconf-yang-push-2-latest
Published:
Intended Status:
Standards Track
Expires:
Authors:
R. Wilton, Ed.
Cisco Systems
H. Keller
Deutsche Telekom
B. Claise
Everything OPS
E. Aries
HPE
J. Cumming
Nokia
T. Graf
Swisscom

YANG Datastore Telemetry (YANG Push version 2)

Abstract

YANG Push version 2 is a YANG datastore telemetry solution, as an alternative lightweight specification to the Subscribed Notifications and YANG Push solution, specifically optimized for the efficient observability of operational data.

About This Document

This note is to be removed before publishing as an RFC.

The latest revision of this draft can be found at https://rgwilton.github.io/draft-yp-observability/draft-ietf-netconf-yang-push-2.html. Status information for this document may be found at https://datatracker.ietf.org/doc/draft-ietf-netconf-yang-push-2/.

Discussion of this document takes place on the Network Configuration Working Group mailing list (mailto:netconf@ietf.org), which is archived at https://mailarchive.ietf.org/arch/browse/netconf/. Subscribe at https://www.ietf.org/mailman/listinfo/netconf/.

Source for this draft and an issue tracker can be found at https://github.com/rgwilton/draft-yp-observability.

Status of This Memo

This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.

Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.

Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."

This Internet-Draft will expire on 2 May 2027.

▲

Table of Contents

1. Document Status

RFC Editor: If present, please remove this section before publication. RFC Editor: Please replace 'RFC XXXX' with the RFC number for this RFC.

Based on the feedback received during the IETF 121 NETCONF session, this document has currently been written as a self-contained lightweight protocol and document replacement for [RFC8639] and [RFC8641], defining a separate configuration data model.

The comparison between YANG Push and YANG Push v2 is now in Appendix A.

Open issues are either now being tracked inline in the text or in Appendix E for the higher level issues.

2. Conventions

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

All YANG tree diagrams used in this document follow the notation defined in [RFC8340].

3. Introduction

[I-D.ietf-nmop-yang-message-broker-integration] describes an architecture for how YANG datastore telemetry, e.g., [RFC8641], can be integrated effectively with message brokers, e.g., [Kafka], that forms part of a wider architecture for a Network Anomaly Detection Framework, specified in [I-D.ietf-nmop-network-anomaly-architecture].

This document specifies "YANG Push v2", an lightweight alternative to Subscribed Notifications [RFC8639] and YANG Push [RFC8641]. YANG Push v2 is a separate YANG datastore telemetry solution, which can be implemented independently or, if desired, alongside [RFC8639] and [RFC8641].

At a high level, YANG Push v2 is designed to solve a similar set of requirements as YANG Push, and it reuses a significant subset of the ideas and base solution from YANG Push. YANG Push v2 defines a separate data model to allow concurrent implementation of both protocols and to facilitate more significant changes in behavior, but many of the data nodes are taken from YANG Push and have the same, or very similar definitions.

The following sections give the background for the solution, and highlight the key ways that this specification differs from the specifications that it is derived from.

3.1. Background and Motivation for YANG Push v2

A push based telemetry solution, as described both in this document and also the YANG Push solution described by [RFC8639] and [RFC8641], is beneficial because it allows operational data to be exported by publishers more immediately and efficiently compared to legacy poll based mechanisms, such as SNMP [RFC3411]. Some further background information on the general motivations for push based telemetry, which equally apply here, can be found in the Motivation (section 1.1) of [RFC8639] and the Introduction (section 1) of [RFC8641]. The remainder of this section is focused on the reasons why a new lightweight version of YANG Push has been specified, and what problems is aims to solve.

Early implementation efforts of the [I-D.ietf-nmop-yang-message-broker-integration] architecture hit issues with using either of the two common YANG datastore telemetry solutions that have been specified, i.e., [gNMI] or YANG Push [RFC8641].

gNMI is specified by the OpenConfig Industry Consortium. It is more widely implemented, but operators report that some inter-operability issues between device implementations cause problems. Many of the OpenConfig protocols and data models are also expected to evolve more rapidly than IETF protocols and models - that are expected to have a more gradual pace of evolution once an RFC has been published.

YANG Push [RFC8641] was standardized by the IETF in 2019, but market adoption has been rather slow. During 2023/2024, when vendors started implementing, or considering implementing, YANG Push, it was seen that some design choices for how particular features have been specified in the solution make it expensive and difficult to write performant implementations, particularly when considering the complexities and distributed nature of operational data. In addition, some design choices of how the data is encoded (e.g., YANG Patch [RFC8072]) make more sense when considering changes in configuration data but less sense when the goal is to export a subset of the operational data off the device in an efficient fashion for both devices (publishers) and clients (receivers).

Hence, during 2024, the vendors and operators working towards YANG telemetry solutions agreed to a plan to implement a subset of [RFC8639] and [RFC8641], including common agreements of features that are not needed and would not be implemented, and deviations from the standards for some aspects of encoding YANG data. In addition, the implementation efforts identified the minimal subset of functionality needed to support the initial telemetry use cases, and areas of potential improvement and optimization to the overall YANG Push telemetry solution (which has been written up as a set of small internet drafts that augment or extend the base YANG Push solution).

Out of this work, consensus was building to specify a cut down version of Subscribed Notifications [RFC8639] and YANG Push [RFC8641] that is both more focussed on the operational telemetry use case and is also easier to implement, achieved by relaxing some of the constraints on consistency on the device, and removing, or simplifying some of the operational features. This has resulted in this specification, YANG Push v2.

The implementation efforts also gave rise to potential improvements to the protocol and encoding of notification messages.

3.2. Complexities in Modelling the Operational State Datastore

The YANG abstraction of a single datastore of related consistent data works very well for configuration that has a strong requirement to be self consistent, and that is always updated, and validated, in a transactional way. But for producers of telemetry data, the YANG abstraction of a single operational datastore is not really possible for devices managing a non-trivial quantity of operational data.

Some systems may store their operational data in a single logical database, yet it is less likely that the operational data can always be updated in a transactional way, and often for memory efficiency reasons such a database does not store individual leaves, but instead semi-consistent records of data at a container or list entry level.

For other systems, the operational information may be distributed across multiple internal nodes (e.g., linecards), and potentially many different process daemons within those distributed nodes. Such systems generally do not, and cannot, exhibit full consistency [Consistency] of the operational data (which would require transactional semantics across all daemons and internal nodes), only offering an eventually consistent [EventualConsistency] view of the data instead.

In practice, many network devices will manage their operational data as a combination of some data being stored in a central operational datastore, and other, higher scale, and potentially more frequently changing data (e.g., statistics or FIB information) being stored elsewhere in a more memory efficient and performant way.

3.3. Complexities for Consumers of YANG Push Data

For the consumer of the telemetry data, there is a requirement to associate a schema with the instance-data that will be provided by a subscription. One approach is to fetch and build the entire schema for the device, e.g., by fetching YANG library, and then use the subscription XPath to select the relevant subtree of the schema that applies only to the subscription. The problem with this approach is that if the schema ever changes, e.g., after a software update, then it is reasonably likely of some changes occurring with the global device schema even if there are no changes to the schema subtree under the subscription path. Hence, it would be helpful to identify and version the schema associated with a particular subscription path, and also to encoded the instance data relatively to the subscription path rather than as an absolute path from the root of the operational datastore.

TODO More needs to be added here, e.g., encoding, on-change considerations. Splitting subscriptions up.

This document proposes a new opt-in YANG-Push encoding format to use instead of the "push-update" and "push-change-update" notifications defined in [RFC8641].

  1. To allow the device to split a subscription into smaller child subscriptions for more efficient independent and concurrent processing. I.e., reusing the ideas from [I-D.ietf-netconf-distributed-notif]. However, all child subscriptions are still encoded from the same subscription point.

3.3.1. Combined periodic and on-change subscription

Sometimes it is helpful to have a single subscription that covers both periodic and on-change notifications.

There are two ways in which this may be useful:

  1. For generally slow changing data (e.g., a device's physical inventory), then on-change notifications may be most appropriate. However, in case there is any lost notification that isn't always detected, for any reason, then it may also be helpful to have a slow cadence periodic backup notification of the data (e.g., once every 24 hours), to ensure that the management systems should always eventually converge on the current state in the network.

  2. For data that is generally polled on a periodic basis (e.g., once every 10 minutes) and put into a time series database, then it may be helpful for some data trees to also get more immediate notifications that the data has changed. Hence, a combined periodic and on-change subscription, would facilitate more frequent notifications of changes of the state, to reduce the need of having to always wait for the next periodic event.

Hence, this document allows a single subscription to be configured as both periodic and on-change.

3.4. Relationships to existing RFCs and Internet Drafts

This document, specifying YANG Push v2, is intended to be a lightweight alternative for [RFC8639] and [RFC8641], but that also incorporates various extensions since those RFCs were written. Often substantial parts of those documents and models have been incorporated almost verbatim, but modified to fit the YANG Push v2 functionality and module structure.

Hence, the authors of this draft would like to sincerely thank and acknowledge the very significant effort put into those RFCs and drafts by authors, contributors and reviewers. In particular, We would like to thank the listed authors of these documents: Eric Voit, Alex Clemm, Alberto Gonzalez Prieto, Einar Nilsen-Nygaard, Ambika Prasad Tripathy, Balazs Lengyel, Alexander Clemm, Benoit Claise, Qin Wu, Qiufang Ma, Alex Huang Feng, Thomas Graf, Pierre Francois.

3.4.1. RFC 8639 and RFC 8641

This document is primarily intended to be a lightweight alternative for [RFC8639] and [RFC8641], but it intentionally reuses substantial parts of the design and data model of those RFCs.

YANG Push v2 is defined using a separate module namespace, and hence can be implemented independently or, if desired, alongside [RFC8639] and [RFC8641], and the various extensions to YANG Push.

A more complete description of the main differences in YANG Push v2 compares to [RFC8639] and [RFC8641] is given in Appendix A.

3.4.2. [I-D.ietf-netconf-notif-envelope] and RFC 5277

All of the notifications defined in this specification, i.e., both the datastore update message and subscription lifecycle update notifications (Section 9.2), use the notification envelope defined in Section 7.1 and the ietf-yang-push-2 YANG module (Section 14.2). This envelope is derived from the work in [I-D.ietf-netconf-notif-envelope], but is defined independently in this document.

As such, this specification does not make any use of the notification format defined in [RFC5277], but this does not prevent implementations using [RFC5277] format notifications for other YANG notifications, e.g., for the "NETCONF" event stream defined in [RFC5277].

3.4.3. RFC 9196 and [I-D.netana-netconf-yp-transport-capabilities]

[RFC9196] defines the ietf-system-capabilities module as a common structure that other modules can augment with capability data. It also defines the ietf-notification-capabilities module, which describes capabilities for YANG Push as specified in [RFC8641], but those capabilities do not apply to YANG Push v2. Instead, this document defines YANG Push v2 capabilities in the ietf-yang-push-2-capabilities module, which augments ietf-system-capabilities directly (see Section 10).

The generic transport capabilities defined in [I-D.netana-netconf-yp-transport-capabilities] have been incorporated into the ietf-yang-push-2 YANG module, to augment YANG Push v2 transport capabilities and to use the different identities.

3.4.4. [I-D.ietf-netconf-https-notif] and [I-D.ietf-netconf-udp-notif]

The ietf-yang-push-2 YANG module has subsumed and extended the receivers data model defined in the ietf-subscribed-notif-receivers YANG module defined in [I-D.ietf-netconf-https-notif].

The overall YANG Push v2 solution anticipates and requires new bis versions of both of these transports documents that augment into the receivers/receiver/transport-type choice statement, and also augment the transport identity defined in the ietf-yang-push-2 data model.

3.4.5. [I-D.ietf-netconf-distributed-notif]

This document builds on the architecture of [I-D.ietf-netconf-distributed-notif]. The YANG Push v2 distributed-notification behavior is fully defined in Section 13, with changes to the message structure and tighter restrictions on publisher ID allocation.

4. YANG Push v2 Overview

This document specifies a lightweight telemetry solution that provides a subscription service for updates to the state and changes in state from a chosen datastore.

Subscriptions specify when notification messages (also referred to as updates) should be sent, what data to include in the update records, and where those notifications should be sent.

A YANG Push v2 subscription comprises:

If a subscription is valid and acceptable to the publisher, and if a suitable connection can be made to the receiver associated with a subscription, then the publisher will enact the subscription, periodically sampling or monitoring changes to the chosen datastore's data nodes that match the selection filter. Push updates are subsequently sent by the publisher to the receiver, as per the terms of the subscription.

Subscriptions may be set up in two ways: either through configuration - or YANG RPCs to create and manage dynamic subscriptions. These two mechanisms are described in Section 9.

Changes to the state of subscription are notified to receivers as subscription lifecycle notifications. These are described in Section 9.2.

Security access control mechanisms, e.g., NACM {RFC8341}} can be used to ensure the receivers only get access to the information for which they are allowed. This is further described in Section 17.

While the functionality defined in this document is transport agnostic, transports like the Network Configuration Protocol (NETCONF) [RFC6241] or RESTCONF [RFC8040] can be used to configure or dynamically signal subscriptions. In the case of configured subscription, the transport used for carrying the subscription notifications is entirely independent from the protocol used to configure the subscription, and other transports, e.g., [I-D.ietf-netconf-udp-notif] defines a simple UDP based transport for Push notifications. Transport considerations are described in Section 8.2. TODO the reference to draft-ietf-netconf-udp-notif isn't right, it wouldn't be that draft, but a -bis version of it. James is querying whether we need this at all

TODO Introduce capabilities and operational monitoring

This document defines a YANG data model, that includes RPCs and notifications, for configuring and managing subscriptions and associated configuration, and to define the format of a update notification message. The YANG model is defined in Section 14.2 and associated tree view in Section 14.1. The YANG data model defined in this document conforms to the Network Management Datastore Architecture defined in [RFC8342].

5. Definitions

This document reuses the terminology defined in [RFC7950], [RFC8341], [RFC8342], [RFC8639] and [RFC8641].

The following terms are taken from [RFC8342]:

The following terms are taken from [RFC8639]:

The following terms are taken from [RFC8641]:

This document introduces the following terms:

The following terms from [I-D.ietf-netconf-distributed-notif] are reused here; their definitions are given below for completeness:

6. Subscription paths and selection filters

A key part of a subscription is to select which data nodes should be monitored, and so a subscription must specify both the selection filters and the datastore against which these selection filters will be applied. This information is used to choose, and subsequently push, update notifications from the publisher's datastore(s) to the subscription's receiver.

Filters can either be defined inline within a configured subscription (Figure 22), a dynamic subscription's establish-subscription RPC (Figure 15), or as part of the datastore-telemetry/filters container (Figure 1) which can then be referenced from a configured or dynamic subscription.

The following selection filter types are included in the YANG Push v2 data model and may be applied against a datastore:

These filters are used as selectors that define which data nodes fall within the scope of a subscription. A publisher MUST support YPath filters, and MAY also support subtree or XPath filters.

For both YPath and XPath based filters, each filter may define a list of path expressions. Each of these filter path expressions MAY be processed by the publisher independently, and if two or more filter path expressions end up selecting overlapping data nodes then the publisher MAY notify duplicate values for those data nodes, but the encoded data that is returned MUST always be syntactically valid, i.e., as per section 5.3 of [RFC8342].

6.1. YPath definition

A YPath represents a simple path into a YANG schema tree, where some of the list key values may be constrained.

A general YPath format is proposed in [I-D.jgc-netmod-yang-path]. The syntax defined below remains the current syntax used by this document, but the intention is to align it with the general YPath format. Alignment requires resolving differences in string quoting, multi-key predicate syntax, relative paths, and regular-expression semantics.

It is encoded in the similar format to the YANG JSON encoding for instance-identifier, section 6.11 of [RFC7951], except with more flexibility on the keys, in that keys may be left-out or be bound to a regular expression filter.

The rules for constructing a YPath are:

  • A YPath is a sequence of data tree path segment separated by a '/' character. If the path starts with a '/' then it is absolute path from the root of the schema, otherwise it is a relative path, where the context of the relative path must be declared.

  • Constraints on key values may be specified within a single pair of '[' ']' brackets, where:

    • keys may be given in any order, and may be omitted, in which case they match any value. Key matches are separated by a comma (,) with optional space character either side.

    • key match is given by <key>=<value>, with optional space characters either side of the equals (=), and value is specified as:

      • '<value>', for an exact match of the key's value. Single quote characters (') must be escaped with a backslash (\).

      • r'<reg-expr>', for a regex match of the key value using [RFC9485], and where the regular-expression is a full match of the string, i.e, it implicit anchors to the start and end of the value.

Some examples of YPaths:

  • /ietf-interfaces:interfaces/interface[name='eth0']/ietf-ip:ipv6/ip - which identifies is 'ipv6/ip' data node in the ietf-ip module for the 'eth0' interface.

  • /ietf-interfaces:interfaces/interface[name=r'eth.*']/ietf-ip:ipv6/ip - which identifies all interfaces with a name that start with "eth".

  • /example:multi-keys-list[first-key='foo', second-key=r'bar.*'] - which identifies all entries in the 'multi-keys-list, where the first-key matches foo, and the second-key starts with bar.

  • /ietf-interfaces:interfaces/interface - which identifies the interface list data node in the ietf-interfaces module for all interfaces. I.e., the interface list 'name' key is unrestricted.

  • /ietf-interfaces:interfaces/interface[] - alternative form of the previous YPath.

6.2. The "filters" Container

The "filters" container maintains a list of all datastore subscription filters that persist outside the lifecycle of a single subscription. This enables predefined filters that may be referenced by more than one configured or dynamic subscription.

Below is a tree diagram for the "filters" container. All objects contained in this tree are described in the YANG module in Section 14.

module: ietf-yang-push-2-config
  +--rw datastore-telemetry!
     +--rw filters
        +--rw filter* [name]
           +--rw name             string
           +--rw (filter)
              +--:(path)
              |  +--rw path       ypath
              +--:(subtree)
              |  +--rw subtree    <anydata> {yp2:subtree}?
              +--:(xpath)
                 +--rw xpath      yang:xpath1.0 {yp2:xpath}?

  augment /yp2:subscription-started/yp2:target:
    +-- filter-ref?   filter-ref
  augment /yp2:subscription-modified/yp2:target:
    +-- filter-ref?   filter-ref
Figure 1

6.3. Decomposing Subscription Filters

In order to address the issues described in Section 3.2, YANG Push v2 allows for publishers to send subtrees of data nodes in separate update notifications, rather than requiring that the subscription data be returned as a single datastore update notification covering all data nodes matched by the subscription filter. This better facilitates publishers that internally group some of their operational data fields together into larger structures for efficiency, and avoids publishers or receivers having to consume potentially very large notification messages. For example, each entry in the /ietf-interfaces:interface/interface list could be represented as an object of data internally within the publisher. In essence, a client specified subscription filter can be decomposed by a publisher into more specific non-overlapping filters that are then used to return the data.

In particular:

  1. A Publisher MAY decompose a client specified subscription filter path into a set of non-overlapping subscription filter paths that collectively cover the same data. The publisher is allowed to return data for each of these decomposed subscription filter paths in separate update notification messages, each with separate, perhaps more precise, observation-time timestamps, but all using the same notification event-time.

  2. A Publisher MAY split large lists into multiple separate update messages, each with separate observation-time timestamps, but all using the same notification event-time. E.g., if a device has 10,000 entries in a list, it may return them in a single response, or it may split them into multiple smaller messages, perhaps for 500 interfaces at a time.

To ensure that clients can reasonably process data returned via decomposed filters then:

  1. update notifications MUST identify the target paths of the supplied data. When a periodic or resync collection is split across messages, receivers MUST wait for complete or update-complete before inferring deletions from the absence of subscribed data in that collection.

7. Datastore Event Streams

In YANG Push v2, a subscription, based on the selected filters, will generate a ordered stream of datastore update records that is referred to as an event stream. Each subscription logically has a different event stream of update records, even if multiple subscriptions use the same filters to select datastore nodes.

As YANG-defined event records are created by a system, they may be assigned to one or more streams. The event record is distributed to a subscription's receiver where (1) a subscription includes the identified stream and (2) subscription filtering does not exclude the event record from that receiver.

Access control permissions may be used to silently exclude event records from an event stream for which the receiver has no read access. See [RFC8341], Section 3.4.6 for an example of how this might be accomplished. Note that per Section 2.7 of this document, subscription state change notifications are never filtered out. TODO, filtering and NACM filtering should be dependent on whether it is a configured or dynamic subscription.

If subscriber permissions change during the lifecycle of a subscription and event stream access is no longer permitted, then the subscription MUST be terminated. TODO, check this

Event records SHALL be sent to a receiver in the order in which they were generated. I.e., the publisher MUST not reorder the events when enqueuing notifications on the transport session, but there is no guarantee of delivery order.

Event records MUST NOT be sent before a subscription-started notification (Section 9.2.1) or after a subscription-terminated notification (Section 9.2.3).

7.1. Notification Envelope

All YANG Push v2 notification messages MUST use the envelope structure defined in the ietf-yang-push-2 YANG module (Section 14.2). This applies to update, update-complete, and all subscription lifecycle notifications (Section 9.2). All messages MUST include the event-time, hostname, sequence-number, and contents nodes. The publisher-id MAY be excluded if it matches the default value (0), otherwise it MUST be included.

  structure envelope:
    +-- event-time         yang:date-and-time
    +-- hostname           inet:host-name
    +-- publisher-id?      uint32
    +-- sequence-number    yang:counter32
    +-- extensions
    +-- contents           <anydata>
Figure 2: YANG Push v2 notification envelope

Publishers SHOULD encode the envelope fields in the order in which they are defined in the ietf-yang-push-2 YANG module, placing all envelope header fields, including the extensions container and its fields, before contents. However, some encodings, such as JSON [RFC7951], do not guarantee field ordering. For example, reprocessing JSON within a telemetry data pipeline may reorder the fields. Receivers SHOULD NOT rely on the order of envelope fields unless they can be confident that the ordering has not changed since publication.

The normative field definitions are given in the YANG module. The fields can be summarized as:

  • event-time - the time the telemetry infrastructure began processing the collection, on-change event, or subscription lifecycle event.

  • hostname - the hostname identifying the network node that published the notification.

  • publisher-id - identifies the publishing process within the network node. The default is 0, which identifies the Publisher Parent (Section 13).

  • sequence-number - a counter maintained independently for each publisher within a subscription. It starts at 1, increments by 1 for each notification from that publisher for that subscription, and wraps from 4294967295 to 0 and continues.

  • extensions - a container reserved for future envelope metadata extensions.

  • contents - the notification carried by the envelope.

The contents anydata node MUST contain exactly one notification, identified by the name of its YANG notification statement and the namespace of the module defining that statement. The notification's data node values are carried unchanged.

Sequence numbers are tracked separately for each combination of hostname, subscription id, and publisher-id (including the default publisher ID of 0). The counter covers all notification types sent by that publisher for that subscription, including lifecycle and update-complete notifications. It continues across collections and subscription modifications without resetting while that publisher remains part of the subscription. A newly created publisher starts its own counter at 1. A publisher removed from and subsequently re-added to a subscription MUST be allocated a new publisher-id. A removed publisher-id MUST NOT be reused within that subscription's lifetime. Terminating and recreating a subscription starts a new lifetime and new counters, even if the subscription ID is reused.

For periodic and resynchronization collections, event-time records when the telemetry infrastructure starts processing the collection. For an on-change event, it records when the telemetry infrastructure starts processing the notification of that change. All notification messages belonging to the same collection or on-change event MUST carry the same event-time, including messages from different publishing processes. Any update-complete notification for a periodic or resynchronization collection MUST carry that collection's event-time. For a subscription lifecycle notification, event-time records when processing of that lifecycle event began.

The common event-time correlates messages from one collection or on-change event. It does not imply that the reported data was read or changed at that instant. A completed periodic or resynchronization collection comprises data collected for that operation, potentially at different observation times.

The following example illustrates a fully encoded update notification defined in the ietf-yang-push-2 YANG module and carried in the contents node.

{
  "ietf-yang-push-2:envelope": {
    "event-time": "2024-10-10T08:00:05.22Z",
    "hostname": "example-router",
    "sequence-number": 3219,
    "contents": {
      "update": {
        "id": "interfaces",
        "path-prefix": "/ietf-interfaces:interfaces",
        "snapshot-type": "periodic",
        "observation-time": "2024-10-10T08:00:05.11Z",
        "updates": [
          {
            "target": "interface",
            "update": {
              "interface": [
                {
                  "name": "eth0",
                  "type": "iana-if-type:ethernetCsmacd",
                  "enabled": true,
                  "oper-status": "up",
                  "admin-status": "up"
                },
                {
                  "name": "eth1",
                  "type": "iana-if-type:ethernetCsmacd",
                  "enabled": true,
                  "oper-status": "up",
                  "admin-status": "up"
                }
              ]
            }
          }
        ],
        "complete": true
      }
    }
  }
}
Figure 3: Example of update notification including notification envelope

Encoding rules for the envelope and its contents are specified in Section 8.3.

7.2. Event Records

A single update record is used for all datastore notifications. It is used to report the current state of a set of data nodes at a given target path for either periodic, on-change, or resync notifications, and also for on-change notifications to indicate that the data node at the given target path has been deleted.

All notification types use the same updates list. For periodic and resync snapshots, each entry in the updates list MUST contain an update element and MUST NOT contain a delete element. The delete operation MUST only be used for on-change notifications. This restriction also applies to resync snapshots for on-change subscriptions.

The schema for this notifications is given in the following tree diagram:

    +---n update
    |  +--ro id?                 subscription-id
    |  +--ro path-prefix?        string
    |  +--ro snapshot-type       enumeration
    |  +--ro observation-time?   yang:date-and-time
    |  +--ro updates* [target]
    |  |  +--ro target          string
    |  |  +--ro (data)
    |  |     +--:(update)
    |  |     |  +--ro update?   <anydata>
    |  |     +--:(delete)
    |  |        +--ro delete?   boolean
    |  +--ro complete?           boolean
Figure 4: 'update' notification

The normative definitions for the notifications fields are given in the YANG module in Section 14. The fields can be informatively summarized as:

  • id - identifies the subscription the notification relates to.

  • path-prefix - provides the common prefix for all target values in the notification. If present, it MUST be an absolute path from the schema root, MUST start with '/', and MUST contain at least one path segment. Neither an empty string nor '/' is a valid path-prefix.

  • snapshot-type - this indicates what type of event causes the update message to be sent. I.e., a periodic collection, an on-change event, or a resync collection.

  • observation-time - the time that the data was sampled for a periodic or resynchronization update, or when the on-change event occurred that caused the message to be published.

  • target - identifies the data being updated or deleted. It MUST be present in every updates entry and MUST NOT be empty. If path-prefix is absent, target MUST be an absolute path from the schema root, starting with '/'. Otherwise, target MUST be a relative path and MUST NOT start with '/'. To act on the entire datastore, path-prefix is omitted and target is '/'.

  • data - A mandatory choice of exactly one operation, with delete available only for on-change notifications:

    • update - supplies current values to create or update in the receiver's view. Existing leaf and leaf-list values supplied in the payload are replaced; containers and list entries are updated recursively, with keyed list entries identified by their keys. Required list keys are included. For on-change notifications, omitted descendants remain unchanged and absence of a data node does not implicitly imply deletion of that data node.

    • delete - a boolean with a default value of false. When true, it indicates that the data node at target and all its descendants no longer exist and should be removed from the receiver's view. When false, no deletion is indicated. Deleting data that is already absent has no effect. This operation is used for on-change deletion events.

  • complete - applies only to periodic and resync updates and defaults to false. When true, it indicates that this message completes the publisher's contribution to the collection, and is semantically equivalent to sending a separate update-complete notification. Publishers MUST NOT include this flag in on-change updates.

The full absolute target-path is constructed by prepending path-prefix, if present, to target, using a single '/' between path segments. Without a path-prefix, target itself is the full target-path. An operation acts on the entire datastore when its full target-path is '/'. This is represented by omitting path-prefix and setting target to '/'. Examples of valid and invalid path-prefix and target combinations are given in Appendix C.

The observation-time describes the source data, with the greatest accuracy available from the source. For periodic and resynchronization updates, it records the time the data was sampled. If the data was previously sampled by a producer and cached, the timestamp SHOULD represent that original sampling. For on-change updates, it records when the underlying event (creation, modification, or deletion) first occurred, rather than when the telemetry infrastructure received or processed the change notification.

Separate messages from one collection or on-change event may have different observation-time values while sharing the same event-time.

For periodic and resynchronization events, the observation-time for data sampled in response to the collection should be the same as or later than the event-time, because collection processing triggers the sampling. If a collection instead reports previously sampled, cached data, its original observation-time may precede the event-time, as described above.

For on-change events, the event-time should be the same as or later than the observation-time, because the underlying change occurs before the telemetry infrastructure processes that change.

As per the structure of the update notification, a single notification MAY provide updates for multiple targets. The updates list MUST NOT contain duplicate target values within a single notification. The target leaf is the list key, so duplicate values are invalid YANG, including when one entry specifies update and another specifies delete for the same target.

7.2.1. Handling Particular YANG Data Nodes

Empty non-presence containers SHOULD be omitted to minimize message size and receiver processing. Presence containers MUST be included when they exist within the reported data, even if empty, and MUST be omitted when they do not exist. For on-change notifications, deletion of a presence container MUST be reported by an explicit delete of that container or an ancestor.

Leaf-lists are reported as a single data node. For on-change notifications, when entries of a subscribed leaf-list are added, removed, modified, or reordered and the leaf-list remains non-empty, the publisher MUST send an update whose target identifies the leaf-list or an ancestor, and whose payload includes the complete current sequence of entries, preserving YANG ordering. The supplied sequence replaces the receiver's previous sequence for that leaf-list. Updates or deletions targeting individual leaf-list entries MUST NOT be sent.

When the final entry is removed, the publisher MUST report an explicit delete of the leaf-list or an ancestor. The leaf-list then has no entries and does not exist in the receiver's view. An update of an enclosing subtree recursively updates the supplied data; omitted descendants remain unchanged. Consequently, omission of a presence container or leaf-list from such an update does not report its deletion.

For a list that has no keys, the position (index) of each list entry is used to identify that entry. TODO: Extend the YPath representation defined in Section 6.1 to identify entries of a non-keyed list and specify the index base and index encoding.

7.3. Types of subscription event monitoring

Subscription can either be based on sampling the requested data on a periodic cadence or being notified when the requested data changes. In addition, this specification allows for subscriptions that both notify on-change and also with a periodic cadence, which can help ensure that the system eventually converges on the right state, even if on-change notification were somehow lost or mis-processed anywhere in the data processing pipeline.

The schema for the update-trigger container is given in the following tree diagram:

module: ietf-yang-push-2-config
  +--rw datastore-telemetry!
     +--rw subscriptions
        +--rw subscription* [id]
           +--rw update-trigger
              +--rw periodic!
              |  +--rw period         centiseconds
              |  +--rw anchor-time?   yang:date-and-time
              +--rw on-change! {on-change}?
                 +--rw sync-on-start?   boolean

  augment /yp2:subscription-started/yp2:target:
    +-- filter-ref?   filter-ref
  augment /yp2:subscription-modified/yp2:target:
    +-- filter-ref?   filter-ref
Figure 5: 'update-trigger' container

The normative definitions for the update-trigger fields are given in the ietf-yang-push-2 YANG module in Section 14. They are also described in the following sections.

7.4. Periodic events

In a periodic subscription, the data included as part of an update record corresponds to data that could have been read using a retrieval operation. Only the state that exists in the system at the time that it is being read is reported, periodic updates never explicitly indicate whether any data-nodes or list entries have been deleted. Instead, receivers must infer deletions from data nodes missing from the complete snapshot provided for a particular collection event.

Periodic and resync notifications carry snapshot data using only update elements in the updates list. Publishers MUST NOT send delete elements in these notifications. Receivers should ignore any delete elements received in periodic or resync notifications. An individual notification may contain only part of the subscribed data. Receivers MUST NOT infer deletion from an omitted data node until the complete snapshot for the collection has been received, as indicated by complete or update-complete. Deletion inference applies only to the subscribed data covered by that collection.

For periodic subscriptions, triggered updates will occur at the boundaries of a specified time interval. These boundaries can be calculated from the periodic parameters:

  • a period that defines the duration between push updates.

  • an anchor-time; update intervals fall on the points in time that are a multiple of a period from an anchor-time. If an anchor-time is not provided, then the publisher chooses a suitable anchor-time, e.g., perhaps the time that the subscription was first instantiated by the publisher.

The anchor time and period are particularly useful, in fact required, for when the collected telemetry data is being stored in a time-series database and the subscription is setup to ensure that each collection is placed in a separate time-interval bucket.

Periodic update notifications are expected, but not required, to use a single target per update notification.

7.5. On-Change events

An on-change subscription monitors the subscribed data for any changes. An update notification is sent whenever any change in the monitored data is detected, with updates/update used to indicate new or changed values and updates/delete used to indicate data nodes that have been deleted.

Each entry in the updates list identifies a data node (i.e., list entry, container, leaf or leaf-list), via the target, that either has come into existence, has changes to its state, or has been deleted.

New or changed values are reported using the update element of an updates entry. The payload SHOULD only report the state that has changed (including any required list keys). Omitting a descendant data node from an update payload does not delete it. The payload MAY include additional unchanged data nodes if the publisher is unable to optimize the on-change update message, but this may incur higher processing overheads for the receiver.

An on-change deletion MUST be reported using a delete entry whose target identifies the deleted data node or subtree. If a descendant of an updated subtree is deleted, it requires a separate delete entry at that descendant's path. This entry MAY be included in the same notification as other updates entries.

Within a subscription, individual publishers (as identified by publisher-id) MUST preserve the causal order of changes affecting the same data node in the sequence-number ordering of the corresponding on-change update notifications. Receivers MUST process these notifications in sequence-number order, accounting for sequence-number wraparound. Successive notifications affecting the same data node normally have increasing observation-time values, but may have the same observation-time if the timestamp resolution is insufficient to assign distinct times to the changes. These values are therefore non-decreasing. These ordering requirements apply across new data nodes, changed values, and deletions.

Within an update notification, receivers MAY process the entries in the updates list in any order. Consequently, within a single notification, the updates list MUST NOT contain duplicate target values, including when one entry specifies update and another specifies delete for the same path. The list MUST NOT contain both a delete entry for a data node and an update entry whose target identifies a descendant of that deleted node.

On-change subscriptions also support the following additional parameters:

  • sync-on-start defines whether or not a complete snapshot of all subscribed data is sent at the start of a subscription. Such early synchronization establishes the frame of reference for subsequent updates. For each data node covered by an on-change with sync-on-start subscription, then an sync-on-start update notification containing the current state MUST be sent before any on-change update notifications for those same data nodes. However, sync-on-start and on-change update notifications may be interleaved for different data-nodes under the subscription. Unsolicited sync-on-start update notifications MUST NOT be sent, they MUST only be sent after a subscription has started.

7.5.1. On-Change Notifiable Datastore Nodes

Publishers are not required to support on-change notifications for all data nodes, and they may not be able to generate on-change updates for some data nodes. Possible reasons for this include:

  • the value of the datastore node changes frequently (e.g., the in-octets counter as defined in [RFC8343]),

  • small object changes that are frequent and meaningless (e.g., a temperature gauge changing 0.1 degrees),

  • or no implementation is available to generate a notification when the source variable for a particular data node has changed.

In addition, publishers are not required to notify every change or value for an on-change monitored data node. Instead, publishers MAY limit the rate at which changes are reported for a given data node, i.e., effectively deciding the interval at which an underlying value is sampled. If a data node changes value and then reverts back to the original value within a sample interval then the publisher MAY not detect the change and it would go unreported. However, if the data node changes to a new value after it has been sampled, then the change and latest state MUST be reported to the receiver. In addition, if a client was to query the value (e.g., through a NETCONF get-data RPC) then they MUST see the same observed value as would be notified.

To give an example, if the interface link state reported by hardware is changing state hundreds of times per second, then it would be entirely reasonable to limit those interface state changes to a much lower cadence, e.g., perhaps every 100 milliseconds. In the particular case of interfaces, there may also be data model specific forms of more advanced dampening that are more appropriate, e.g., that notify interface down events immediately, but rate limit how quickly the interface is allowed to transition to up state, which overall acts as a limit on the rate at which the interface state may change, and hence also act as a limit on the rate at which on-change notifications could be generated.

The information about what nodes support on-change notifications is reported using the capabilities operational data model. This is further described in Section 10.

7.5.2. On-Change Considerations

On-change subscriptions allow receivers to receive updates whenever changes to targeted objects occur. As such, on-change subscriptions are particularly effective for data that changes infrequently but for which applications need to be quickly notified, with minimal delay, whenever a change does occur.

On-change subscriptions tend to be more difficult to implement than periodic subscriptions. Accordingly, on-change subscriptions may not be supported by all implementations or for every object.

Whether or not to accept or reject on-change subscription requests when the scope of the subscription contains objects for which on-change is not supported is up to the publisher implementation. A publisher MAY accept an on-change subscription even when the scope of the subscription contains objects for which on-change is not supported. In that case, updates are sent only for those objects within the scope of the subscription that do support on-change updates, whereas other objects are excluded from update records, even if their values change. In order for a subscriber to determine whether objects support on-change subscriptions, objects are marked accordingly on a publisher. Accordingly, when subscribing, it is the responsibility of the subscriber to ensure that it is aware of which objects support on-change and which do not. For more on how objects are so marked, see Section 3.10. TODO Is this paragraph and the one below still the right choice for YANG Push v2?

Alternatively, a publisher MAY decide to simply reject an on-change subscription if the scope of the subscription contains objects for which on-change is not supported. In the case of a configured subscription, the publisher MAY keep the subscription in inactive state.

7.6. Combined periodic and on-change subscriptions

A single subscription may created to generate notifications both when changes occur and on a periodic cadence. Such subscriptions are equivalent to having separate periodic and on-change subscriptions on the same path, except that they share the same subscription-id and filter paths.

7.7. Streaming Update Examples

Figure 6 provides an example of a notification message for a subscription tracking the operational status of interface (per [RFC8343]). This notification message is encoded using JSON [RFC7951].

{
  "ietf-yang-push-2:update": {
    "id": "interfaces",
    "path-prefix": "/ietf-interfaces:interfaces",
    "snapshot-type": "periodic",
    "observation-time": "2024-10-10T08:00:05.11Z",
    "updates": [
      {
        "target": "interface",
        "update": {
          "interface": [
            {
              "name": "eth0",
              "type": "iana-if-type:ethernetCsmacd",
              "enabled": true,
              "oper-status": "up",
              "admin-status": "up"
            },
            {
              "name": "eth1",
              "type": "iana-if-type:ethernetCsmacd",
              "enabled": true,
              "oper-status": "up",
              "admin-status": "up"
            }
          ]
        }
      }
    ],
    "complete": false
  }
}
Figure 6: Example periodic update message

Figure 7 provides an example of an on-change notification message for the same subscription. The eth0 update includes only the fields that changed: enabled and oper-status. The eth1 interface has been deleted.

{
  "ietf-yang-push-2:update": {
    "id": "interfaces",
    "path-prefix": "/ietf-interfaces:interfaces",
    "snapshot-type": "on-change",
    "observation-time": "2025-10-10T08:16:06.11Z",
    "updates": [
      {
        "target": "interface[name='eth0']",
        "update": {
          "enabled": false,
          "oper-status": "down"
        }
      },
      {
        "target": "interface[name='eth1']",
        "delete": true
      }
    ]
  }
}
Figure 7: Example on-change update and delete message

8. Receivers, Transports, and Encodings

8.1. Receivers

Every subscription is associated with a receiver, which identifies the destination host, transport and encoding settings, where all notifications for a subscription are sent.

For configured subscriptions there is no explicit association with an existing transport session, and hence the properties associated with the receiver are explicitly configured, as described in Section 8.1.1.

For dynamic subscriptions, the receiver, and most associated properties are implicit from the session on which the dynamic subscription was initiated, as described in Section 8.1.2.

8.1.1. Receivers for Configured Subscriptions

For configured subscriptions, receivers are configured independently from the subscriptions and then referenced from the subscription configuration.

Below is a tree diagram for datastore-telemetry/receivers container. All objects contained in this tree are described in the YANG module in Section 14.2.

These parameters identify how to connect to each receiver. For each subscription, the publisher uses the referenced receiver configuration to establish transport connectivity to the receiver.

module: ietf-yang-push-2-config
  +--rw datastore-telemetry!
     +--rw receivers
        +--rw receiver* [name]
           +--rw name                      string
           +--rw encoding                  yp2:encoding
           +--rw dscp?                     inet:dscp
           +---x reset
           +--rw (notification-message-origin)?
           |  +--:(interface-originated)
           |  |  +--rw source-interface?   if:interface-ref
           |  |          {interface-designation}?
           |  +--:(address-originated)
           |     +--rw source-vrf?         leafref {supports-vrf}?
           |     +--rw source-address?     inet:ip-address-no-zone
           +--rw (transport-type)

  augment /yp2:subscription-started/yp2:target:
    +-- filter-ref?   filter-ref
  augment /yp2:subscription-modified/yp2:target:
    +-- filter-ref?   filter-ref
Figure 8: datastore-telemetry/receivers container

Each configured receiver has the following associated properties:

  • a name to identify and reference the receiver in the subscription configuration.

  • a transport, which identifies the transport protocol to use for all connections to the receiver.

    • any transport-specific related parameters, some of which may be mandatory, others optional to specify, e.g., DSCP. There are likely to be various data nodes related to establishing appropriate security and encryption.

  • an encoding used for both the envelope and contents of all notification messages sent to the receiver (Section 8.3).

  • optional parameters to identify where traffic should egress the publisher:

    • a source-interface, identifying the egress interface to use from the publisher, implicitly choosing the source IP address and VRF.

    • a source-vrf, identifying the Virtual Routing and Forwarding (VRF) instance on which to reach receivers. This VRF is a network instance as defined in [RFC8529]. Publisher support for VRFs is optional and advertised using the supports-vrf feature.

    • a source-address address, identifying the IP address to source notification messages from.

    If none of the above parameters are set, the publisher MAY choose which interface(s) and address(es) to source subscription notifications from.

This specification is transport independent, e.g., see Section 8.2, and thus the YANG module defined in Section 14.2 cannot directly define and expose these transport parameters. Instead, receiver-specific transport connectivity parameters MUST be configured via transport-specific augmentations to the YANG choice node /datastore-telemetry/receivers/receiver/transport-type.

A publisher supporting configured subscriptions clearly must support at least one YANG data model that augments transport connectivity parameters onto /datastore-telemetry/receivers/receiver/transport-type. For an example of a similar such augmentation (but for YANG Push), see [I-D.ietf-netconf-udp-notif]. TODO, this reference and text will need to be updated to a UDP-notif bis document, that augments the new YANG Push v2 receiver path.

8.1.2. Receivers for Dynamic Subscriptions

For dynamic subscriptions, each subscription has a single receiver that is implicit from the host that initiated the establish-subscription RPC, reusing the same transport session for all subscription notifications.

Hence most receiver parameters for a dynamic subscription, e.g., related to the transport, are implicitly determined and cannot be explicitly controlled.

Dynamic subscriptions MAY specify DSCP Marking (see Section 8.2.1.1) for the telemetry notifications in the establish-subscription RPC (see Figure 15).

8.1.3. Receiver Session States and State Machine

Each subscription will need to establish a subscription to the specified receiver. Multiple subscriptions may share one or more transport sessions to the same receiver.

A receiver in YANG Push v2 can be in one of the following states:

  • Configured: The receiver has been configured on the publisher, but the receiver is not referenced by any valid subscriptions and hence there is no attempt to establish a connection to the receiver.

  • Connecting: The receiver has at least one associated subscription and the publisher is attempting to establish a transport session and complete any required security exchanges, but this process has not yet succeeded.

  • Active: The receiver has at least one associated subscription, a transport session has been established (if required), security exchanges have successfully completed, and the publisher is able to send notifications to the receiver.

The state transitions for a receiver are illustrated below:

                    .-------------------.
                    |                   |
                    |    Configured     |
                    |                   |
                    '-------------------'
                            |  ^
  Receiver is referenced by |  |  No configured subscriptions
  1 or more subscriptions   |  |  reference the receiver
                            v  |
                    .-------------------.
                    |                   |
                    |    Connecting     |
                    |                   |
                    '-------------------'
                            |  ^
  Transport and/or security |  |  Transport or security session
  has been established.     |  |  has been lost or failed.
                            v  |
                    .-------------------.
                    |                   |
                    |      Active       |
                    |                   |
                    '-------------------'
Figure 9: Receiver Session State Diagram

This state model allows implementations and operators to clearly distinguish between receivers that are simply configured, those that are in the process of connecting, and those that are actively being used.

If the configuration has changed such that there were previously connections to a receiver, but that receiver is no longer referenced by valid subscriptions, then the publisher MUST close any associated transport sessions to the receiver, but MAY delay the closing for a short period of time (no more than 15 minutes) to potentially allow existing transport session to be reused by new subscriptions.

8.2. Transports

This document describes a transport-agnostic mechanism for subscribing to YANG datastore telemetry. Hence, separate specifications are required to define transports that support YANG Push v2. The requirements for these transport specifications are documented in the following section:

8.2.1. Requirements for YANG Push v2 Transport Specifications

This section provides requirements for any transport specifications supporting the YANG Push v2 solution presented in this document.

The transport specification MUST provide YANG modules, to be implemented by publishers implementing the YANG Push configuration model in Section 15, that:

  • augments the datastore-telemetry/receivers/transport-type choice statement with a container that both identifies the transport and contains all transport specific parameters.

  • augments /sysc:system-capabilities/transport/transport-capabilities/ container with any transport specific capabilities or options (conditional on a YANG when statement). Note, encodings for a given transport are advertised directly via the ietf-yang-push-2-capabilities YANG Model Section 16.2.

Using a secure transport is RECOMMENDED. Thus, any transport specification MUST provide a mechanism to ensure secure communication between the publisher and receiver in a hostile environment, e.g., through the use of transport layer encryption. Transport specifications MAY also specify a mechanism for unencrypted communications, which can be used when transport layer security is not required, e.g., if the transport session is being secured via another mechanism, or when operating within a controlled environment or test lab.

Any transport specification SHOULD support mutual receiver and publisher authentication at the transport layer.

The transport selected by the subscriber to reach the publisher SHOULD be able to support multiple "establish-subscription" requests made in the same transport session.

The transport specification MUST specifying how multiple subscriptions referencing the same receiver are to be handled at the transport layer. The transport specification MAY require separate transport sessions per subscription to a given receiver, or it MAY allow multiple subscriptions to the same receiver to be multiplexed over a shared transport session.

A specification for a transport built upon this document can choose whether to use the same logical channel for the RPCs and the event records. For a given subscription and Message Publisher process, the update records and subscription state change notifications sent by that process MUST be sent on the same transport session. Transport session considerations for distributed publishers are described in Section 13.

The transport specification MAY specify a keepalive mechanism to keep the transport session alive. There is no YANG Push v2 protocol or application level keepalive mechanism.

TODO, do we need to mention anything about transport session timeouts, e.g., which would cause a subscription to be terminated. What about buffering? Is that a transport consideration?

Additional transport requirements may be dictated by the choice of transport used with a subscription.

8.2.1.1. DSCP Marking

YANG Push v2 supports dscp marking to differentiate prioritization of notification messages during network transit.

A receiver with a dscp leaf results in a corresponding Differentiated Services Code Point (DSCP) marking [RFC2474]} being placed in the IP header of any resulting update notification messages and subscription state change notifications. A publisher MUST respect the DSCP markings for subscription traffic egressing that publisher.

The transport specification MUST specify if there are any particular quality-of-service or class-of-service considerations related to handling DSCP settings associated with the subscription.

8.3. Encodings

The update notification (Section 7.2), update-complete notification, and subscription lifecycle notifications (Section 9.2) can be encoded in any format that has a definition for encoding YANG data. For a given subscription, all notification messages, including both the envelope and its contents, are encoded using the same encoding.

To maximize interoperability, implementations SHOULD support both JSON and CBOR with text identifiers. Constrained platforms may not be able to support JSON and hence may choose to only support CBOR encoding. Support for XML and CBOR with YANG SIDs is OPTIONAL unless required by the selected protocol binding.

Encoding identities derive from the encoding base identity in ietf-yang-push-2. Supported encodings are advertised through the transport capabilities (Section 16.2).

8.3.1. Encoding the Envelope and Notification Contents

The envelope and its contents MUST follow the corresponding YANG encoding rules:

  • JSON (json), [RFC7951]: the root is an object with the member ietf-yang-push-2:envelope, whose value is an object containing the envelope nodes.

  • XML (xml), [RFC7950]: the root is an <envelope> element in the namespace urn:ietf:params:xml:ns:yang:ietf-yang-push-2, containing the envelope's child elements.

  • CBOR with text identifiers (cbor), [RFC9254]: the root is a map with the text key ietf-yang-push-2:envelope, whose value is a map containing the envelope nodes, using text identifiers as keys.

  • CBOR with YANG SIDs (cbor-sids), [RFC9254]: the root is a map keyed by the envelope structure's SID, whose value is a map containing the envelope nodes. SIDs MUST be allocated according to [RFC9595]; SID deltas and absolute SIDs follow [RFC9254].

The contents node directly contains the notification, identified by the name and namespace of its YANG notification statement, or its allocated SID. The notification's data nodes use the same YANG encoding as the envelope. For CBOR with SIDs, the notification's SID is encoded relative to the contents node as specified for anydata in Section 4.5 of [RFC9254].

9. Setting up and Managing Subscriptions

Subscriptions can be set up and managed in two ways:

  1. Configured Subscriptions - a subscription created and principally controlled by configuration.

  2. Dynamic Subscriptions - a subscription created and principally controlled via YANG RPCs from a telemetry receiver.

Conformant implementations MUST implement at least one of the two mechanisms above for establishing and maintaining subscriptions, but they MAY choose to only implement a single mechanism.

The core behavior for both configured and dynamic subscription is the same, with the key differentiation being how they are provisioned, and how the transport is setup. This next section describes the functionality that is common to both types of subscription, followed by the sections that describe the specifics and differences between the two ways of managing subscriptions.

9.1. Common Subscription Parameters

All subscriptions require the following state to be instantiated:

  • an id to identify the subscription.

  • the target for the subscription, comprising:

    • the target datastore, as per [RFC8342]

    • a set of selection filters to choose which datastore nodes the subscription is monitoring or sampling, as described in Section 6.

  • the update-trigger to indicate when update notifications are generated:

    • periodic, for the publisher to send updated copies of the state on a periodic basis

    • on-change, for the publisher to send state updates when the internal state changes, i.e., event driven.

  • receiver, transport, and notification encoding parameters, as per Section 8.1 and Section 8.3. The encoding applies to both the envelope and its contents. How these parameters are provided differs for configured and dynamic subscriptions, as further explained below.

Subscription ids MUST be unique across all configured and dynamic subscriptions. Configured subscription take precedence over dynamic subscription, so:

  • attempts to create a dynamic subscription with a subscription id that conflicts with any other subscription id (configured or dynamic) MUST fail,

  • configuring a subscription, assuming it passes configuration validation, replaces any dynamic subscriptions with the same subscription id. Thus, causing the dynamic subscription to be immediately terminated (see Section 9.1.4).

  • subscription ids starting with dyn- are reserved for the publisher to use for automatically allocate subscription ids for dynamic subscriptions when the client has choosen not to provide one in the establish-subscription RPC.

9.1.1. Subscription States

YANG Push v2 has a small set of simple states for a subscription on a publisher. These states are intended to help clients easily determine the health and status of a subscription.

  • Invalid: a subscription that is invalid for any reason. E.g., the subscription references an invalid filter expression for the current device schema. Normally, invalid configurations should be rejected by the system, whether due to subscription configuration or establish-subscription RPC, and hence this state should rarely be seen.

  • Inactive: a valid subscription, but one that is not active because it has no associated receiver. This state is unlikely to be seen for dynamic subscriptions.

  • Connecting: a subscription that is valid, and has appropriate receiver configuration, but the publisher has not managed to successfully connect to the receiver yet, and hence has not sent a subscription-started notification. Transport security failures would be in this state.

  • Active: a valid subscription, connected to the receiver, that has sent a subscription-stated notification and is generating update notifications, as per the terms of the subscription update policy.

  • Terminated: represents a subscription that has finished. Subscriptions would only be expected to transiently be in this state and hence it would not normally be reported. Terminated dynamic subscriptions, or unconfigured subscriptions, should quickly be removed from the operational state of the device. Terminated

Below is a state diagram illustrating the states, and the likely changes between states. However, this is not a formal state machine and publishers can move between arbitrary states based on changes to subscription properties, the system, connectivity to receivers, or resource constraints on the system. New subscriptions should choose an appropriate starting state, e.g., either Inactive or Invalid.

                  .-------------------.         .-------------------.
                  |                   |         |                   |
                  |    Inactive       | <------>|     Invalid       |
                  |                   |         |                   |
                  '-------------------'         '-------------------'
                            ^
                            |
                            v
                  .-------------------.
                  |                   |
                  |    Connecting     |
                  |                   |
                  '-------------------'
                            ^
                            |
                            v
                  .-------------------.
                  |                   |
                  |    Active         |
                  |                   |
                  '-------------------'


                  .-------------------.
                  |                   |
                  |    Terminated     |
                  |                   |
                  '-------------------'
Figure 10: Publisher's States for a Subscription

9.1.2. Creating Subscriptions

After a subscription is successfully established, the publisher immediately sends a subscription-started subscription state change notification to the receiver. It is quite possible that upon configuration, reboot, or even steady-state operations, a transport session may not be currently available to the receiver.

With active configured subscriptions, it is allowable to buffer event records even after a subscription-started has been sent. However, if events are lost (rather than just delayed) due to buffer capacity being reached, a subscription-terminated notification MUST be sent, followed by a new subscription-started notification. These notifications indicate an event record discontinuity has occurred. TODO, do we always want this behaviour or is it transport specific?

9.1.3. Modifying Subscriptions

The parameters associated with a subscription MAY be modified by client modify-subscription RPC or through configuration.

If the subscription is in Active state, and hence a subscription-started notification has been enqueued to the receiver, then any subscription parameter changes are handled as per the following sub-sections. If the subscription is not yet in Active state then any transport changes associated with the receiver must be made, but otherwise the new parameters would be notified in the subscription-started notification.

9.1.3.1. Modifications requiring subscription-terminated notification

Changes to any of following parameters MUST terminate the subscription, as per Section 9.1.4, before recreating it, clearing and reinitializing any associated statistics, as per Section 9.1.2:

  1. the subcription id

  2. the encoding

  3. any receiver settings that change the encoding, transport, transport security, or receiver destination address/port

  4. the update-trigger to enable sync-on-start.

  5. if the sync-on-start option is enabled, then any changes to the subscription-filter (inline or referenced) or YANG schema (schema-id) associated with the subscription. TODO, Why? Should a subscription-modifies message resend the sync-on-start data anyway?

The subscription-terminated notification MUST be sent using the old encoding and receiver settings before the subscription parameters were changed. The subscription-started notification MUST be sent using the updated subscription parameters.

9.1.3.2. Modifications allowing subscription-modified notification

If changes to a subscription only include changes to the following parameters then they SHOULD be handled via a subscription-modified notification, but MAY be handled as described above. This applies for changes to:

  1. the subscription target filter (inline, referring to a different named filter, or changing the referenced filter).

  2. the YANG schema (schema-id) associated with subscription target filter

  3. the update-trigger, unless sync-on-start is enabled

  4. the description field

  5. the message-publishers/publisher-id leaf-list

  6. any other fields that are included in a subscription-modified notification message, unless the definition of those fields explicitly specifies different behavior.

9.1.3.3. Modifications requiring no lifecycle notification

Changes to any of the following subscription parameters do not need to be notified to the client:

  1. dscp settings.

  2. source-address, source-interface, source-vrf, or the source port.

  3. any other settings not reported in the subscription-started notification message.

9.1.4. Terminating Subscriptions

Subscriptions MUST be terminated by the publisher due to any of the following circumstances:

  1. The subscription has been unconfigured.

  2. Some subscription, receiver, transport or encoding configuration has been removed, e.g., receiver configuration, such that there is no longer the sufficient minimum information to maintain the subscription.

  3. A dynamic subscription has been terminated via a delete-subscription or kill-subscription YANG RPC.

  4. Transport connectivity to the receiver has been lost, either due to network issues, or a failure in the security session state.

  5. The publisher does not have sufficient resources to honor the terms of the subscription, i.e., it is generating too many update notifications, or attempting to send too much data.

  6. The subscription parameters have changed in such a way, i.e., as defined in Section 9.1.3.1, that needs the subscription to be reset by terminating and recreating it.

  7. The reset RPC is invoked on a configured subscription, or on the referenced receiver associated with a configured subscription.

In addition, from a receiver's perspective, if transport connectivity is lost, then that is equivalent to terminating the subscription via a subscription-terminated notification.

If possible, the publisher MUST try and close the subscription gracefully by generating a subscription-terminated notification to the receiver before closing any sessions to any receivers that have no remaining subscriptions. Publishers MAY complete their current collection if one is in progress before generating the subscription-terminated notification. Obviously, if transport connectivity to a receiver has been lost then neither of these two actions is possible.

The publisher MUST NOT generate any further events, e.g., update notifications, related to the subscription after the subscription-terminated notification has been generated. In addition, receivers SHOULD ignore any messages received outside of an active subscription, i.e., either before a subscription-started notification or after a subscription-terminated notification.

If the publisher accepts the request, which it MUST, if the subscription-id matches a dynamic subscription established in the same transport session, then it should stop the subscription and send a subscription-terminated notification.

9.2. Subscription Lifecycle Notifications

In addition to sending event records to receivers, a publisher also sends subscription lifecycle state change notifications when lifecycle events related to subscription management occur.

Subscription state change notifications are generated per subscription, and are injected into the steam of update messages for that that subscription. These notifications MUST NOT be dropped or filtered.

Future extensions, or implementations MAY augment additional fields into the notification structures. Receivers MUST silently ignore unexpected fields.

The complete set of subscription state change notifications is described in the following subsections:

9.2.1. "subscription-started"

The subscription started notification is sent to a receiver to indicate that a subscription is active and they may start to receive update records from the publisher.

The subscription-started notification is sent for any of these reasons:

  1. A new subscription (configured or dynamic) has been started.

  2. The properties of a configured subscription has been changed, i.e., as specified in Section 9.1.3.1, that requires a subscription-terminated notification to be sent followed by a subscription-started notification, presuming that the new subscription parameters are valid.

  3. A configured subscription previously failed, and was terminated. After the publisher has successfully re-established a connection to the receiver and is ready to send datastore event records again.

Below is the tree diagram for the subscription-started notification. All data nodes contained in this tree diagram are described in the YANG module in Section 14.2.

    +---n subscription-started
    |  +--ro id                    subscription-id
    |  +--ro description?          string
    |  +--ro target
    |  |  +--ro datastore?                 identityref
    |  |  +--ro (filter)
    |  |  |  +--:(path)
    |  |  |  |  +--ro path                 ypath
    |  |  |  +--:(subtree)
    |  |  |  |  +--ro subtree              <anydata> {yp2:subtree}?
    |  |  |  +--:(xpath)
    |  |  |     +--ro xpath                yang:xpath1.0 {yp2:xpath}?
    |  |  +--ro schema-id?                 string
    |  |  +--ro yang-library-content-id?
    |  |          -> /yanglib:yang-library/content-id
    |  +--ro update-trigger
    |  |  +--ro periodic!
    |  |  |  +--ro period         centiseconds
    |  |  |  +--ro anchor-time?   yang:date-and-time
    |  |  +--ro on-change! {on-change}?
    |  |     +--ro sync-on-start?   boolean
    |  +--ro message-publishers
    |     +--ro publisher-id*   uint32
Figure 11: subscription-started Notification Tree Diagram

9.2.2. "subscription-modified"

The subscription-modified notification is sent to a receiver to indicate that some parameters associated with an active subscription have changed, as per Section 9.1.3.2.

Below is the tree diagram for the subscription-modified notification. Other than the notification name and the reason leaf, the parameters for a subscription-modified notification are the same as for the subscription-started notification. Robust receivers are expected to handle subscription-started and subscription-modified notifications equivalently.

All data nodes contained in this tree diagram are described in the YANG module in Section 14.2.

    +---n subscription-modified
    |  +--ro id                    subscription-id
    |  +--ro description?          string
    |  +--ro target
    |  |  +--ro datastore?                 identityref
    |  |  +--ro (filter)
    |  |  |  +--:(path)
    |  |  |  |  +--ro path                 ypath
    |  |  |  +--:(subtree)
    |  |  |  |  +--ro subtree              <anydata> {yp2:subtree}?
    |  |  |  +--:(xpath)
    |  |  |     +--ro xpath                yang:xpath1.0 {yp2:xpath}?
    |  |  +--ro schema-id?                 string
    |  |  +--ro yang-library-content-id?
    |  |          -> /yanglib:yang-library/content-id
    |  +--ro update-trigger
    |  |  +--ro periodic!
    |  |  |  +--ro period         centiseconds
    |  |  |  +--ro anchor-time?   yang:date-and-time
    |  |  +--ro on-change! {on-change}?
    |  |     +--ro sync-on-start?   boolean
    |  +--ro message-publishers
    |  |  +--ro publisher-id*   uint32
    |  +--ro reason                subscription-change
Figure 12: subscription-modified Notification Tree Diagram

9.2.3. "subscription-terminated"

For a receiver, this notification indicates that no further event records for an active subscription should be expected from the publisher unless and until a new subscription-started notification is received.

A subscription-terminated notification SHOULD only be sent by a publisher to a receiver if a subscription-started notification was previously sent.

The subscription terminated notification may be sent to a receiver for any of these reasons:

  1. A subscription has been stopped, either due to the change/removal of some configuration, or an RPC has been invoked to delete or kill a dynamic subscription.

  2. The properties of a subscription have been changed, i.e., as specified in Section 9.1.3.1, that requires a subscription-terminated notification to be sent followed by a subscription-started notification, presuming that the new subscription parameters are valid.

  3. A subscription has failed for any reason, e.g.,:

    • The publisher is no longer able to honor the subscription, due to resource constraints, or the filter is no longer valid.

    • Any transport level buffer to the receiver has become full, and the hence the publisher is dropping update notifications.

Below is a tree diagram for "subscription-terminated". All objects contained in this tree are described in the YANG module in Section 14.2.

    +---n subscription-terminated
    |  +--ro id        subscription-id
    |  +--ro reason    identityref
Figure 13: subscription-terminated Notification Tree Diagram

TODO Augmenting extra fields is better for clients? The reason data node identityref indicates why a subscription has been terminated, and could be extended with further reasons in future. I suggest that we change this to an enum with an optional description field.**

9.2.4. "update-completed"

TODO, this description needs to be updated.

This notification indicates that all of the event records prior to the current time have been passed to a receiver. It is sent before any notification messages containing an event record with a timestamp later than (1) the subscription's start time.

After the update-complete notification has been sent, additional event records will be sent in sequence as they arise naturally on the publisher.

Below is a tree diagram for update-complete. All objects contained in this tree are described in the YANG module in Section 4.

    +---n update-complete
       +--ro id?   subscription-id
Figure 14: update-complete Notification Tree Diagram

9.3. Configured Subscriptions

Configured subscriptions allow the management of subscriptions via configuration so that a publisher can send notification messages to a receiver.

This document specifies the ietf-yang-push-2-config YANG module Section 15.2 that defines an configuration model for configuring subscriptions. Support for this YANG module is OPTIONAL and is advertised using the normal YANG mechanisms, e.g., [RFC8525]. TODO, do we also advertise support via capabilities, i.e., issue 16

In addition to the common subscription parameters described in Section 9.1, a configured subscription also includes:

  • the receiver for the subscription, as described in Section 8.1. The referenced receiver specifies all transport, receiver, and encoding parameters.

Configured subscriptions have several characteristics distinguishing them from dynamic subscriptions, such as:

  • configured subscriptions are created, modified or deleted, by any configuration client with write permission on the subscription configuration.

  • configured subscription may reference a filter rather than define it inline as part of the subscription. Even for a referenced filter, the subscription-started and subscription-modified notifications always include the filter specification inline in the notification.

  • The lifetime of a configured subscription is tied to the configuration. I.e., if a valid and complete configuration exists for a subscription, then the publisher MUST attempt to connect to the receiver and honor the requirements of the subscription. In particular:

    • If the configuration is altered or removed then the subscription will similarly be altered or removed.

    • If the device reboots, then the configured subscription will obviously end, but once the subscription configuration has been processed after boot up, then the subscription will be recreated again, assuming the subscription configuration is still valid.

    • If the publisher detects that transport connectivity to the receiver is broken, then any subscriptions using that transport are terminated, but the publisher MUST periodically attempt to re-establish connection to the receiver and re-activate any configured subscriptions to that receiver.

  • The lifetime of any transport session(s) to receiver(s) are also tied to the subscription configuration, but in a way that depends on the behavior of the Yang Push 2 transport specificiation, i.e.,

    • For YANG Push transports that specify a separate transport session for each subscription to the same receiver then a new transport session is established whenever a valid subscription is configured and the transport session MUST be closed if the subscription configuration is removed or changed such that the subscription is no longer valid.

    • For YANG Push transports that specify a shared transport session for all subscriptions to the same receiver then a new transport session is established for the first valid configured subscription. Note, if there are no active subscriptions for a given receiver then any transport session(s) associated with that receiver MUST be closed, but that MAY be after a short delay.

  • Other than the reset YANG Action, described in Section 9.3.4, there are no YANG RPCs to dynamically create, modify, or delete a configured subscription, any alterations MUST be done via changes to the configuration.

9.3.1. Creating a Configured Subscription

Configured subscriptions are those created via changes to the publisher's configuration, e.g., using the YANG module defined in Section 15, or an equivalent configuration mechanism, such as a command-line interface, or alternative YANG configuration model.

After the configuration change has been accepted by the system, then the subscription is updated, as per Section 9.1.2.

TODO, to see an example of subscription creation using configuration operations over NETCONF, see Appendix A.

9.3.2. Modifying a Configured Subscription

Configured subscriptions can be modified due to configuration changes in the subscription configuration or referenced configuration, i.e., filters or receivers. After the configuration change has been accepted by the system, then the subscription is updated, as per Section 9.1.3.

9.3.3. Deleting a Configured Subscription

Configured subscriptions can be deleted via configuration. After the configuration change has been accepted by the system the subscription is terminated, as per Section 9.1.4.

9.3.4. Resetting a Configured Subscription

Configured subscriptions are generally expected to self-monitor and automatically reconnect to the receiver if they experience network or transport issues. However, the data model also defines explicit YANG actions to either: (i) reset a single subscription, or (ii) reset all subscriptions and the transports(s) associated with a specific configured receiver instance.

These reset actions primarily act at the subscription application layer, but may be useful if a receiver or collector determines that a configured subscription is not behaving correctly, and wishes to force a reset of the subscription without modifying the configuration associated with the subscription or forcing a configuration change on the publisher device.

The reset action on a subscription is handled equivalently to removing and re-adding the subscription configuration. I.e., the subscription MUST be terminated, as per Section 9.1.4 before being recreated, as per Section 9.1.2. The reset action also resets (terminated and re-establishes) any subscription specific transport session that is not shared with any other subscriptions. Any counters associated with the subscription are also re-initialized in a manner that is consistent with a client unconfiguring and then reconfiguring the subscription.

The reset action on a receiver is handled equivalently to removing and re-adding the receiver configuration for the receiver that has been reset. Specifically, every subscription referencing the receiver MUST be terminated, as per Section 9.1.4 before being recreated, as per Section 9.1.2. Any transport sessions tied to the subscriptions referencing the reset receiver MUST also be terminated and re-established. Any counters associated with the receiver are also re-initialized in a manner that is consistent with a client unconfiguring and then reconfiguring the receiver configuration.

9.4. Dynamic Subscriptions

Dynamic subscriptions are created by a subscriber invoking the establish-subscription YANG RPC [RFC7950], as described in Section 9.4.1.

Support for dynamic subscriptions is OPTIONAL, with its availability advertised via the dynamic YANG feature in the ietf-yang-push-2 YANG module Section 14.2, and also via the capabilities module Section 16.2.

Dynamic subscription differ from configured subscription in the following ways:

  • Dynamic subscription reuse the same transport session on which the establish-subscription RPC was received to send back any notifications, and so the transport and receiver do not need to be specified and each dynamic subscription can always only have a single receiver.

  • The publisher MUST reply to the establish-subscription RPC before sending the subscription-started or any update notifications for this subscription.

  • The lifetime of a dynamic subscription is bound by the transport session used to establish it. If the transport session fails then the dynamic subscription MUST be terminated.

  • Dynamic subscriptions can either be terminated by the client that established the subscription sending a delete-subscription YANG RPC on the same transport session, or any client with sufficient access permissions invoking the kill-subscription YANG RPC.

  • A publisher MAY terminate a dynamic subscription at any time, i.e., due to internal constraints of the publisher.

  • If a dynamic subscription is terminated for any reason, then the client is responsible for re-establishing the subscription if it is still required.

  • If the publisher cannot honor the terms of a dynamic subscription then the subscription MUST be terminated. TODO, is this a SHOULD or MUST, do we want some leeway for temporary issues? E.g., allow some buffering. Also, this effectively applies to config subscriptions as well and hence should move.

9.4.1. Establishing a Dynamic Subscription

The establish-subscription RPC allows a subscriber to request the creation of a subscription.

In addition to the common subscription parameters described in Section 9.1, the establish-subscription YANG RPC:

  • includes the mandatory encoding to be used for all YANG Push v2 notifications for the subscription (Section 8.3).

  • optionally includes DSCP settings to use for the transport.

The selected encoding MUST match the encoding of the incoming establish-subscription RPC and be supported by the protocol binding. The publisher MUST reject an unsupported encoding with encoding-unsupported. For example, NETCONF [RFC6241] uses XML, so dynamic subscriptions established over NETCONF use XML for both the envelope and its contents. JSON or CBOR dynamic subscriptions require a protocol binding that supports that encoding for both RPCs and notifications.

The DSCP code point settings for all subscription using the same transport session MUST be the same. Attempts to invoke establish-subscription with a different DSCP code point MUST be rejected.

If the publisher can satisfy the establish-subscription request, it replies with a numeric identifier for the subscription and then immediately starts streaming notification messages.

A dynamic subscription request MUST be declined if a publisher determines that it may be unable to provide update records meeting the terms of an establish-subscription RPC request.

Below is a tree diagram for establish-subscription YANG RPC. All objects contained in this tree are described in the YANG module in Section 14.2.

    +---x establish-subscription {dynamic}?
    |  +---w input
    |  |  +---w id?               subscription-id
    |  |  +---w description?      string
    |  |  +---w target
    |  |  |  +---w datastore?       identityref
    |  |  |  +---w (filter)
    |  |  |     +--:(path)
    |  |  |     |  +---w path       ypath
    |  |  |     +--:(subtree)
    |  |  |     |  +---w subtree    <anydata> {yp2:subtree}?
    |  |  |     +--:(xpath)
    |  |  |        +---w xpath      yang:xpath1.0 {yp2:xpath}?
    |  |  +---w update-trigger
    |  |  |  +---w periodic!
    |  |  |  |  +---w period         centiseconds
    |  |  |  |  +---w anchor-time?   yang:date-and-time
    |  |  |  +---w on-change! {on-change}?
    |  |  |     +---w sync-on-start?   boolean
    |  |  +---w encoding          encoding
    |  |  +---w dscp?             inet:dscp
    |  +--ro output
    |     +--ro id    subscription-id
Figure 15: establish-subscription YANG RPC

A publisher MAY reject the "establish-subscription" RPC for many reasons, as described in TODO (Section 2.4.6)?

9.4.2. Modifying a Dynamic Subscription

The modify-subscription RPC allows a subscriber to request the modification of parameters associated with a dynamic subscription. It uses the same parameters as the establish-subscription RPC defined in Section 9.4.1, except that the id leaf is mandatory.

If the modification to the subscription is accepted by the publisher then it is processed as per Section 9.1.3, otherwise an error is returned to the modify-subscription RPC and the subscription is left unmodified.

The publisher MUST reply to the modify-subscription RPC before sending any subscription lifecycle notifications, i.e., a pair of subscription-terminated/subscription-started notifications, or asubscription-modified notification.

Below is a tree diagram for the modify-subscription YANG RPC. All objects contained in this tree are described in the YANG module in Section 14.2.

    +---x modify-subscription {dynamic}?
    |  +---w input
    |     +---w id                subscription-id
    |     +---w description?      string
    |     +---w target
    |     |  +---w datastore?       identityref
    |     |  +---w (filter)
    |     |     +--:(path)
    |     |     |  +---w path       ypath
    |     |     +--:(subtree)
    |     |     |  +---w subtree    <anydata> {yp2:subtree}?
    |     |     +--:(xpath)
    |     |        +---w xpath      yang:xpath1.0 {yp2:xpath}?
    |     +---w update-trigger
    |     |  +---w periodic!
    |     |  |  +---w period         centiseconds
    |     |  |  +---w anchor-time?   yang:date-and-time
    |     |  +---w on-change! {on-change}?
    |     |     +---w sync-on-start?   boolean
    |     +---w dscp?             inet:dscp
Figure 16: modify-subscription YANG RPC

A publisher MAY reject the "modify-subscription" RPC for various reasons, as described in TODO.

9.4.3. Deleting a Dynamic Subscription

The delete-subscription operation permits canceling an existing dynamic subscription that was established on the same transport session connecting to the subscriber.

The publisher responds to the request in the following way:

  • If the identifier matches a dynamic subscription created on the same transport session then it MUST terminate the subscription, as per Section 9.1.4.

    The publisher MAY reply back to the client before the subscription has been terminated, i.e., it may act asynchronously with respect to the delete request, however, the publisher MUST allow the client to create a new subscription using the same subscription id immediately after either the RPC operation completes or the subscription-terminated notification (Section 9.2.3) has been transmitted.

  • Otherwise, the request is failed with an "unknown subscription" error message.

Below is the tree diagram for the delete-subscription RPC. All objects contained in this tree are described in the YANG module in Section 14.2.

    +---x delete-subscription {dynamic}?
    |  +---w input
    |     +---w id    subscription-id
Figure 17: delete-subscription YANG RPC

9.4.4. Killing a Dynamic Subscription

The kill-subscription RPC operation permits a client, that has the required access permissions, to forcibly terminate any arbitrary dynamic subscription, identified by subscription id, including those not associated with the transport session used for the kill-subscription RPC. The subscription is terminated as per Section 9.1.4.

The publisher MAY reply back to the client before the subscription has been terminated, i.e., it may act asynchronously with respect to the delete request, however, the publisher MUST allow the client to create a new subscription using the same subscription id immediately after the subscription-terminated notification (Section 9.2.3) has been transmitted.

Below is the tree diagram for the kill-subscription RPC. All objects contained in this tree are described in the YANG module in Section 14.2.

    +---x kill-subscription {dynamic}?
       +---w input
          +---w id    subscription-id
Figure 18: kill-subscription YANG RPC

9.4.5. RPC Failures

TODO, we should see if we can simplify how errors are reported.

Whenever an RPC is unsuccessful, the publisher returns relevant information as part of the RPC error response. Transport-level error processing MUST be done before the RPC error processing described in this section. In all cases, RPC error information returned by the publisher will use existing transport-layer RPC structures, such as those seen with NETCONF (Appendix A of [RFC6241]) or RESTCONF (Section 7.1 of [RFC8040]). These structures MUST be able to encode subscription-specific errors identified below and defined in this document's YANG data model.

As a result of this variety, how subscription errors are encoded in an RPC error response is transport dependent. Valid errors that can occur for each RPC are as follows:

  establish-subscription         modify-subscription
  ----------------------         ----------------------
  dscp-unavailable               filter-unsupported
  encoding-unsupported           insufficient-resources
  filter-unsupported             no-such-subscription
  insufficient-resources

  delete-subscription            kill-subscription
  ----------------------         ----------------------
  no-such-subscription           no-such-subscription

To see a NETCONF-based example of an error response from the list above, see the "no-such-subscription" error response illustrated in [RFC8640], Figure 10.

There is one final set of transport-independent RPC error elements included in the YANG data model defined in this document: three yang-data structures that enable the publisher to provide to the receiver any error information that does not fit into existing transport-layer RPC structures. These structures are:

  1. "establish-subscription-stream-error-info": This MUST be returned with the leaf "reason" populated if an RPC error reason has not been placed elsewhere in the transport portion of a failed "establish-subscription" RPC response. This MUST be sent if hints on how to overcome the RPC error are included.

  2. "modify-subscription-stream-error-info": This MUST be returned with the leaf "reason" populated if an RPC error reason has not been placed elsewhere in the transport portion of a failed "modify-subscription" RPC response. This MUST be sent if hints on how to overcome the RPC error are included.

  3. "delete-subscription-error-info": This MUST be returned with the leaf "reason" populated if an RPC error reason has not been placed elsewhere in the transport portion of a failed "delete-subscription" or "kill-subscription" RPC response.

10. Capabilities

This document defines the ietf-yang-push-2-capabilities YANG module, which augments the ietf-system-capabilities module defined in [RFC9196]. These modules provide a standard, machine-readable representation of YANG Push v2 capabilities, including supported subscription types, transports, and parameters.

The ietf-yang-push-2-capabilities module contains capabilities to indicate what types of subscriptions and transports may be configured, along with acceptable subscription parameter for given subtrees.

The schema tree for the ietf-system-capabilities augmented by ietf-yang-push-2-capabilities is given below.

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 yp2ca:datastore-telemetry
     |        +--ro yp2ca:periodic-notifications-supported?
     |        |       notification-support
     |        +--ro (yp2ca:update-period)?
     |        |  +--:(yp2ca:minimum-update-period)
     |        |  |  +--ro yp2ca:minimum-update-period?        uint32
     |        |  +--:(yp2ca:supported-update-period)
     |        |     +--ro yp2ca:supported-update-period*      uint32
     |        +--ro yp2ca:on-change-supported?
     |                notification-support
     +--ro yp2ca:datastore-telemetry
     |  +--ro yp2ca:periodic-notifications-supported?
     |  |       notification-support
     |  +--ro (yp2ca:update-period)?
     |  |  +--:(yp2ca:minimum-update-period)
     |  |  |  +--ro yp2ca:minimum-update-period?        uint32
     |  |  +--:(yp2ca:supported-update-period)
     |  |     +--ro yp2ca:supported-update-period*      uint32
     |  +--ro yp2ca:on-change-supported?
     |  |       notification-support
     |  +--ro yp2ca:transport
     |     +--ro yp2ca:transport-capability* [transport-protocol]
     |        +--ro yp2ca:transport-protocol    identityref
     |        +--ro yp2ca:security-protocol?    identityref
     |        +--ro yp2ca:encoding-format*      identityref
     +--ro yp2ca:distributed-notifications-supported?   boolean
Figure 19: YANG tree for ietf-system-capabilities with ietf-yl-lite-capabilities augmentations.

TODO, do we need additional capabilities, as per Issue 18

11. Robustness, Reliability, and Subscription Monitoring

11.1. Robustness and Reliability

It is important for clients to have confidence that the telemetry data that they receive is correct and complete. The design of YANG Push v2 achieves this in several ways:

  • the complete flag in the update notification, or the equivalent update-complete notification, are used to signal when all data for a periodic or resynchronization collection has been enqueued by the publisher. This allows clients to delete stale information and monitor the performance and behavior of the publisher.

  • publishers use buffers when enqueuing traffic on to a transport to a receiver, but if that buffer becomes full then the transport specification indicates whether update messages should be dropped, or the subscription should be terminated. In that case that a dynamic subscription is terminated, the client may attempt to re-created the subscription. For configured subscriptions that have been terminated, the publisher should attempt to periodically recreate the subscription or reconnect the receiver.

  • the notification envelope structure, Section 7.1, used for all YANG Push notifications contains a sequence-number counter scoped to each subscription and publisher-id. Gaps in that notification stream, accounting for wraparound and reordering, allow lost messages in an end-to-end data pipeline spanning multiple transport hops to be detected and appropriate mitigation steps to be taken. For example, see figure 1 in [I-D.ietf-nmop-network-anomaly-architecture].

  • the protocol relies on transport protocols that are either reliable, e.g., TCP or HTTP, or unreliable transports that employ mechanisms for clients to detect when losses at the transport layer have occurred, e.g., the message id in [I-D.ietf-netconf-udp-notif] (TODO fix reference to bis version, once that becomes available).

  • finally, if a publisher is not able to honor the expectation for a subscription for any reason, then the publisher always has the option to terminate the subscription. It can then subsequently refuse to handle new subscriptions if it does not have sufficient resources to handle the subscription.

11.2. Subscription Monitoring

In the operational state datastore, the datastore-telemetry container maintains operational state for all configured and dynamic subscriptions.

Both configured and dynamic subscriptions are represented in the list ietf-yang-push-2-config:datastore-telemetry/subscriptions/subscription. Dynamic subscriptions are only present in the list when they are active, and are removed as soon as they are terminated. Whereas, configured subscriptions are always present in the list when they are configured, regardless of whether they are active.

The operational state is important for monitoring the health of subscriptions, receivers, and the overall telemetry subsystem.

This includes:

TODO, update the YANG model with more useful operational data, and mostly this section should briefly summarize and refer to the YANG model. We should also consider what indications to include from filters that cause a larger amount of internal work but don't generate a large number of transmitted notifications.

  • per subscription status and counters

  • per receiver status and counters

  • maybe some indication of the overall load on the telemetry subsystem, but we need to consider how useful that actually is, and whether just monitoring the device CPU load and general performance would be a better indication.

11.3. Publisher Capacity

A publisher SHOULD reject a request for a subscription if it is unlikely that the publisher will be able to fulfill the terms of that subscription request.

Whether or not a subscription can be supported will be determined by a combination of several factors, such as the subscription update trigger (on-change or periodic), the period in which to report changes (one-second periods will consume more resources than one-hour periods), the amount of data in the datastore subtree that is being subscribed to, the number and combination of other subscriptions that are concurrently being serviced, and the overall load from other services running on the publisher.

It is entirely possible that a subscription may be reasonable at the time that it is created, but other changes to configuration or operational data or load in the system means that the subscription can no longer be honored.

TODO - Do we allow servers to reduce the period of the subscription to allow it to be kept active? E.g., with a subscription modification notification? E.g., see issue 41

12. Conformance

The normative requirements for a conformant YANG Push v2 implementation are stated throughout this document using [RFC2119] language. This section summarizes the implementation choices; the normative requirements remain in the sections referenced below.

An implementation supports configured subscriptions, dynamic subscriptions, or both. The requirement to support at least one of these mechanisms is specified in Section 9. Requirements for the behavior of each mechanism are specified in Section 9.3 and Section 9.4.

The ietf-yang-push-2-config YANG module contains both the configuration and operational-state models. Support for this module is optional, as specified in Section 9.3. Implementations that use alternative mechanisms to configure and manage subscriptions may omit this module.

12.1. Subscription Content Versioning

Many receivers will want to know what the schema is associated with a subscription and whether that schema has changed, e.g., due to a changing in software on the publisher.

Various mechanisms are available to help receivers or collectors learn or monitor the schema associated with a subscription:

  1. The device schema is available in the YANG library module ietf-yang-library.yang as defined in [RFC8525]. YANG library also provides a simple "yang-library-change" notification that informs the subscriber that the library has changed, or alternatively, the publisher may support an on-change telemetry subscription to

Content Schema Identification

YANG Module Synchronization

To make subscription requests, the subscriber needs to know the YANG datastore schemas used by the publisher. These schemas are available in the YANG library module ietf-yang-library.yang as defined in [RFC8525]. The receiver is expected to know the YANG library information before starting a subscription.

The set of modules, revisions, features, and deviations can change at runtime (if supported by the publisher implementation). For this purpose, the YANG library provides a simple "yang-library-change" notification that informs the subscriber that the library has changed. In this case, a subscription may need to be updated to take the updates into account. The receiver may also need to be informed of module changes in order to process updates regarding datastore

TODO, this section should be updated so that a subscription is restarted if the schema that it is using changes, and to incorporate ideas to fingerprint the subscription schema in the subscription-started notification.

13. Distributed Notifications - Multiple Publishing Processes

Distributed notifications allow a subscription to be served by multiple publishing processes on the same device. For example, separate processes on linecards can publish local data directly to the receiver, avoiding a bottleneck at the management processor.

The YANG Push 2 specification supports distributed notifications based on [I-D.ietf-netconf-distributed-notif], but the solution is fully defined in this document. It makes small changes to accommodate the YANG Push 2 message structure and imposes tighter restrictions on publisher ID allocation: ID 0 is reserved for the Publisher Parent Process, and if a Publisher Agent is removed and re-added to an ongoing subscription then it is allocated a new Publisher ID.

It is OPTIONAL for YANG Push 2 publishers to support multiple publisher agents since they always have the option of handling all subscriptions from a single publisher process on each server. Receivers and consumers of YANG Push 2 subscription data MUST accommodate servers that publish their data from multiple Message Publishing processes, including correlating collection completion across those processes.

The following rules describe how distributed notifications are supported in YANG Push 2:

14. Core YANG Push v2 YANG Data Model

14.1. ietf-yang-push-2 YANG tree

This section shows the full tree output for ietf-yang-push-2 YANG module.

Note, this output does not include support for any transport configuration, and for any implementation that supports configured subscriptions using this YANG module then at least one transport would expect to be configurable.

module: ietf-yang-push-2

  rpcs:
    +---x establish-subscription {dynamic}?
    |  +---w input
    |  |  +---w id?               subscription-id
    |  |  +---w description?      string
    |  |  +---w target
    |  |  |  +---w datastore?       identityref
    |  |  |  +---w (filter)
    |  |  |     +--:(path)
    |  |  |     |  +---w path       ypath
    |  |  |     +--:(subtree)
    |  |  |     |  +---w subtree    <anydata> {yp2:subtree}?
    |  |  |     +--:(xpath)
    |  |  |        +---w xpath      yang:xpath1.0 {yp2:xpath}?
    |  |  +---w update-trigger
    |  |  |  +---w periodic!
    |  |  |  |  +---w period         centiseconds
    |  |  |  |  +---w anchor-time?   yang:date-and-time
    |  |  |  +---w on-change! {on-change}?
    |  |  |     +---w sync-on-start?   boolean
    |  |  +---w encoding          encoding
    |  |  +---w dscp?             inet:dscp
    |  +--ro output
    |     +--ro id    subscription-id
    +---x modify-subscription {dynamic}?
    |  +---w input
    |     +---w id                subscription-id
    |     +---w description?      string
    |     +---w target
    |     |  +---w datastore?       identityref
    |     |  +---w (filter)
    |     |     +--:(path)
    |     |     |  +---w path       ypath
    |     |     +--:(subtree)
    |     |     |  +---w subtree    <anydata> {yp2:subtree}?
    |     |     +--:(xpath)
    |     |        +---w xpath      yang:xpath1.0 {yp2:xpath}?
    |     +---w update-trigger
    |     |  +---w periodic!
    |     |  |  +---w period         centiseconds
    |     |  |  +---w anchor-time?   yang:date-and-time
    |     |  +---w on-change! {on-change}?
    |     |     +---w sync-on-start?   boolean
    |     +---w dscp?             inet:dscp
    +---x delete-subscription {dynamic}?
    |  +---w input
    |     +---w id    subscription-id
    +---x kill-subscription {dynamic}?
       +---w input
          +---w id    subscription-id

  notifications:
    +---n subscription-started
    |  +--ro id                    subscription-id
    |  +--ro description?          string
    |  +--ro target
    |  |  +--ro datastore?                 identityref
    |  |  +--ro (filter)
    |  |  |  +--:(path)
    |  |  |  |  +--ro path                 ypath
    |  |  |  +--:(subtree)
    |  |  |  |  +--ro subtree              <anydata> {yp2:subtree}?
    |  |  |  +--:(xpath)
    |  |  |     +--ro xpath                yang:xpath1.0 {yp2:xpath}?
    |  |  +--ro schema-id?                 string
    |  |  +--ro yang-library-content-id?
    |  |          -> /yanglib:yang-library/content-id
    |  +--ro update-trigger
    |  |  +--ro periodic!
    |  |  |  +--ro period         centiseconds
    |  |  |  +--ro anchor-time?   yang:date-and-time
    |  |  +--ro on-change! {on-change}?
    |  |     +--ro sync-on-start?   boolean
    |  +--ro message-publishers
    |     +--ro publisher-id*   uint32
    +---n subscription-modified
    |  +--ro id                    subscription-id
    |  +--ro description?          string
    |  +--ro target
    |  |  +--ro datastore?                 identityref
    |  |  +--ro (filter)
    |  |  |  +--:(path)
    |  |  |  |  +--ro path                 ypath
    |  |  |  +--:(subtree)
    |  |  |  |  +--ro subtree              <anydata> {yp2:subtree}?
    |  |  |  +--:(xpath)
    |  |  |     +--ro xpath                yang:xpath1.0 {yp2:xpath}?
    |  |  +--ro schema-id?                 string
    |  |  +--ro yang-library-content-id?
    |  |          -> /yanglib:yang-library/content-id
    |  +--ro update-trigger
    |  |  +--ro periodic!
    |  |  |  +--ro period         centiseconds
    |  |  |  +--ro anchor-time?   yang:date-and-time
    |  |  +--ro on-change! {on-change}?
    |  |     +--ro sync-on-start?   boolean
    |  +--ro message-publishers
    |  |  +--ro publisher-id*   uint32
    |  +--ro reason                subscription-change
    +---n subscription-terminated
    |  +--ro id        subscription-id
    |  +--ro reason    identityref
    +---n update
    |  +--ro id?                 subscription-id
    |  +--ro path-prefix?        string
    |  +--ro snapshot-type       enumeration
    |  +--ro observation-time?   yang:date-and-time
    |  +--ro updates* [target]
    |  |  +--ro target          string
    |  |  +--ro (data)
    |  |     +--:(update)
    |  |     |  +--ro update?   <anydata>
    |  |     +--:(delete)
    |  |        +--ro delete?   boolean
    |  +--ro complete?           boolean
    +---n update-complete
       +--ro id?   subscription-id
Figure 20: YANG tree for YANG Push v2 Module Tree Output

14.2. ietf-yang-push-2 YANG Model

This module imports typedefs from [RFC6991], [RFC8343], [RFC8341], [RFC8529], and [RFC8342]. It references [RFC6241], [XPATH] ("XML Path Language (XPath) Version 1.0"), [RFC7049], [RFC8259], [RFC7950], [RFC7951], and [RFC7540].

This YANG module imports typedefs from [RFC6991], identities from [RFC8342], and the "sx:structure" extension from [RFC8791]. It also references [RFC6241], [XPATH], and [RFC7950].

<CODE BEGINS> file "ietf-yang-push-2.yang#0.1.0"

module ietf-yang-push-2 {
  yang-version 1.1;
  namespace "urn:ietf:params:xml:ns:yang:ietf-yang-push-2";
  prefix yp2;

  import ietf-inet-types {
    prefix inet;
    reference
      "RFC 6991: Common YANG Data Types";
  }
  import ietf-netconf-acm {
    prefix nacm;
    reference
      "RFC 8341: Network Configuration Access Control Model";
  }
  import ietf-yang-structure-ext {
    prefix sx;
    reference
      "RFC 8525: YANG Data Structure Extensions";
  }
  import ietf-yang-types {
    prefix yang;
    reference
      "RFC 6991: Common YANG Data Types";
  }
  import ietf-datastores {
    prefix ds;
    reference
      "RFC 8342: Network Management Datastore Architecture (NMDA)";
  }
  import ietf-yang-library {
    prefix yanglib;
    reference
      "RFC 8525: YANG Library";
  }

  organization
    "IETF NETCONF (Network Configuration) Working Group";
  contact
    "WG Web:  <https:/datatracker.ietf.org/wg/netconf/>
     WG List: <mailto:netconf@ietf.org>

     Author:  Robert Wilton
              <mailto:rwilton@cisco.com>";
  description
    "This module contains YANG specifications for YANG-Push
     version 2, a simplified version of the YANG-Push [RFC 8641]
     protocol.

     The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
     NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
     'MAY', and 'OPTIONAL' in this document are to be interpreted as
     described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
     they appear in all capitals, as shown here.

     Copyright (c) 2025 IETF Trust and the persons identified as
     authors of the code.  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 Revised BSD License set
     forth in Section 4.c of the IETF Trust's Legal Provisions
     Relating to IETF Documents
     (https://trustee.ietf.org/license-info).

     This version of this YANG module is part of RFC XXXX
     (https://www.rfc-editor.org/info/rfcXXXX); see the RFC itself
     for full legal notices.";

  revision 2026-04-21 {
    description
      "Initial revision.";
    reference
      "XXXX: YANG Datastore Telemetry (YANG Push version 2)";
  }

  /*
   * FEATURES
   */

  feature dynamic {
    description
      "This feature indicates that dynamic establishment of
       subscriptions is
       supported.";
  }

  feature on-change {
    description
      "This feature indicates that on-change triggered subscriptions
       are supported.";
  }

  feature subtree {
    description
      "This feature indicates support for YANG subtree filtering.";
    reference
      "RFC 6241: Network Configuration Protocol (NETCONF),
                 Section 6";
  }

  feature xpath {
    description
      "This feature indicates support for XPath filtering.";
    reference
      "XML Path Language (XPath) Version 1.0
       (https://www.w3.org/TR/1999/REC-xpath-19991116)";
  }

  /*
   * IDENTITIES
   */
  /* Identities for RPC and notification errors */

  identity delete-subscription-error {
    description
      "Base identity for the problem found while attempting to
       fulfill either a 'delete-subscription' RPC request or a
       'kill-subscription' RPC request.";
  }

  identity establish-subscription-error {
    description
      "Base identity for the problem found while attempting to
       fulfill an 'establish-subscription' RPC request.";
  }

  identity subscription-terminated-reason {
    description
      "Base identity for the problem condition communicated to a
       receiver as part of a 'subscription-terminated'
       notification.";
  }

  identity dscp-unavailable {
    base establish-subscription-error;
    description
      "The publisher is unable to mark notification messages with
       prioritization information in a way that will be respected
       during network transit.";
  }

  identity encoding-unsupported {
    base establish-subscription-error;
    description
      "Unable to encode notification messages in the desired
       format.";
  }

  identity filter-unavailable {
    base subscription-terminated-reason;
    description
      "Referenced filter does not exist.  This means a receiver is
       referencing a filter that doesn't exist or to which it
       does not have access permissions.";
  }

  identity filter-unsupported {
    base establish-subscription-error;
    description
      "Cannot parse syntax in the filter.  This failure can be from
       a syntax error or a syntax too complex to be processed by the
       publisher.";
  }

  identity insufficient-resources {
    base establish-subscription-error;
    description
      "The publisher does not have sufficient resources to support
       the requested subscription.  An example might be that
       allocated CPU is too limited to generate the desired set of
       notification messages.";
  }

  identity no-such-subscription {
    base delete-subscription-error;
    base subscription-terminated-reason;
    description
      "Referenced subscription doesn't exist.  This may be as a
       result of a nonexistent subscription ID, an ID that belongs to
       another subscriber, or an ID for a configured subscription.";
  }

  identity stream-unavailable {
    base subscription-terminated-reason;
    description
      "Not a subscribable event stream.  This means the referenced
       event stream is not available for subscription by the
       receiver.";
  }

  identity suspension-timeout {
    base subscription-terminated-reason;
    description
      "Termination of a previously suspended subscription.  The
       publisher has eliminated the subscription, as it exceeded a
       time limit for suspension.";
  }

  identity unsupportable-volume {
    base subscription-terminated-reason;
    description
      "The publisher does not have the network bandwidth needed to
       get the volume of generated information intended for a
       receiver.";
  }

  identity conflicting-identifier {
    base subscription-terminated-reason;
    description
      "The subscription identifier conflicts with another
       subscription.

       This can prevent a dynamic subscription from being
       established, or cause a dynamic subscription to be terminated
       if a configured subscription with the same id is created.";

    // TODO - Should there be separate error codes for creating a
    // subscription vs terminating an existing one?
  }


  /* Identities for encodings */

  identity encoding {
    description
      "Base identity to represent data encodings.";
  }

  identity json {
    base encoding;
    description
      "Encode data using JSON as described in RFC 7951.";
    reference
      "RFC 7951: JSON Encoding of Data Modeled with YANG";
  }

  identity xml {
    base encoding;
    description
      "Encode data using XML as described in RFC 7950.";
    reference
      "RFC 7950: The YANG 1.1 Data Modeling Language";
  }

  identity cbor {
    base encoding;
    description
      "Encode data using CBOR as described in RFC 9254,
       using text identifiers instead of YANG SIDs.";
    reference
      "RFC 9254: Encoding of Data Modeled with YANG in the
       Concise Binary Object Representation (CBOR).";
  }

  identity cbor-sids {
    base encoding;
    description
      "Encode data using CBOR as described in RFC 9254, using YANG
       SIDs allocated as described in RFC 9595.";
    reference
      "RFC 9254: Encoding of Data Modeled with YANG in the
       Concise Binary Object Representation (CBOR).

       RFC 9595: YANG Schema Item iDentifier (YANG SID).";
  }

  /* Identities for transports */

  identity transport {
    description
      "An identity that represents the underlying mechanism for
       passing notification messages.";
  }


  /*
   * TYPEDEFs
   */

  typedef ypath {
    type string {
      length "1..max";
    }
    description
      "A type for YANG instance data paths.";
  }

  typedef encoding {
    type identityref {
      base encoding;
    }
    description
      "Specifies a data encoding, e.g., for a data subscription.";
  }

  typedef subscription-id {
   type string {
      length "1..64";
      pattern '[A-Za-z0-9._-]+';
    }
    description
      "A used friendly string identifier for a subscription.";
  }

  typedef transport {
    type identityref {
      base transport;
    }
    description
      "Specifies the transport used to send notification messages
       to a receiver.";
  }

// TODO - Consider changes to list keys or reordering of
//        user-ordered lists.

  typedef centiseconds {
    type uint32;
    description
      "A period of time, measured in units of 0.01 seconds.";
  }

  typedef subscription-type {
    type enumeration {
      enum configured {
        description
          "A subscription that is created and managed via
           configuration.";
      }
      enum dynamic {
        description
          "A subscription that is created and managed via RPC
           primitives.";
      }
    }
    description
      "Indicate the type of subscription.";
  }

  typedef subscription-status {
    type enumeration {
      enum invalid {
        description
          "The subscription as a whole is unsupportable with its
          current parameters.";
      }
      enum inactive {
        description
          "The subscription is supportable with its current
          parameters, but it is not currently connected to a
          receiver";
      }
      enum active {
        description
          "The subscription is actively running, and is connected
           to at least one receiver.

           A subscription-started notification must have been sent
           for a subscription to be in this state, and the receiver
           will receive update notifications, as per the
           update-trigger selection.";
      }
    }
    description
      "Indicates the status of a subscription";
  }

  typedef subscription-change {
    type enumeration {
      enum new-subscription {
        description
          "This is a new subscription.";
      }
      enum deleted {
        description
          "The subscription has been unconfigured or deleted via
           a delete-subscription RPC";
      }
      enum killed {
        description
          "A dynamic subscription has been killed via a
           kill-subscription RPC";
      }
      enum receiver-added {
        description
          "A new receiver has been added to a configured
           subscription, and has connected successfully.";
      }
      enum receiver-removed {
        description
          "A receiver has been removed from a configured
           subscription, or has become disconnected.";
      }
      enum config-changed {
        description
          "The subscription configuration has been changed,
           requiring the subscription to be restarted.";
      }
    }

    description
      "Indicates the reason why a subscription has changed.";
  }

  /*
   * GROUPINGS
   */

  grouping dscp {
    description
      "This grouping describes QoS information concerning a
       subscription.  This information is passed to lower layers
       for transport prioritization and treatment.";
    leaf dscp {
      type inet:dscp;
      default "0";
      description
        "The desired network transport priority level.  This is the
         priority set on notification messages encapsulating the
         results of the subscription.  This transport priority is
         shared for all receivers of a given subscription.";
    }
  }

  grouping publishers {
    description
      "Grouping describes the list of publisher-ids";
    leaf-list publisher-id {
      type uint32;
      default 0;
      config false;
      description
        "Identifies the software process which publishes notification
        messages (e.g., processor 1 on line card 1). This field
        is used to notify the receiver which publisher processes
        are going to publish. The identifiers are locally unique to
        the Network Node. A publisher removed from and re-added to a
        subscription MUST be allocated a new identifier. Removed
        identifiers MUST NOT be reused within that subscription's
        lifetime.";
    }
  }

  grouping filter-choice {
    description
      "This grouping defines the types of selectors for objects
       from a datastore.";
    choice filter {
      mandatory true;
      description
        "The content filter specification for this request.";

      leaf path {
        type ypath;
        mandatory true;
        description
          "A basic path filter that allows wildcard, regex, or
           fixed value for list keys.  Each format is TODO";
      }
      anydata subtree {
        if-feature "yp2:subtree";
        mandatory true;
        description
          "This parameter identifies the portions of the
           target datastore to retrieve.";
        reference
          "RFC 6241: Network Configuration Protocol (NETCONF),
                     Section 6";
      }
      leaf xpath {
        if-feature "yp2:xpath";
        type yang:xpath1.0;
        mandatory true;
        description
          "This parameter contains an XPath expression identifying
           the portions of the target datastore to retrieve.

           If the expression returns a node set, all nodes in the
           node set are selected by the filter.  Otherwise, if the
           expression does not return a node set, the filter
           doesn't select any nodes.

           The expression is evaluated in the following XPath
           context:

           o  The set of namespace declarations is the set of prefix
              and namespace pairs for all YANG modules implemented
              by the server, where the prefix is the YANG module
              name and the namespace is as defined by the
              'namespace' statement in the YANG module.

              If the leaf is encoded in XML, all namespace
              declarations in scope on the 'stream-xpath-filter'
              leaf element are added to the set of namespace
              declarations.  If a prefix found in the XML is
              already present in the set of namespace declarations,
              the namespace in the XML is used.

           o  The set of variable bindings is empty.

           o  The function library is comprised of the core
              function library and the XPath functions defined in
              Section 10 in RFC 7950.

           o  The context node is the root node of the target
              datastore.";
        reference
          "XML Path Language (XPath) Version 1.0
           (https://www.w3.org/TR/1999/REC-xpath-19991116)
           RFC 7950: The YANG 1.1 Data Modeling Language,
                     Section 10";
      }
    }
  }

  grouping update-policy {
    description
      "This grouping describes the susbcription update policy";

    container update-trigger {
      description
        "This container describes all conditions under which
         subscription update messages are generated";

      container periodic {
        presence "indicates a periodic subscription";
        description
          "The publisher is requested to periodically notify the
            receiver regarding the current values of the datastore
            as defined by the selection filter.";
        leaf period {
          type centiseconds;
          mandatory true;
          description
            "Duration of time that should occur between periodic
              push updates, in units of 0.01 seconds.";
        }
        leaf anchor-time {
          type yang:date-and-time;
          description
            "Designates a timestamp before or after which a series
              of periodic push updates are determined.  The next
              update will take place at a point in time that is a
              multiple of a period from the 'anchor-time'.
              For example, for an 'anchor-time' that is set for the
              top of a particular minute and a period interval of a
              minute, updates will be sent at the top of every
              minute that this subscription is active.";
        }
      }
      container on-change {
        if-feature "on-change";
        presence "indicates an on-change subscription";
        description
          "The publisher is requested to notify the receiver
            regarding changes in values in the datastore subset as
            defined by a selection filter.";

        leaf sync-on-start {
          type boolean;
          default "true";
          description
            "When this object is set to 'false', (1) it restricts an
             on-change subscription from sending 'push-update'
             notifications and (2) pushing a full selection per the
             terms of the selection filter MUST NOT be done for
             this subscription.  Only updates about changes
             (i.e., only 'push-change-update' notifications)
             are sent.  When set to 'true' (the default behavior),
             in order to facilitate a receiver's synchronization,
             a full update is sent, via a 'push-update' notification,
             when the subscription starts.  After that,
             'push-change-update' notifications are exclusively sent,
             unless the publisher chooses to resync the subscription
             via a new 'push-update' notification.";
        }
      }
    }
  }

  grouping subscription-id {
    description
      "This grouping describes the subscription identifier.";

    leaf id {
      type subscription-id;
      mandatory true;
      description
        "The unique identifier for the subscription.";
    }
  }

  grouping client-subscription-id {
    description
      "This grouping describes a subscription identifier that
       cannot start with 'dyn-', which is reserved for dynamically
       created subscriptions.";

    leaf id {
      type subscription-id {
        pattern "dyn-.*" {
          modifier "invert-match";
        }
      }
      description
        "A identifier for the subscription, that MUST be unique
        across all configured and dynamic subscriptions.

        MUST NOT start with 'dyn-' which is reserved for
        dynamic subscriptions created by the publisher.";
    }
  }

  grouping subscription-schema {
    description
      "This grouping describes schema information related to a
       subscription.";

    leaf schema-id {
      type string;
      description
        "Indicates the version of the YANG schema used for this
        subscription.  The schema-id MUST change if the schema
        associated with the subscription changes.  The schema-id
        MAY change if the device schema changes, even if the
        change does not affect the subscription.";
    }

    leaf yang-library-content-id {
      type leafref {
        path "/yanglib:yang-library/yanglib:content-id";
      }
      description
        "Contains the YANG library content identifier.";
    }
  }

  grouping subscription-common {
    description
      "Common settings that are shared between dynamic and
       configured subscriptions.";

    leaf description {
      type string {
        length "1..1000";
      }
      description
        "Open text allowing a configuring entity to embed the
         originator or other specifics of this subscription.";
    }

    container target {
      description
        "Identifies the source of information against which a
         subscription is being applied as well as specifics on the
         subset of information desired from that source.";
      leaf datastore {
        type identityref {
          base ds:datastore;
        }
        default "ds:operational";
        description
          "Datastore from which to retrieve data, defaults to
           operational";
      }

      uses filter-choice;
    }

    uses update-policy;
  }


  /*
   * RPCs
   */

  rpc establish-subscription {
    if-feature "dynamic";
    description
      "This RPC allows a subscriber to create (and possibly
       negotiate) a subscription on its own behalf.  If successful,
       the subscription remains in effect for the duration of the
       subscriber's association with the publisher or until the
       subscription is terminated.  If an error occurs or the
       publisher cannot meet the terms of a subscription, an RPC
       error is returned, and the subscription is not created.
       In that case, the RPC reply's 'error-info' MAY include
       suggested parameter settings that would have a higher
       likelihood of succeeding in a subsequent
       'establish-subscription' request.";
    input {
      uses client-subscription-id {
        refine id {
          description
            "A optional identifier for a dynamic
             subscription, that must be unique across all
             configured and dynamic subscriptions.

             MUST NOT start with 'dyn-'.

             If not provided, the publisher MUST generate a unique
             identifier for the subscription, with an identifier
             that starts with 'dyn-', which is returned to the
             client in the RPC reply.";
        }
      }
      uses subscription-common;

      leaf encoding {
        type encoding;
        mandatory true;
        description
          "The encoding for the entire notification, including its
           envelope and contents. This MUST match the encoding of
           this establish-subscription RPC. An unsupported encoding
           MUST be rejected with encoding-unsupported. This applies
           to all notifications for the subscription, including
           subscription lifecycle notifications.";
      }

      uses dscp;

    }
    output {
      leaf id {
        type subscription-id;
        mandatory true;
        description
          "Identifier used for this subscription.";
      }
    }
  }

  rpc modify-subscription {
    if-feature "dynamic";
    description
      "This RPC allows a subscriber to modify a dynamic
       subscription's parameters.  If successful, the changed
       subscription parameters remain in effect for the duration of
       the subscription, until the subscription is again modified, or
       until the subscription is terminated.  In the case of an error
       or an inability to meet the modified parameters, the
       subscription is not modified and the original subscription
       parameters remain in effect.";
    input {
      uses subscription-id;
      uses subscription-common;

      uses dscp;

    }
    //output {
      // leaf id {
      //   type subscription-id;
      //   mandatory true;
      //   description
      //     "Identifier used for this subscription.";
      // }
    //}
  }

  sx:structure establish-subscription-stream-error-info {
    container establish-subscription-stream-error-info {
      description
        "If any 'establish-subscription' RPC parameters are
         unsupportable against the event stream, a subscription
         is not created and the RPC error response MUST indicate the
         reason why the subscription failed to be created.  This
         yang-data MAY be inserted as structured data in a
         subscription's RPC error response to indicate the reason for
         the failure.  This yang-data MUST be inserted if hints are
         to be provided back to the subscriber.";
      leaf reason {
        type identityref {
          base establish-subscription-error;
        }
        description
          "Indicates the reason why the subscription has failed to
           be created to a targeted event stream.";
      }
      leaf filter-failure-hint {
        type string;
        description
          "Information describing where and/or why a provided
           filter was unsupportable for a subscription.  The
           syntax and semantics of this hint are
           implementation specific.";
      }
    }
  }

  rpc delete-subscription {
    if-feature "dynamic";
    description
      "This RPC allows a subscriber to delete a subscription that
       was previously created by that same subscriber using the
       'establish-subscription' RPC.

       Only subscriptions that were created using
       'establish-subscription' from the same origin as this RPC
       can be deleted via this RPC. // TODO - Why same origin?

       If an error occurs, the server replies with an 'rpc-error'
       where the 'error-info' field MAY contain a
       'delete-subscription-error-info' structure.";
    input {
      leaf id {
        type subscription-id;
        mandatory true;
        description
          "The name of the dynamic subscription to be deleted.";
      }
    }
  }

  rpc kill-subscription {
    if-feature "dynamic";
    nacm:default-deny-all;
    description
      "This RPC allows an operator to delete a dynamic subscription
       without restrictions on the originating subscriber or
       underlying transport session.

       Only dynamic subscriptions, i.e., those that were created
       using 'establish-subscription', may be deleted via this RPC.

       If an error occurs, the server replies with an 'rpc-error'
       where the 'error-info' field MAY contain a
       'delete-subscription-error-info' structure.";
    input {
      leaf id {
        type subscription-id;
        mandatory true;
        description
          "The name of the dynamic subscription to be deleted.";
      }
    }
  }

  sx:structure delete-subscription-error-info {
    container delete-subscription-error-info {
      description
        "If a 'delete-subscription' RPC or a 'kill-subscription' RPC
         fails, the subscription is not deleted and the RPC error
         response MUST indicate the reason for this failure.  This
         yang-data MAY be inserted as structured data in a
         subscription's RPC error response to indicate the reason
         for the failure.";
      leaf reason {
        type identityref {
          base delete-subscription-error;
        }
        mandatory true;
        description
          "Indicates the reason why the subscription has failed to be
           deleted.";
      }
    }
  }

  /*
   * NOTIFICATIONS
   */

  grouping subscription-update-common {
    description
      "Data nodes common to both subscription-started and
       subscription-modified notifications.";

    uses subscription-id;
    uses subscription-common {
      augment "target" {
        description
          "Augments fields to identify the target schema.";
        uses subscription-schema;
      }
    }
    container message-publishers {
      description
        "Holds the publisher-ids for all processes currently
         associated with the subscription";
        uses yp2:publishers;
    }
  }

  notification subscription-started {
    description
      "This notification indicates that a subscription has started
       and notifications will now be sent.";
       uses subscription-update-common;
  }

  notification subscription-modified {
    description
      "This notification indicates that subscription paramaters have
       changed.";
    uses subscription-update-common;

    leaf reason {
      type subscription-change;
      mandatory true;
      description
        "Gives a hint for the message recipient as to why the
         notification has been sent.";
    }
  }

  notification subscription-terminated {
    description
      "This notification indicates that a subscription has been
       terminated.";
    uses subscription-id;
    leaf reason {
      type identityref {
        base subscription-terminated-reason;
      }
      mandatory true;
      description
        "Identifies the condition that resulted in the
         termination.";
    }
  }

  notification update {
    description
      "This notification contains a push update that in turn
       contains data subscribed to via a subscription.  In the case
       of a periodic subscription, this notification is sent for
       periodic updates.  It can also be used for synchronization
       updates of an on-change subscription.  This notification
       shall only be sent to receivers of a subscription.";
    leaf id {
      type subscription-id;
      description
        "The identifier of the subscription that is the source of
         this notification.";
    }

    leaf path-prefix {
      type string {
        length '2..max';
        pattern '/[^/].*' {
          error-message
            "path-prefix must start with '/' and contain at least "
          + "one path segment.";
        }
      }
      description
        "If present, this MUST be an absolute path from the
         schema root, starting with '/' and containing at least
         one path segment.  Neither an empty string nor '/'
         is permitted.  It specifies the common prefix for all
         target values in this notification.

         TODO - This should be a JSONified instance data path.";
    }

    leaf snapshot-type {
      type enumeration {
        enum "periodic" {
          description
            "The update message is due to a periodic update.";
        }
        enum "on-change" {
          description
            "The update message is due to an on-change event and
             may contain both update and delete operations.";
        }
        enum "resync" {
          description
            "This indicates that the update is to resynchronize the
             state, e.g., after a subscription started notification.

             Ideally, the resync message SHOULD be the first
             notification sent when a subscription has started, but
             it is not gauranteed or required to be the first
             (e.g., if an on-change event occurs).

             These messages can be used to ensure that all state
             has been sent to the client, and can be used to purge
             stale data.";
        }
      }
      mandatory true;
      description
        "This indicates the type of notification message that is
         being sent.";
    }

    leaf observation-time {
      type yang:date-and-time;
      description
        "The most accurate available time when the reported data
         was sampled for a periodic or resynchronization update,
         or when the underlying creation, modification, or deletion
         event first occurred for an on-change update.";
    }

    list updates {
      key "target";
      description
        "Each entry reports updated values or the deletion of the
         data node identified by target.  A notification may
         contain a partial snapshot of the subscribed data.

         Receivers MAY process the updates list entries in any
         order.  Consequently, the list MUST NOT contain duplicate
         target values within a single notification.  The
         target is the list key, so duplicate values are
         invalid YANG.  The list MUST NOT contain both a delete
         entry for a data node and an update entry whose
         target identifies a descendant of that deleted
         node.";

      leaf target {
        type string {
          length "1..max";
        }
        must "../../path-prefix or "
           + "starts-with(., '/')" {
          error-message
            "Without a path-prefix, target must be an "
          + "absolute path starting with '/'.";
        }
        must "not(../../path-prefix) or "
           + "not(starts-with(., '/'))" {
          error-message
            "With a path-prefix, target must be relative "
          + "and must not start with '/'.";
        }
        description
          "Identifies the data being updated or deleted.  As the
           updates list key, target MUST be present in every entry
           and MUST NOT be empty.  When path-prefix is absent,
           target MUST be an
           absolute path from the schema root, starting with '/'.
           When path-prefix is present, target MUST be relative
           and MUST NOT start with '/'.

           With a path-prefix, the full target path is
           formed by appending the target path segments to the
           prefix, using a single '/' between path segments.
           Otherwise, target itself is the full target path.
           A full target path of '/' identifies the entire
           datastore and MUST be represented by omitting
           path-prefix and setting target to '/'.";
      }

      choice data {
        mandatory true;
        description
          "Selects either an update of the supplied data or deletion
           of the data node at the target path.";
        anydata update {
          description
            "The current values of the supplied data nodes.  The
             receiver creates data nodes that do not yet exist and
             replaces the values of existing leaf and leaf-list
             nodes that are supplied.  Containers and list entries
             are updated recursively, with list entries identified
             by their keys.  Required list keys are included.

             For on-change notifications, omitted descendant data
             nodes are unchanged; their absence does not imply
             deletion.

             For periodic and resynchronization collections,
             absence is used to infer deletion only after the
             complete snapshot of
             the subscribed data has been received, as indicated
             by complete or update-complete.

             The data is encoded relative to the full target path,
             formed by combining path-prefix and target.";
        }
        leaf delete {
          when "../../snapshot-type = 'on-change'" {
            description
              "Deletion is only permitted in on-change
               notifications, never in periodic or resync
               snapshots.";
          }
          type boolean;
          default "false";
          description
            "When true, the data node at the target path and all its
             descendants have been deleted.  This operation also
             removes the corresponding data from the receiver's
             view.  If the data is already absent, no action is
             required. When false, no deletion is indicated.
             This operation MUST only be used for
             on-change deletion events and MUST NOT be used in
             periodic or resync snapshots.";
        }
      }
    }

    leaf complete {
      when "../snapshot-type = 'periodic' or "
         + "../snapshot-type = 'resync'";
      type boolean;
      default "false";
      description
        "This flag applies only to periodic and resynchronization
         collections. When true, it indicates the end of this
         publisher's contribution to the collection identified by the
         subscription id and the envelope's event-time. The
         publisher is identified by the envelope's publisher-id.
         Receivers MUST track completion per publisher and MUST NOT
         consider the full collection complete until all publishers
         serving the subscription for that collection have indicated
         completion.
         The data need not have been sampled at a single instant.

         The 'update-complete' notification MAY be used as an
         alternative to setting this flag, and is semantically
         equivalent.";
    }
  }

  notification update-complete {
    description
      "This notification indicates the end of this publisher's
       contribution to a periodic or resynchronization collection,
       identified by the subscription id and the envelope's
       event-time.

       The publisher is identified by the envelope's publisher-id.
       Receivers MUST track completion per publisher and MUST NOT
       consider the full collection complete until all publishers
       serving the subscription for that collection have indicated
       completion. The receiver MAY then purge stale state within
       the complete snapshot's scope.

       Alternatively, the 'complete' flag in the update
       notification MAY be used instead of sending this notification
       as a separate message, and both are semantically equivalent.";
    leaf id {
      type subscription-id;
      description
        "The name of the subscription that is the source of
          this notification.";
    }
  }

  sx:structure envelope {
    description
      "Encapsulates each YANG Push v2 notification, including
       datastore updates, update-complete notifications, and
       subscription lifecycle notifications.";
    leaf event-time {
      type yang:date-and-time;
      mandatory true;
      description
        "The time the telemetry infrastructure began processing the
         collection, on-change event, or subscription lifecycle
         event. All notifications for the same collection or
         on-change event MUST use the same value, including any
         update-complete notification.";
    }
    leaf hostname {
      type inet:host-name;
      mandatory true;
      description
        "The hostname of the network node. This value is usually
        configured on the node by the administrator to identify
        the node in the network uniquely.";
    }
    leaf publisher-id {
      type uint32;
      default 0;
      description
        "Identifies the software process which publishes notification
         messages (e.g., processor 1 on line card 1). This field
         is used to notify the receiver which publisher process
         published which message. The identifier is locally unique to
         the Network Node. A publisher removed from and re-added to a
         subscription MUST be allocated a new identifier. Removed
         identifiers MUST NOT be reused within that subscription's
         lifetime.";
    }
    leaf sequence-number {
      type yang:counter32;
      mandatory true;
      description
        "Sequence number maintained independently for each
         publisher-id within a subscription. The first notification
         from each newly created or re-added publisher uses 1
         under its new publisher-id.
         Each subsequent notification from that publisher-id for
         that subscription increments the value by 1, wrapping from
         4294967295 to 0 and continuing. The counter
         MUST NOT be reset during the lifetime of the subscription.";
    }
    container extensions {
      description
        "This container is reserved for future extensions to the
         notification envelope.";
    }
    anydata contents {
      mandatory true;
      description
        "Contains exactly one notification, identified by the name
         of its YANG 'notification' statement and the namespace of
         the module defining that statement. The notification's
         data node values are carried unchanged.";
    }
  }
}

<CODE ENDS>
Figure 21: YANG module ietf-yang-push-2

15. Configured Subscription YANG Data Model

This document specifies the ietf-yang-push-2-config YANG module Section 15.2 that defines an NMDA [RFC8342] compatible YANG data model for configuring subscriptions. Support for this YANG module is OPTIONAL and is advertised using the normal mechanisms, e.g., [RFC8525].

Below is a tree diagram for the "subscriptions" container. All objects contained in this tree are described in the YANG module in Section 14.2. In the operational datastore [RFC8342], the "subscription" list contains entries both for configured and dynamic subscriptions.

module: ietf-yang-push-2-config
  +--rw datastore-telemetry!
     +--rw subscriptions
        +--rw subscription* [id]
           +--rw id                    subscription-id
           +--rw description?          string
           +--rw target
           |  +--rw datastore?          identityref
           |  +--rw (filter)
           |     +--:(path)
           |     |  +--rw path          ypath
           |     +--:(subtree)
           |     |  +--rw subtree       <anydata> {yp2:subtree}?
           |     +--:(xpath)
           |     |  +--rw xpath         yang:xpath1.0 {yp2:xpath}?
           |     +--:(by-reference)
           |        +--rw filter-ref    filter-ref
           +--rw update-trigger
           |  +--rw periodic!
           |  |  +--rw period         centiseconds
           |  |  +--rw anchor-time?   yang:date-and-time
           |  +--rw on-change! {on-change}?
           |     +--rw sync-on-start?   boolean
           +--rw receiver
           |       -> /datastore-telemetry/receivers/receiver/name
           +--ro status?               yp2:subscription-status
           +--ro type?                 yp2:subscription-type
           +--ro encoding?             yp2:encoding
           +--ro message-publishers* [publisher-id]
           |  +--ro publisher-id    uint32
           |  +--ro events
           |  |  +--ro last-status-change-time?
           |  |  |       yang:zero-based-counter64
           |  |  +--ro last-sequence-number?
           |  |  |       yang:zero-based-counter64
           |  |  +--ro last-update-notification-time?
           |  |  |       yang:date-and-time
           |  |  +--ro last-on-change-update-notification-time?
           |  |  |       yang:date-and-time
           |  |  +--ro last-error-time?
           |  |          yang:date-and-time
           |  +--ro statistics
           |     +--ro update-notifications?
           |     |       yang:zero-based-counter64
           |     +--ro on-change-update-notifications?
           |     |       yang:zero-based-counter64
           |     +--ro packets-sent?
           |     |       yang:zero-based-counter64
           |     +--ro bytes-sent?
           |     |       yang:zero-based-counter64
           |     +--ro receiver-disconnects?
           |     |       yang:zero-based-counter64
           |     +--ro errors?
           |             yang:zero-based-counter64
           +---x reset

  augment /yp2:subscription-started/yp2:target:
    +-- filter-ref?   filter-ref
  augment /yp2:subscription-modified/yp2:target:
    +-- filter-ref?   filter-ref
Figure 22: subscriptions container Tree Diagram

An overview of the behavior for configured subscriptions is specified in Section 9.3, with further details specified in the ietf-yang-push-2-config YANG module.

15.1. ietf-yang-push-2-config YANG tree

This section shows the full tree output for ietf-yang-push-2-config YANG module.

Note, this output does not include support for any transport configuration, and for any implementation that supports configured subscriptions using this YANG module then at least one transport would expect to be configurable.

module: ietf-yang-push-2-config
  +--rw datastore-telemetry!
     +--rw filters
     |  +--rw filter* [name]
     |     +--rw name             string
     |     +--rw (filter)
     |        +--:(path)
     |        |  +--rw path       ypath
     |        +--:(subtree)
     |        |  +--rw subtree    <anydata> {yp2:subtree}?
     |        +--:(xpath)
     |           +--rw xpath      yang:xpath1.0 {yp2:xpath}?
     +--rw subscriptions
     |  +--rw subscription* [id]
     |     +--rw id                    subscription-id
     |     +--rw description?          string
     |     +--rw target
     |     |  +--rw datastore?          identityref
     |     |  +--rw (filter)
     |     |     +--:(path)
     |     |     |  +--rw path          ypath
     |     |     +--:(subtree)
     |     |     |  +--rw subtree       <anydata> {yp2:subtree}?
     |     |     +--:(xpath)
     |     |     |  +--rw xpath         yang:xpath1.0 {yp2:xpath}?
     |     |     +--:(by-reference)
     |     |        +--rw filter-ref    filter-ref
     |     +--rw update-trigger
     |     |  +--rw periodic!
     |     |  |  +--rw period         centiseconds
     |     |  |  +--rw anchor-time?   yang:date-and-time
     |     |  +--rw on-change! {on-change}?
     |     |     +--rw sync-on-start?   boolean
     |     +--rw receiver
     |     |       -> /datastore-telemetry/receivers/receiver/name
     |     +--ro status?               yp2:subscription-status
     |     +--ro type?                 yp2:subscription-type
     |     +--ro encoding?             yp2:encoding
     |     +--ro message-publishers* [publisher-id]
     |     |  +--ro publisher-id    uint32
     |     |  +--ro events
     |     |  |  +--ro last-status-change-time?
     |     |  |  |       yang:zero-based-counter64
     |     |  |  +--ro last-sequence-number?
     |     |  |  |       yang:zero-based-counter64
     |     |  |  +--ro last-update-notification-time?
     |     |  |  |       yang:date-and-time
     |     |  |  +--ro last-on-change-update-notification-time?
     |     |  |  |       yang:date-and-time
     |     |  |  +--ro last-error-time?
     |     |  |          yang:date-and-time
     |     |  +--ro statistics
     |     |     +--ro update-notifications?
     |     |     |       yang:zero-based-counter64
     |     |     +--ro on-change-update-notifications?
     |     |     |       yang:zero-based-counter64
     |     |     +--ro packets-sent?
     |     |     |       yang:zero-based-counter64
     |     |     +--ro bytes-sent?
     |     |     |       yang:zero-based-counter64
     |     |     +--ro receiver-disconnects?
     |     |     |       yang:zero-based-counter64
     |     |     +--ro errors?
     |     |             yang:zero-based-counter64
     |     +---x reset
     +--rw receivers
        +--rw receiver* [name]
           +--rw name                      string
           +--rw encoding                  yp2:encoding
           +--rw dscp?                     inet:dscp
           +---x reset
           +--rw (notification-message-origin)?
           |  +--:(interface-originated)
           |  |  +--rw source-interface?   if:interface-ref
           |  |          {interface-designation}?
           |  +--:(address-originated)
           |     +--rw source-vrf?         leafref {supports-vrf}?
           |     +--rw source-address?     inet:ip-address-no-zone
           +--rw (transport-type)

  augment /yp2:subscription-started/yp2:target:
    +-- filter-ref?   filter-ref
  augment /yp2:subscription-modified/yp2:target:
    +-- filter-ref?   filter-ref
Figure 23: YANG tree for YANG Push v2 Config Module Tree Output

15.2. ietf-yang-push-2-config YANG Model

This module has import dependencies on [RFC6991], [RFC8343], and [RFC8529], and ietf-yang-push-lite.yang (this RFC). In addition, this YANG module references [BCP14] ([RFC2119] [RFC8174]), and [RFC8529].

<CODE BEGINS> file "ietf-yang-push-2-config.yang#0.1.0"

module ietf-yang-push-2-config {
  yang-version 1.1;
  namespace
    "urn:ietf:params:xml:ns:yang:ietf-yang-push-2-config";
  prefix yp2co;

  import ietf-inet-types {
    prefix inet;
    reference
      "RFC 6991: Common YANG Data Types";
  }
  import ietf-interfaces {
    prefix if;
    reference
      "RFC 8343: A YANG Data Model for Interface Management";
  }
  import ietf-network-instance {
    prefix ni;
    reference
      "RFC 8529: YANG Data Model for Network Instances";
  }
  import ietf-yang-types {
    prefix yang;
    reference
      "RFC 6991: Common YANG Data Types";
  }
  import ietf-yang-push-2 {
    prefix yp2;
    reference
      "RFC XXXX: YANG Datastore Telemetry (YANG Push version 2)";
  }

  organization
    "IETF NETCONF (Network Configuration) Working Group";
  contact
    "WG Web:  <https:/datatracker.ietf.org/wg/netconf/>
     WG List: <mailto:netconf@ietf.org>

     Author:  Robert Wilton
              <mailto:rwilton@cisco.com>";
  description
    "This module contains YANG specifications for YANG-Push version 2
     configuration and operational state model.

     The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
     NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
     'MAY', and 'OPTIONAL' in this document are to be interpreted as
     described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
     they appear in all capitals, as shown here.

     Copyright (c) 2025 IETF Trust and the persons identified as
     authors of the code.  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 Revised BSD License set
     forth in Section 4.c of the IETF Trust's Legal Provisions
     Relating to IETF Documents
     (https://trustee.ietf.org/license-info).

     This version of this YANG module is part of RFC XXXX
     (https://www.rfc-editor.org/info/rfcXXXX); see the RFC itself
     for full legal notices.";

  revision 2025-08-03 {
    description
      "Initial revision.";
    reference
      "XXX: YANG Datastore Telemetry (YANG Push version 2)";
  }

  /*
   * FEATURES
   */

  feature interface-designation {
    description
      "This feature indicates that a publisher supports sourcing all
       receiver interactions for a configured subscription from a
       single designated egress interface.";
  }

  feature supports-vrf {
    description
      "This feature indicates that a publisher supports VRF
       configuration for configured subscriptions.  VRF support for
       dynamic subscriptions does not require this feature.";
    reference
      "RFC 8529: YANG Data Model for Network Instances,
                 Section 6";
  }

  /*
   * TYPEDEFs
   */

  typedef filter-ref {
    type leafref {
      path "/datastore-telemetry/filters/filter/name";
    }
    description
      "This type is used to reference a selection filter.";
  }

  /*
   * GROUPINGS
   */
  grouping filter-ref {
    description
      "This grouping is used to reference a selection filter.";
    leaf filter-ref {
      type filter-ref;
      mandatory true;
      description
        "References an existing selection filter that is to be
        applied to the subscription.";
    }
  }

  /*
   * DATA NODES
   */

  container datastore-telemetry {
    presence "Enables datastore telemetry";
    description
    "YANG Push v2 Datastore Telemetry Configuration and State.";
    container filters {
      description
        "Contains a list of configurable filters that can be applied
         to subscriptions.  This facilitates the reuse of complex
         filters once defined.";

      list filter {
        key "name";
        description
          "A list of preconfigured filters that can be applied
          to datastore subscriptions.";
        leaf name {
          type string {
            length "1..64";
            pattern '[A-Za-z0-9._-]+';
          }
          description
            "A unique name to identify the selection filters.";
        }
        uses yp2:filter-choice;
      }
    }
    container subscriptions {
      description
        "Contains the list of currently active subscriptions, i.e.,
        subscriptions that are currently in effect, used for
        subscription management and monitoring purposes.  This
        includes subscriptions that have been set up via
        RPC primitives as well as subscriptions that have been
        established via configuration.";
      list subscription {
        key "id";
        description
          "The identity and specific parameters of a subscription.
          Subscriptions in this list can be created using a control
          channel or RPC or can be established through configuration.

          If the 'kill-subscription' RPC or configuration operations
          are used to delete a subscription, a
          'subscription-terminated' message is sent to any active or
          suspended receivers.";

        uses yp2:client-subscription-id;
        uses yp2:subscription-common;

        leaf receiver {
          type leafref {
            path "/datastore-telemetry/receivers/receiver/name";
          }
          mandatory true;
          description
            "Identifies the receiver for a subscription.";
        }

        // leaf status {
        //   type enumeration {
        //     enum disconnected {
        //       description
        //         "This subscription does not have an active session
        //           with the receiver, and it is not trying to
        //           connect.

        //         E.g., this state may be reported if the
        //         subscription is not valid, or has not been started
        //         yet.";
        //     }
        //     enum connecting {
        //       description
        //         "The publisher is trying to establish a session
        //           with the receiver for this subscription.

        //           For a session less transport, this state may be
        //           used to indicate that there is no route to the
        //           receiver.

        //           A receiver in connecting state may indicate that
        //           the transport or associated security session
        //           could not be established, and the publisher is
        //         periodically trying to establish the connection.";
        //     }
        //     enum active {
        //       description
        //         "The publisher has successfully connected (if over
        //           a session based transport) to the receiver for
        //           this subscription, and the publisher is able to
        //           send notifications to the receiver.";
        //     }
        //   }
        //   config false;
        //   description
        //     "Specifies the connection status of the receiver for
        //       this subscription.";
        // }

        leaf status {
          type yp2:subscription-status;
          config false;
          description
            "The presence of this leaf indicates that the
             subscription originated from configuration, not through
             a control channel or RPC.  The value indicates the state
             of the subscription as established by the publisher.";
        }

        leaf type {
          type yp2:subscription-type;
          default "configured";
          config false;
          description
            "Whether the subscription is configured or dynamic.";
        }

        leaf encoding {
          type yp2:encoding;
          config false;
          description
            "The encoding of the entire notification, including its
             envelope and contents. For a dynamic subscription,
             this matches the encoding of the establish-subscription
             RPC.";
        }

        list message-publishers {
          key "publisher-id";
          config false;
          description
            "Holds per publisher-id information for all processes
             currently associated with the subscription";
          leaf publisher-id {
            type uint32;
//            default 0;
            description
              "Identifies the software process which publishes
               notification messages (e.g., processor 1 on line
               card 1). This field is used to notify the receiver
               which publisher processes are going to publish.
               The identifiers are locally unique to the Network
               Node.";
          }

          container events {
            description
              "Holds event information for the subscription.";

            leaf last-status-change-time {
              type yang:zero-based-counter64;
              config false;
              description
                "The timestamp when the subscription status last
                changed";
            }

            leaf last-sequence-number {
              type yang:zero-based-counter64;
              config false;
              description
                "The envelope sequence number for the last
                 notification sent for this subscription from this
                 publisher.";
            }

            leaf last-update-notification-time {
              type yang:date-and-time;
              config false;
              description
                "The timestamp of the last update notification, of
                 any type from this publisher.";
            }

            leaf last-on-change-update-notification-time {
              type yang:date-and-time;
              config false;
              description
                "The timestamp of the last update notification for
                 an on-change event from this publisher.";
            }

            leaf last-error-time {
              type yang:date-and-time;
              config false;
              description
                "The timestamp of the last time an error occurred
                 on this subscription.  E.g., failing to retrieve
                 some of the data, failing to encode some data.";
            }
          }

          container statistics {
            description
              "Statistics related to the number of messages or
              notifications generated for this publisher
              for this subscription.

              All counters are initialized to zero when the
              subscription is first created.";

            leaf update-notifications {
              type yang:zero-based-counter64;
              description
                "The number of *update* notifications generated.

                 Excludes update-complete notifications.

                 The count is re-initialized to 0 when the
                 subscription is first created.";
            }

            leaf on-change-update-notifications {
              type yang:zero-based-counter64;
              description
                "The number of *on-change* update notifications
                 generated.

                 The count is re-initialized to 0 when the
                 subscription is first created.";
            }

            leaf packets-sent {
              type yang:zero-based-counter64;
              description
                "The total number of packets sent to the receiver.";
            }

            leaf bytes-sent {
              type yang:zero-based-counter64;
              description
                "The total number of bytes sent to the receiver.";
            }

            leaf receiver-disconnects {
              type yang:zero-based-counter64;
              description
                "The total number of times the receiver has been
                  disconnected.";
            }

            leaf errors {
              type yang:zero-based-counter64;
              description
                "The total number of errors that have occurred.";
            }
          }
        }

        action reset {
          description
            "Reset the subscription.

             This action will cause a new subscription-started
             message to be sent for the subscription";
        }
      }
    }
    container receivers {
      description
        "A container for all instances of configured receivers.";

      list receiver {
        key "name";

        leaf name {
          type string {
            length "1..64";
            pattern '[A-Za-z0-9._-]+';
          }
          description
            "An arbitrary but unique name for this receiver
            instance.";
        }

        leaf encoding {
          type yp2:encoding;
          mandatory true;
          description
            "The encoding of both the notification envelope and
             its contents for configured subscriptions referencing
             this receiver.";
        }

        uses yp2:dscp;

        action reset {
          description
            "Resets all configured subscriptions that reference
             this receiver.

             This action is similar to invoking the 'reset' action
             on all subscriptions that reference this receiver
             configuration.";
        }

        choice notification-message-origin {
          description
            "Identifies the egress interface on the publisher
            from which notification messages are to be sent.";
          case interface-originated {
            description
              "When notification messages are to egress a specific,
              designated interface on the publisher.";
            leaf source-interface {
              if-feature "interface-designation";
              type if:interface-ref;
              description
                "References the interface for notification
                 messages.";
            }
          }
          case address-originated {
            description
              "When notification messages are to depart from a
              publisher using a specific originating address and/or
              routing context information.";
            leaf source-vrf {
              if-feature "supports-vrf";
              type leafref {
                path
                  '/ni:network-instances/ni:network-instance/'
                  + 'ni:name';
              }
              description
                "VRF from which notification messages should egress a
                publisher.";
            }
            leaf source-address {
              type inet:ip-address-no-zone;
              description
                "The source address for the notification messages.
                If a source VRF exists but this object doesn't, a
                publisher's default address for that VRF must
                be used.";
            }
          }
        }

        choice transport-type {
          mandatory true;
          description
            "Choice of different types of transports used to
             send notifications.  The 'case' statements must
             be augmented in by other modules.";
        }

        description
          "A list of all receiver instances.";
      }
    }
  }

  augment "/yp2:subscription-started/yp2:target" {

    description
      "Allow a subscription-started notification to include a
       referenced named filter";
    uses filter-ref {
      refine "filter-ref" {
        mandatory false;
      }
    }
  }

  augment "/yp2:subscription-modified/yp2:target" {

    description
      "Allow a subscription-modified notification to include a
       referenced named filter";
    uses filter-ref {
      refine "filter-ref" {
        mandatory false;
      }
    }
  }

  augment "/datastore-telemetry/subscriptions/subscription/"
        + "target/filter" {

    description
      "Augment the subscription filter to allow
       referencing a filter configured separately.";

    case by-reference {
      description
        "Incorporates a filter that has been configured
         separately.";
      uses filter-ref;
    }
  }
}

<CODE ENDS>
Figure 24: YANG module ietf-yang-push-2-config

16. Capabilities YANG Data Model

16.1. ietf-yang-push-2-capabilities YANG tree

This section shows the tree output for ietf-yang-push-2-capabilities YANG module, which augments the ietf-system-capabilities YANG module [RFC9196].

module: ietf-yang-push-2-capabilities

  augment /sysc:system-capabilities:
    +--ro datastore-telemetry
    |  +--ro periodic-notifications-supported?   notification-support
    |  +--ro (update-period)?
    |  |  +--:(minimum-update-period)
    |  |  |  +--ro minimum-update-period?        uint32
    |  |  +--:(supported-update-period)
    |  |     +--ro supported-update-period*      uint32
    |  +--ro on-change-supported?                notification-support
    |  +--ro transport
    |     +--ro transport-capability* [transport-protocol]
    |        +--ro transport-protocol    identityref
    |        +--ro security-protocol?    identityref
    |        +--ro encoding-format*      identityref
    +--ro distributed-notifications-supported?   boolean
  augment /sysc:system-capabilities/sysc:datastore-capabilities
            /sysc:per-node-capabilities:
    +--ro datastore-telemetry
       +--ro periodic-notifications-supported?   notification-support
       +--ro (update-period)?
       |  +--:(minimum-update-period)
       |  |  +--ro minimum-update-period?        uint32
       |  +--:(supported-update-period)
       |     +--ro supported-update-period*      uint32
       +--ro on-change-supported?                notification-support
Figure 25: YANG tree for YANG Push v2 Capabilities Module Tree Output

16.2. ietf-yang-push-2-capabilities YANG Model

This module imports typedefs from the yang-push-lite YANG module.

This module augments the ietf-system-capabilities YANG module [RFC9196].

<CODE BEGINS> file "ietf-yang-push-2-capabilities.yang#0.1.0"

module ietf-yang-push-2-capabilities {
  yang-version 1.1;
  namespace
    "urn:ietf:params:xml:ns:yang:ietf-yang-push-2-capabilities";
  prefix yp2ca;

  import ietf-system-capabilities {
    prefix sysc;
    reference
      "RFC 9196: YANG Modules Describing Capabilities for Systems
       and Datastore Update Notifications";
  }
  import ietf-yang-push-2 {
    prefix yp2;
    reference
      "RFC XXX: YANG Datastore Telemetry (YANG Push version 2)";
  }

  organization
    "IETF NETCONF (Network Configuration) Working Group";
  contact
    "WG Web:  <https:/datatracker.ietf.org/wg/netconf/>
     WG List: <mailto:netconf@ietf.org>

     Author:  Robert Wilton
              <mailto:rwilton@cisco.com>";
  description
    "This module contains YANG specifications for YANG-Push lite.

     The key words 'MUST', 'MUST NOT', 'REQUIRED', 'SHALL', 'SHALL
     NOT', 'SHOULD', 'SHOULD NOT', 'RECOMMENDED', 'NOT RECOMMENDED',
     'MAY', and 'OPTIONAL' in this document are to be interpreted as
     described in BCP 14 (RFC 2119) (RFC 8174) when, and only when,
     they appear in all capitals, as shown here.

     Copyright (c) 2025 IETF Trust and the persons identified as
     authors of the code.  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 Revised BSD License set
     forth in Section 4.c of the IETF Trust's Legal Provisions
     Relating to IETF Documents
     (https://trustee.ietf.org/license-info).

     This version of this YANG module is part of RFC XXXX
     (https://www.rfc-editor.org/info/rfcXXXX); see the RFC itself
     for full legal notices.";

  revision 2024-11-11 {
    description
      "Initial revision.";
    reference
      "XXX: YANG Datastore Telemetry (YANG Push version 2)";
  }

  /*
   * IDENTITIES
   */

  identity security-protocol {
    description
      "Identity for security protocols.";
  }

  identity tls12 {
    base security-protocol;
    description
      "Indicates TLS Protocol Version 1.2. TLS 1.2 is obsolete,
       and thus it is NOT RECOMMENDED to enable this feature.";
    reference
      "RFC 5246: The Transport Layer Security (TLS) Protocol
                 Version 1.2";
  }

  identity tls13 {
    base security-protocol;
    description
      "Indicates TLS Protocol Version 1.3.";
    reference
      "RFC 8446: The Transport Layer Security (TLS)
                 Protocol Version 1.3";
  }

  identity dtls12 {
    base security-protocol;
    description
      "Indicates DTLS Protocol Version 1.2. TLS 1.2 is obsolete,
       and thus it is NOT RECOMMENDED to enable this feature.";
    reference
      "RFC 6347: The Datagram Transport Layer Security (TLS) Protocol
                 Version 1.2";
  }

  identity dtls13 {
    base security-protocol;
    description
      "Indicates DTLS Protocol Version 1.3.";
    reference
      "RFC 9147: The Datagram Transport Layer Security (TLS)
                 Protocol Version 1.3";
  }

  identity ssh {
    base security-protocol;
    description
      "Indicates SSH.";
  }


  grouping yp2-capabilities {
    description
      "Capabilities related to YANG Push Lite subscriptions
       and notifications";
    container datastore-telemetry {
      description
        "Capabilities related to YANG Push List subscriptions
         and notifications";
      typedef notification-support {
        type bits {
          bit config-changes {
            description
              "The publisher is capable of sending
               notifications for 'config true' nodes for the
               relevant scope and subscription type.";
          }
          bit state-changes {
            description
              "The publisher is capable of sending
               notifications for 'config false' nodes for the
               relevant scope and subscription type.";
          }
        }
        description
          "Type for defining whether 'on-change' or
           'periodic' notifications are supported for all data nodes,
           'config false' data nodes, 'config true' data nodes, or
           no data nodes.

           The bits config-changes or state-changes have no effect
           when they are set for a datastore or for a set of nodes
           that does not contain nodes with the indicated config
           value.  In those cases, the effect is the same as if no
           support was declared.  One example of this is indicating
           support for state-changes for a candidate datastore that
           has no effect.";
      }

      leaf periodic-notifications-supported {
        type notification-support;
        description
          "Specifies whether the publisher is capable of
           sending 'periodic' notifications for the selected
           data nodes, including any subtrees that may exist
           below them.";
        reference
          "RFC 8641: Subscription to YANG Notifications for
           Datastore Updates, 'periodic' subscription concept";
      }
      choice update-period {
        description
          "Supported update period value or values for
           'periodic' subscriptions.";
        leaf minimum-update-period {
          type uint32;
          units "centiseconds";
          description
            "Indicates the minimal update period that is
             supported for a 'periodic' subscription.

             A subscription request to the selected data nodes with
             a smaller period than what this leaf specifies is
             likely to result in a 'period-unsupported' error.";
        }
        leaf-list supported-update-period {
          type uint32;
          units "centiseconds";
          description
            "Supported update period values for a 'periodic'
             subscription.

             A subscription request to the selected data nodes with a
             period not included in the leaf-list will result in a
             'period-unsupported' error.";
        }
      }
      leaf on-change-supported {
        type notification-support;
        description
          "Specifies whether the publisher is capable of
           sending 'on-change' notifications for the selected
           data nodes and the subtree below them.";
      }
    }
  }

  grouping yp2-transport-capabilities {
    description
      "Capabilities related to transports supporting Yang Push Lite";
    container transport {
      description
        "Specifies capabilities related to YANG-Push transports.";
      list transport-capability {
        key "transport-protocol";
        description
          "Indicates a list of capabilities related to notification
                  transport.";
        leaf transport-protocol {
          type identityref {
            base yp2:transport;
          }
          description
            "Indicates supported transport protocol for YANG-Push.";
        }
        leaf security-protocol {
          type identityref {
            base security-protocol;
          }
          description
            "Indicates transport security protocol.";
        }
        leaf-list encoding-format {
          type identityref {
            base yp2:encoding;
          }
          description
            "Indicates supported encoding formats.";
        }
      }
    }
  }

  // YANG Push Lite Capabilities
  augment "/sysc:system-capabilities" {
    description
      "Adds system level capabilities for YANG Push Lite";
    uses yp2-capabilities;

    leaf distributed-notifications-supported {
      type boolean;
      description
        "Indicates whether the server supports distributed
          notifications and may source message from different
          Message Publishers.";
    }
  }

  augment "/sysc:system-capabilities/yp2ca:datastore-telemetry" {
    description
      "Adds system level Yang Push Lite transport capabilities";
    uses yp2-transport-capabilities;
  }

  augment "/sysc:system-capabilities/sysc:datastore-capabilities"
        + "/sysc:per-node-capabilities" {
    description
      "Add datastore and node-level capabilities";
    uses yp2-capabilities;
  }
}

<CODE ENDS>
Figure 26: YANG module ietf-yang-push-2-capabilities

17. Security Considerations

With configured subscriptions, one or more publishers could be used to overwhelm a receiver. To counter this, notification messages SHOULD NOT be sent to any receiver that does not support this specification. Receivers that do not want notification messages need only terminate or refuse any transport sessions from the publisher.

When a receiver of a configured subscription gets a new "subscription-started" message for a known subscription where it is already consuming events, it may indicate that an attacker has done something that has momentarily disrupted receiver connectivity. TODO - Do we still want this paragraph?.

For dynamic subscriptions, implementations need to protect against malicious or buggy subscribers that may send a large number of "establish-subscription" requests and thereby use up system resources. To cover this possibility, operators SHOULD monitor for such cases and, if discovered, take remedial action to limit the resources used, such as suspending or terminating a subset of the subscriptions or, if the underlying transport is session based, terminating the underlying transport session.

Using DNS names for configured subscription's receiver "name" lookups can cause situations where the name resolves differently than expected on the publisher, so the recipient would be different than expected.

17.1. Use of YANG Push v2 with NACM

TODO, do we even need this section?

This specification MAY be used with access control tools, such as NACM [RFC8341]. Please refer to that specification for normative guidance of how NACM applies.

For informative purposes, please note that NACM can be used:

  • NACM can be used to control access to the data nodes and RPCs defined in the YANG modules defined in this document.

  • NACM can be used to control access to the data included in the YANG update notifications.

17.2. Receiver Authorization

TODO Relax when access control must be checked.

TODO Consider if this is the best place in the document, but this text needs to be updated regardless.

A receiver of subscription data MUST only be sent updates for which it has proper authorization. A publisher MUST ensure that no unauthorized data is included in push updates. To do so, it needs to apply all corresponding checks applicable at the time of a specific pushed update and, if necessary, silently remove any unauthorized data from datastore subtrees. This enables YANG data that is pushed based on subscriptions to be authorized in a way that is equivalent to a regular data retrieval ("get") operation.

Each "push-update" and "push-change-update" MUST have access control applied, as depicted in Figure 5. This includes validating that read access is permitted for any new objects selected since the last notification message was sent to a particular receiver. A publisher MUST silently omit data nodes from the results that the client is not authorized to see. To accomplish this, implementations SHOULD apply the conceptual authorization model of [RFC8341], specifically Section 3.2.4, extended to apply analogously to data nodes included in notifications, not just <rpc-reply> messages sent in response to <get> and <get-config> requests.

                     +-----------------+      +--------------------+
  push-update or --> | datastore node  |  yes | add datastore node |
 push-change-update  | access allowed? | ---> | to update record   |
                     +-----------------+      +--------------------+
Figure 27: Access Control for Push Updates

A publisher MUST allow for the possibility that a subscription's selection filter references nonexistent data or data that a receiver is not allowed to access. Such support permits a receiver the ability to monitor the entire lifecycle of some datastore tree without needing to explicitly enumerate every individual datastore node. If, after access control has been applied, there are no objects remaining in an update record, then the effect varies given if the subscription is a periodic or on-change subscription. For a periodic subscription, an empty "push-update" notification MUST be sent, so that clients do not get confused into thinking that an update was lost. For an on-change subscription, a "push-update" notification MUST NOT be sent, so that clients remain unaware of changes made to nodes they don't have read-access for.

A publisher MAY choose to reject an "establish-subscription" request that selects nonexistent data or data that a receiver is not allowed to access. The error identity "unchanging-selection" SHOULD be returned as the reason for the rejection. In addition, a publisher MAY choose to terminate a dynamic subscription or suspend a configured receiver when the authorization privileges of a receiver change or the access controls for subscribed objects change. In that case, the publisher SHOULD include the error identity "unchanging-selection" as the reason when sending the "subscription-terminated" or "subscription-suspended" notification, respectively. Such a capability enables the publisher to avoid having to support continuous and total filtering of a subscription's content for every update record. It also reduces the possibility of leakage of access-controlled objects.

If read access into previously accessible nodes has been lost due to a receiver permissions change, this SHOULD be reported as a patch "delete" operation for on-change subscriptions. If not capable of handling such receiver permission changes with such a "delete", publisher implementations MUST force dynamic subscription re-establishment or configured subscription reinitialization so that appropriate filtering is installed.

17.3. YANG Module Security Considerations

This section is modeled after the template described in Section 3.7.1 of [I-D.ietf-netmod-rfc8407bis].

The "ietf-yang-push-2" YANG module defines a data model that is designed to be accessed via YANG-based management protocols, such as NETCONF [RFC6241] and RESTCONF [RFC8040]. These protocols have to use a secure transport layer (e.g., SSH [RFC4252], TLS [RFC8446], and QUIC [RFC9000]) and have to use mutual authentication.

The Network Configuration Access Control Model (NACM) [RFC8341] provides the means to restrict access for particular NETCONF or RESTCONF users to a pre-configured subset of all available NETCONF or RESTCONF protocol operations and content.

There are a number of data nodes defined in this YANG module that are writable/creatable/deletable (i.e., "config true", which is the default). All writable data nodes are likely to be reasonably sensitive or vulnerable in some network environments. Write operations (e.g., edit-config) and delete operations to these data nodes without proper protection or authentication can have a negative effect on network operations. The following subtrees and data nodes have particular sensitivities/vulnerabilities:

  • There are no particularly sensitive writable data nodes.

Some of the readable data nodes in this YANG module may be considered sensitive or vulnerable in some network environments. It is thus important to control read access (e.g., via get, get-config, or notification) to these data nodes. Specifically, the following subtrees and data nodes have particular sensitivities/vulnerabilities:

  • There are no particularly sensitive readable data nodes.

Some of the RPC or action operations in this YANG module may be considered sensitive or vulnerable in some network environments. It is thus important to control access to these operations. Specifically, the following operations have particular sensitivities/vulnerabilities:

  • kill-subscription - this RPC operation allows the caller to kill any dynamic subscription, even those created via other users, or other transport sessions.

18. IANA Considerations

18.1. Namespace URI registrations

This document registers the following namespace URI in the "IETF XML Registry" [RFC3688]:

Table 1: Namespace URI registrations
URI
urn:ietf:params:xml:ns:yang:ietf-yang-push-2
urn:ietf:params:xml:ns:yang:ietf-yang-push-2-config
urn:ietf:params:xml:ns:yang:ietf-yang-push-2-capabilities

For all registrations:

  • Registrant Contact: The IESG.

  • XML: N/A; the requested URI is an XML namespace.

19. YANG Module Name registrations

This document registers the following YANG modules in the "YANG Module Names" registry [RFC6020]:

Table 2: YANG Module Name Registrations
Name Namespace Prefix
ietf-yang-push-2 urn:ietf:params:xml:ns:yang:ietf-yang-push-2 ypl
ietf-yang-push-2-config urn:ietf:params:xml:ns:yang:ietf-yang-push-2-config yplco
ietf-yang-push-2-capabilities urn:ietf:params:xml:ns:yang:ietf-yang-push-2-capabilities yplca

For all registration the reference is "RFC XXXX".

Acknowledgments

This initial draft is early work is based on discussions with various folk, particularly Thomas Graf, Holger Keller, Dan Voyer, Nils Warnke, and Alex Huang Feng; but also wider conversations that include: Benoit Claise, Pierre Francois, Paolo Lucente, Jean Quilbeuf, among others.

In addition, as described in the introduction, the authors would like to acknowledge that this work builds on work of others, such as, Subscribed Notifications, YANG Push, and various extensions to that work.

Markup and prose have been produced using ChatGPT Codex and reviewed by the authors. The final content remains the responsibility of the authors.

Contributors

The following individuals have actively contributed to this draft and the YANG Push Solution.

References

Normative References

[BCP14]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/rfc/rfc8174>.
[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/rfc/rfc2119>.
[RFC2474]
Nichols, K., Blake, S., Baker, F., and D. Black, "Definition of the Differentiated Services Field (DS Field) in the IPv4 and IPv6 Headers", RFC 2474, DOI 10.17487/RFC2474, , <https://www.rfc-editor.org/rfc/rfc2474>.
[RFC6241]
Enns, R., Ed., Bjorklund, M., Ed., Schoenwaelder, J., Ed., and A. Bierman, Ed., "Network Configuration Protocol (NETCONF)", RFC 6241, DOI 10.17487/RFC6241, , <https://www.rfc-editor.org/rfc/rfc6241>.
[RFC6991]
Schoenwaelder, J., Ed., "Common YANG Data Types", RFC 6991, DOI 10.17487/RFC6991, , <https://www.rfc-editor.org/rfc/rfc6991>.
[RFC7950]
Bjorklund, M., Ed., "The YANG 1.1 Data Modeling Language", RFC 7950, DOI 10.17487/RFC7950, , <https://www.rfc-editor.org/rfc/rfc7950>.
[RFC7951]
Lhotka, L., "JSON Encoding of Data Modeled with YANG", RFC 7951, DOI 10.17487/RFC7951, , <https://www.rfc-editor.org/rfc/rfc7951>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/rfc/rfc8174>.
[RFC8340]
Bjorklund, M. and L. Berger, Ed., "YANG Tree Diagrams", BCP 215, RFC 8340, DOI 10.17487/RFC8340, , <https://www.rfc-editor.org/rfc/rfc8340>.
[RFC8341]
Bierman, A. and M. Bjorklund, "Network Configuration Access Control Model", STD 91, RFC 8341, DOI 10.17487/RFC8341, , <https://www.rfc-editor.org/rfc/rfc8341>.
[RFC8342]
Bjorklund, M., Schoenwaelder, J., Shafer, P., Watsen, K., and R. Wilton, "Network Management Datastore Architecture (NMDA)", RFC 8342, DOI 10.17487/RFC8342, , <https://www.rfc-editor.org/rfc/rfc8342>.
[RFC8525]
Bierman, A., Bjorklund, M., Schoenwaelder, J., Watsen, K., and R. Wilton, "YANG Library", RFC 8525, DOI 10.17487/RFC8525, , <https://www.rfc-editor.org/rfc/rfc8525>.
[RFC8529]
Berger, L., Hopps, C., Lindem, A., Bogdanovic, D., and X. Liu, "YANG Data Model for Network Instances", RFC 8529, DOI 10.17487/RFC8529, , <https://www.rfc-editor.org/rfc/rfc8529>.
[RFC8791]
Bierman, A., Björklund, M., and K. Watsen, "YANG Data Structure Extensions", RFC 8791, DOI 10.17487/RFC8791, , <https://www.rfc-editor.org/rfc/rfc8791>.
[RFC9196]
Lengyel, B., Clemm, A., and B. Claise, "YANG Modules Describing Capabilities for Systems and Datastore Update Notifications", RFC 9196, DOI 10.17487/RFC9196, , <https://www.rfc-editor.org/rfc/rfc9196>.
[RFC9254]
Veillette, M., Ed., Petrov, I., Ed., Pelov, A., Bormann, C., and M. Richardson, "Encoding of Data Modeled with YANG in the Concise Binary Object Representation (CBOR)", RFC 9254, DOI 10.17487/RFC9254, , <https://www.rfc-editor.org/rfc/rfc9254>.
[RFC9485]
Bormann, C. and T. Bray, "I-Regexp: An Interoperable Regular Expression Format", RFC 9485, DOI 10.17487/RFC9485, , <https://www.rfc-editor.org/rfc/rfc9485>.
[RFC9595]
Veillette, M., Ed., Pelov, A., Ed., Petrov, I., Ed., Bormann, C., and M. Richardson, "YANG Schema Item iDentifier (YANG SID)", RFC 9595, DOI 10.17487/RFC9595, , <https://www.rfc-editor.org/rfc/rfc9595>.
[RFC9911]
Schönwälder, J., Ed., "Common YANG Data Types", RFC 9911, DOI 10.17487/RFC9911, , <https://www.rfc-editor.org/rfc/rfc9911>.

Informative References

[Consistency]
Wikipedia, "Consistency (database systems)", <https://en.wikipedia.org/wiki/Consistency_(database_systems)>.
[EventualConsistency]
Rouse, M., "Eventual Consistency", <https://www.techopedia.com/definition/29165/eventual-consistency>.
[gNMI]
OpenConfig, "gRPC Network Management Interface (gNMI)", <https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md>.
[I-D.ietf-netconf-distributed-notif]
Zhou, T., Zheng, G., Voit, E., Graf, T., and P. Francois, "Subscription to Notifications in a Distributed Architecture", Work in Progress, Internet-Draft, draft-ietf-netconf-distributed-notif-23, , <https://datatracker.ietf.org/doc/html/draft-ietf-netconf-distributed-notif-23>.
[I-D.ietf-netconf-https-notif]
Jethanandani, M. and K. Watsen, "An HTTPS-based Transport for YANG Notifications", Work in Progress, Internet-Draft, draft-ietf-netconf-https-notif-16, , <https://datatracker.ietf.org/doc/html/draft-ietf-netconf-https-notif-16>.
[I-D.ietf-netconf-notif-envelope]
Feng, A. H., Francois, P., Graf, T., and B. Claise, "Extensible YANG Model for YANG-Push Notifications", Work in Progress, Internet-Draft, draft-ietf-netconf-notif-envelope-06, , <https://datatracker.ietf.org/doc/html/draft-ietf-netconf-notif-envelope-06>.
[I-D.ietf-netconf-udp-notif]
Feng, A. H., Francois, P., Zhou, T., Graf, T., and P. Lucente, "UDP-based Transport for Configured Subscriptions", Work in Progress, Internet-Draft, draft-ietf-netconf-udp-notif-26, , <https://datatracker.ietf.org/doc/html/draft-ietf-netconf-udp-notif-26>.
[I-D.ietf-netmod-rfc8407bis]
Bierman, A., Boucadair, M., and Q. Wu, "Guidelines for Authors and Reviewers of Documents Containing YANG Data Models", Work in Progress, Internet-Draft, draft-ietf-netmod-rfc8407bis-28, , <https://datatracker.ietf.org/doc/html/draft-ietf-netmod-rfc8407bis-28>.
[I-D.ietf-nmop-network-anomaly-architecture]
Graf, T., Du, W., Francois, P., and A. H. Feng, "A Framework for a Network Anomaly Detection Architecture", Work in Progress, Internet-Draft, draft-ietf-nmop-network-anomaly-architecture-08, , <https://datatracker.ietf.org/doc/html/draft-ietf-nmop-network-anomaly-architecture-08>.
[I-D.ietf-nmop-yang-message-broker-integration]
Graf, T. and A. Elhassany, "An Architecture for YANG-Push to Message Broker Integration", Work in Progress, Internet-Draft, draft-ietf-nmop-yang-message-broker-integration-13, , <https://datatracker.ietf.org/doc/html/draft-ietf-nmop-yang-message-broker-integration-13>.
[I-D.jgc-netmod-yang-path]
Cumming, J., "YANG path format (ypath)", Work in Progress, Internet-Draft, draft-jgc-netmod-yang-path-00, , <https://datatracker.ietf.org/doc/html/draft-jgc-netmod-yang-path-00>.
[I-D.netana-netconf-yp-transport-capabilities]
Wu, Q., Ma, Q., Feng, A. H., and T. Graf, "YANG Notification Transport Capabilities", Work in Progress, Internet-Draft, draft-netana-netconf-yp-transport-capabilities-01, , <https://datatracker.ietf.org/doc/html/draft-netana-netconf-yp-transport-capabilities-01>.
[I-D.yn-netmod-yang-xml-03]
Watsen, K., "XML Encoding of Data Modeled with YANG", Work in Progress, Internet-Draft, draft-yn-netmod-yang-xml-03, , <https://datatracker.ietf.org/doc/html/draft-yn-netmod-yang-xml-03>.
[Kafka]
Apache.org, "Apache Kafka", <https://kafka.apache.org/>.
[RFC3411]
Harrington, D., Presuhn, R., and B. Wijnen, "An Architecture for Describing Simple Network Management Protocol (SNMP) Management Frameworks", STD 62, RFC 3411, DOI 10.17487/RFC3411, , <https://www.rfc-editor.org/rfc/rfc3411>.
[RFC3688]
Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688, DOI 10.17487/RFC3688, , <https://www.rfc-editor.org/rfc/rfc3688>.
[RFC4252]
Ylonen, T. and C. Lonvick, Ed., "The Secure Shell (SSH) Authentication Protocol", RFC 4252, DOI 10.17487/RFC4252, , <https://www.rfc-editor.org/rfc/rfc4252>.
[RFC5277]
Chisholm, S. and H. Trevino, "NETCONF Event Notifications", RFC 5277, DOI 10.17487/RFC5277, , <https://www.rfc-editor.org/rfc/rfc5277>.
[RFC6020]
Bjorklund, M., Ed., "YANG - A Data Modeling Language for the Network Configuration Protocol (NETCONF)", RFC 6020, DOI 10.17487/RFC6020, , <https://www.rfc-editor.org/rfc/rfc6020>.
[RFC7049]
Bormann, C. and P. Hoffman, "Concise Binary Object Representation (CBOR)", RFC 7049, DOI 10.17487/RFC7049, , <https://www.rfc-editor.org/rfc/rfc7049>.
[RFC7540]
Belshe, M., Peon, R., and M. Thomson, Ed., "Hypertext Transfer Protocol Version 2 (HTTP/2)", RFC 7540, DOI 10.17487/RFC7540, , <https://www.rfc-editor.org/rfc/rfc7540>.
[RFC8040]
Bierman, A., Bjorklund, M., and K. Watsen, "RESTCONF Protocol", RFC 8040, DOI 10.17487/RFC8040, , <https://www.rfc-editor.org/rfc/rfc8040>.
[RFC8072]
Bierman, A., Bjorklund, M., and K. Watsen, "YANG Patch Media Type", RFC 8072, DOI 10.17487/RFC8072, , <https://www.rfc-editor.org/rfc/rfc8072>.
[RFC8259]
Bray, T., Ed., "The JavaScript Object Notation (JSON) Data Interchange Format", STD 90, RFC 8259, DOI 10.17487/RFC8259, , <https://www.rfc-editor.org/rfc/rfc8259>.
[RFC8343]
Bjorklund, M., "A YANG Data Model for Interface Management", RFC 8343, DOI 10.17487/RFC8343, , <https://www.rfc-editor.org/rfc/rfc8343>.
[RFC8446]
Rescorla, E., "The Transport Layer Security (TLS) Protocol Version 1.3", RFC 8446, DOI 10.17487/RFC8446, , <https://www.rfc-editor.org/rfc/rfc8446>.
[RFC8639]
Voit, E., Clemm, A., Gonzalez Prieto, A., Nilsen-Nygaard, E., and A. Tripathy, "Subscription to YANG Notifications", RFC 8639, DOI 10.17487/RFC8639, , <https://www.rfc-editor.org/rfc/rfc8639>.
[RFC8640]
Voit, E., Clemm, A., Gonzalez Prieto, A., Nilsen-Nygaard, E., and A. Tripathy, "Dynamic Subscription to YANG Events and Datastores over NETCONF", RFC 8640, DOI 10.17487/RFC8640, , <https://www.rfc-editor.org/rfc/rfc8640>.
[RFC8641]
Clemm, A. and E. Voit, "Subscription to YANG Notifications for Datastore Updates", RFC 8641, DOI 10.17487/RFC8641, , <https://www.rfc-editor.org/rfc/rfc8641>.
[RFC9000]
Iyengar, J., Ed. and M. Thomson, Ed., "QUIC: A UDP-Based Multiplexed and Secure Transport", RFC 9000, DOI 10.17487/RFC9000, , <https://www.rfc-editor.org/rfc/rfc9000>.
[W3C.REC-xml-20001006]
W3C, "Extensible Markup Language (XML) 1.0 (Second Edition)", <https://www.w3.org/TR/2000/REC-xml-20001006>.
[XPATH]
W3C, "XML Path Language (XPath) Version 1.0", <https://www.w3.org/TR/1999/REC-xpath-19991116/>.

Appendix A. Functional changes between YANG Push v2 and YANG Push

This non-normative section highlights the significant functional changes where the YANG Push v2 implementation differs from YANG Push. However, the main body of this document, from Section 4 onwards, provides the normative definition of the YANG Push v2 specification, except for any text or sections that explicitly indicate that they are informative rather being normative.

Note to reviewers: If you notice mistakes in this section during development of the document and solution then please point them out to the authors and the working group. (RFC editor, please remove this paragraph prior to publication)

A.1. Removed Functionality

This section lists functionality specified in [RFC8639] and YANG Push which is not specified in YANG Push v2.

  • The ability to suspend and resume a dynamic subscription. Instead a dynamic subscription is terminated if the device cannot reliably fulfill the subscription or a receiver is too slow causing the subscription to be back pressured.

  • Specifying a subscription stop time, and the corresponding subscription-completed notification have been removed.

  • Replaying of buffered event records are not supported, for both configured and dynamic subscriptions. The nearest equivalent is requesting a sync-on-start replay when the subscription transport session comes up which will reply the current state.

  • QoS weighting and dependency between subscriptions has been removed due to the complexity of implementation.

  • The "subscription-state-notif" extension has been removed.

  • The YANG Patch format [RFC8072] is no longer used for on-change subscriptions.

  • Support for multiple receivers for a configured subscription.

A.2. Changed Functionality

This section documents behavior that exists in both YANG Push and YANG Push v2, but the behavior differs between the two:

  • Subscription error reporting, including hints, remains under review. The device SHOULD reject subscriptions that are likely to overload the device, but more onus is placed on the operator configuring the subscriptions or setting up the dynamic subscriptions to ensure that subscriptions are reasonable, as they would be expected to do for any other configuration.

  • All YANG Push v2 notification messages use the notification envelope defined in this document (Section 7.1). YANG Push [RFC8641] uses the notification format defined in [RFC5277], or the notification envelope defined in [I-D.ietf-netconf-notif-envelope] if supported and enabled.

  • There is a lot more alignment in data model, behavior, and state machined in YANG Push v2, aiming to minimize differences.

  • Changes to handling receivers:

    • For configured subscriptions, receivers are configured separately from the subscription and are referenced.

    • For configured subscriptions, transport and encoding parameters are configured as part of a receiver definition, and are used by all subscriptions directed towards a given receiver.

    • Encoding is now a mandatory parameter under a receiver and dynamic subscription (rather than specifying a default).

    • Invoking the reset YANG action on a receiver requires and forces a reset of any transport sessions associated with that receiver. Previously, the sessions would not be reset if they were used by other subscriptions.

    • YANG Push v2 only supports a single receiver per subscription.

  • Periodic and on-change message uses a common update notification message format, allowing for the messages to be processed by clients in a similar fashion and to support combined periodic and on-change subscriptions.

  • Changes related to the configuration model:

    • Subscriptions are identified by a string identifier rather than a numeric identifier. The prefix 'dyn-' is reserved for publisher allocated dyanmic subscription ids. Clients may provide the id to be used for dynamic subscriptions. There is changed handling for conflicting subscription-ids between configured and dynamic.

    • Purpose has been renamed to Description (since it is a more generic term), limited to 1k characters, but also available for dynamic subscriptions.

  • On-change dampening:

    • Client configurable on-change dampening has been removed.

    • However, YANG Push v2 allows a publisher to limit the rate at which a data node is sampled for on-change notifications. See Section 7.5.1 for further details.

  • Dynamic subscriptions are no longer mandatory to implement, either or both of Configured and Dynamic Subscriptions may be implemented in YANG Push v2.

  • The solution focuses solely on datastore subscriptions that each have their own event stream. Filters cannot be applied to the event stream, only to the set of datastore data nodes that are monitored by the subscription.

  • The lifecycle events of when a subscription-started or subscription-terminated may be sent differs from [RFC8639]/[RFC8641]:

    • Subscription-started notifications are also sent for dynamic subscriptions.

  • Some of the requirements on transport have been relaxed.

  • The encoding identities have been extended with CBOR encodings, and the "encoding-" prefix has been removed (so that there is a better on the wire representation).

  • YANG Push v2 allows for a publisher to provide an eventually consistent distributed view of the operational datastore, with subscribed data decomposed across messages and publishing processes, rather than requiring a single atomic snapshot.

A.3. Added Functionality

  • Device capabilities are reported via ietf-yang-push-2-capabilities, which augments ietf-system-capabilities ([RFC9196]).

  • A new update message:

    • Covers both on-change and periodic events.

    • Allows multiple updates to be sent in a single message (e.g., for on-change).

    • Allows for a common path prefix to be specified, with any paths and encoded YANG data to be encoded relative to the common path prefix.

  • The complete flag or an update-complete notification indicates completion of a publisher's contribution to a periodic or resynchronization collection. Receivers track completion across all participating publishers.

  • Support for distributed notifications has been added to the base YANG Push v2 specification, as described in Section 13.

  • TODO - More operational data on the subscription load and performance.

  • All YANG Push v2 configuration is under a new datastore-telemetry presence container

Appendix B. Subscription Errors (from RFC 8641)

B.1. RPC Failures

Rejection of an RPC for any reason is indicated via an RPC error response from the publisher. Valid RPC errors returned include both (1) existing transport-layer RPC error codes, such as those seen with NETCONF in [RFC6241] and (2) subscription-specific errors, such as those defined in the YANG data model. As a result, how subscription errors are encoded in an RPC error response is transport dependent.

References to specific identities in the ietf-subscribed- notifications YANG module [RFC8639] or the ietf-yang-push YANG module may be returned as part of the error responses resulting from failed attempts at datastore subscription. For errors defined as part of the ietf-subscribed-notifications YANG module, please refer to [RFC8639]. The errors defined in this document, grouped per RPC, are as follows:

      establish-subscription          modify-subscription
      ---------------------------     ---------------------
       cant-exclude                    period-unsupported
       datastore-not-subscribable      update-too-big
       on-change-unsupported           sync-too-big
       on-change-sync-unsupported      unchanging-selection
       period-unsupported
       update-too-big                 resync-subscription
       sync-too-big                   ----------------------------
       unchanging-selection            no-such-subscription-resync
                                       sync-too-big

There is one final set of transport-independent RPC error elements included in the YANG data model. These are the four yang-data structures for failed datastore subscriptions:

  1. yang-data "establish-subscription-error-datastore": This MUST be returned if information identifying the reason for an RPC error has not been placed elsewhere in the transport portion of a failed "establish-subscription" RPC response. This MUST be sent if hints are included.

  2. yang-data "modify-subscription-error-datastore": This MUST be returned if information identifying the reason for an RPC error has not been placed elsewhere in the transport portion of a failed "modify-subscription" RPC response. This MUST be sent if hints are included.

  3. yang-data "sn:delete-subscription-error": This MUST be returned if information identifying the reason for an RPC error has not been placed elsewhere in the transport portion of a failed "delete-subscription" or "kill-subscription" RPC response.

  4. yang-data "resync-subscription-error": This MUST be returned if information identifying the reason for an RPC error has not been placed elsewhere in the transport portion of a failed "resync-subscription" RPC response.

B.2. Failure Notifications

A subscription may be unexpectedly terminated or suspended independently of any RPC or configuration operation. In such cases, indications of such a failure MUST be provided. To accomplish this, a number of errors can be returned as part of the corresponding subscription state change notification. For this purpose, the following error identities are introduced in this document, in addition to those that were already defined in [RFC8639]:

  subscription-terminated        subscription-suspended
  ---------------------------    ----------------------
  datastore-not-subscribable     period-unsupported
  unchanging-selection           update-too-big
                                  synchronization-size

Appendix C. Path Prefix and Target Examples

The following examples illustrate the path rules for update notifications. They assume an illustrative YANG module named example with a top-level system container containing a name leaf. "Absent" means that the field is omitted; "" means a present field containing an empty string. An invalid combination has no valid full target path. For valid combinations, an update supplies data at the identified target, and a delete removes the identified data and its descendants from the receiver's view.

Table 3: Examples of target path construction
path-prefix target Full target path Validity and expected behavior
Absent /example:system /example:system Valid: acts on the system container.
/example:system name /example:system/name Valid: acts on the name leaf.
/example:system "" None Invalid: the target must not be empty.
Absent / / Valid: acts on the entire datastore.
"" /example:system None Invalid: a present prefix cannot be empty.
/ example:system None Invalid: the prefix contains no path segment.
example:system name None Invalid: the prefix is not absolute.
Absent example:system None Invalid: without a prefix, the target is not absolute.
/example:system /name None Invalid: with a prefix, the target starts with '/'.
Absent "" None Invalid: without a prefix, an empty target is not absolute.
/example:system Absent None Invalid: the target is the required key of each updates entry.

Appendix D. Examples

Notes on examples:

D.1. Example of periodic update messages

In this example, a subscription is for /ietf-interfaces:interfaces/interface. However, for efficiency reasons, the publisher is internally returning the data from two different data providers.

Of note:

  • The first periodic message is published for the entries in the /ietf-interfaces:interface/interfaces list, but doesn't contain the data in the statistics child container.

  • the path-prefix identifies the parent of the subscribed interface list.

  • the target is interface, identifying the subscribed list relative to path-prefix.

{
  "ietf-yang-push-2:update": {
    "id": "interfaces",
    "path-prefix": "/ietf-interfaces:interfaces",
    "snapshot-type": "periodic",
    "observation-time": "2024-10-10T08:00:05.11Z",
    "updates": [
      {
        "target": "interface",
        "update": {
          "interface": [
            {
              "name": "eth0",
              "type": "iana-if-type:ethernetCsmacd",
              "enabled": true,
              "oper-status": "up",
              "admin-status": "up"
            },
            {
              "name": "eth1",
              "type": "iana-if-type:ethernetCsmacd",
              "enabled": true,
              "oper-status": "up",
              "admin-status": "up"
            }
          ]
        }
      }
    ],
    "complete": false
  }
}
Figure 28: Example periodic update for interfaces list

For the second notification related to the same subscription:

  • the second periodic message is published for only the statistics associated with the interfaces.

  • as above, path-prefix identifies the parent of the subscribed interface list, and target is interface.

  • the second notification uses a separate observation-time, but would use the same event-time in the notification header so that the two messages can be correlated to the same periodic collection event.

  • the second periodic message has set the complete flag to indicate that it is the last notification as part of the periodic collection. A separate update-complete notification could have been sent instead.

{
  "ietf-yang-push-2:update": {
    "id": "interfaces",
    "path-prefix": "/ietf-interfaces:interfaces",
    "snapshot-type": "periodic",
    "observation-time": "2024-10-10T08:00:05.21Z",
    "updates": [
      {
        "target": "interface",
        "update": {
          "ietf-interfaces:interface": [
            {
              "name": "eth0",
              "statistics": {
                "in-octets": 123456,
                "out-octets": 654321
              }
            },
            {
              "name": "eth1",
              "statistics": {
                "in-octets": 789012,
                "out-octets": 210987
              }
            }
          ]
        }
      }
    ]
  }
}
Figure 29: Example periodic update for interface statistics

D.2. Example of an on-change notification containing updated data

If the subscription is for on-change notifications, or periodic-and-on-change notifications, then, if the interface state changed (specifically if the enabled and oper-status leaves changed), and if the device was capable of generating on-change notifications, then you may see the following message. A few points of notes here:

  • The on-change notification includes only the data nodes that changed within the target. It does not repeat unchanged sibling data.

  • A single on-change notification could also publish updates for multiple interfaces in the same message.

  • The schema of the change message is exactly the same as for the equivalent periodic message. It doesn't use the YANG Patch format [RFC8072] for on-change messages.

  • The observation-time leaf represents when the system first observed the on-change event occurring. The envelope's event-time represents when the telemetry infrastructure began processing the change notification.

  • The on-change snapshot type identifies messages triggered by changes to the subscribed data. Each entry in the updates list specifies an update or delete operation, and a single message may contain both operations. An update operation does not distinguish between creation and modification.

<CODE BEGINS> file "on-change-msg.json"

{
  "ietf-yang-push-2:envelope": {
    "event-time": "2025-10-10T08:16:05.22Z",
    "hostname": "example-router",
    "sequence-number": 454,
    "contents": {
      "update": {
        "id": "interfaces",
        "snapshot-type": "on-change",
        "observation-time": "2025-10-10T08:16:05.11Z",
        "updates": [
          {
            "target": "/ietf-interfaces:interfaces/interface[name='eth0']",
            "update": {
              "enabled": false,
              "oper-status": "down"
            }
          }
        ]
      }
    }
  }
}

<CODE ENDS>
Figure 30: Example YANG Push v2 on-change update message

D.3. Example of an on-change notification containing deleted data

D.3.1. Update message with single deleted data node

If the interface was deleted, and if the system was capable of reporting on-change events for the delete event, then an on-change delete message would be encoded as per the following message.

Of note:

  • The ietf-yang-push-2:envelope has been elided

  • The deleted data is identified by the target node in the updates/target element.

  • The observation time represents the time at which the delete event occurred, e.g., perhaps when the system processed a configuration change.

{
  "ietf-yang-push-2:update": {
    "id": "interfaces",
    "snapshot-type": "on-change",
    "observation-time": "2025-10-10T08:16:15.11Z",
    "updates": [
      {
        "target": "/ietf-interfaces:interfaces/interface[name='eth0']",
        "delete": true
      }
    ]
  }
}
Figure 31: Example YANG Push v2 on-change delete message

D.3.2. Update message with multiple on-change deletes

This follow example illustrates how a single update notification message can contain multiple on-change delete events for different data nodes. In this example, two separate interfaces are being deleted.

Of note:

  • The ietf-yang-push-2:envelope has been elided

  • path-prefix is used to shorten the target values. Each full target-path is formed by appending the corresponding target path segments to path-prefix.

  • all delete events share a common observation-time of when the delete events occurred. If it is necessary to identify separate observation times then the publisher would send separate messages.

  • data node subtrees that are deleted (list entries in this case) are identified by separate entries in the updates list.

{
  "ietf-yang-push-2:update": {
    "id": "interfaces",
    "path-prefix": "/ietf-interfaces:interfaces",
    "snapshot-type": "on-change",
    "observation-time": "2025-10-10T08:16:16.11Z",
    "updates": [
      {
        "target": "interface[name='eth0']",
        "delete": true
      },
      {
        "target": "interface[name='eth1']",
        "delete": true
      }
    ]
  }
}
Figure 32: Example YANG Push v2 on-change delete message

D.4. NETCONF Dynamic Subscription RPC examples

The examples in this section illustrate NETCONF RPCs for establishing and deleting dynamic subscriptions using YANG Push v2. The examples include one successfully establishing a subscription, and a second to illustrate how errors are returned if a request to establish the subscription fails. Examples of the update and subscription lifecycle notifications have been given in the previous section.

D.4.1. Successful periodic subscription

The subscriber sends an "establish-subscription" RPC with the parameters listed in Section 9.4.1 An example might look like:

<netconf:rpc
message-id="101" xmlns:netconf="urn:ietf:params:xml:ns:netconf:base:1.0">
  <establish-subscription xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push-2">
    <id>if-stats-sub</id>
    <description>Subscribe to interface statistics</description>
    <target>
      <datastore xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">
        ds:operational
      </datastore>
      <path>/ietf-interfaces:interfaces/interface/statistics</path>
    </target>
    <update-trigger>
      <periodic>
        <period>3000</period>
      </periodic>
    </update-trigger>
    <encoding>xml</encoding>
  </establish-subscription>
</netconf:rpc>
Figure 33: Example establish-subscription RPC for interface statistics

If a publisher is happy to accept the subscription, then it returns a positive response that includes the "id" of the accepted subscription. For example,

<rpc-reply
message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <id xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-push-2">dyn-52</id>
</rpc-reply>
Figure 34: Example establish-subscription RPC successful reply

Once established, the publisher would send a subscription-started notification message followed by update notification messages at the requested periodic cadence.

D.4.2. Failed periodic subscription

A subscription can be rejected for multiple reasons, including the lack of authorization to establish a subscription, no capacity to serve the subscription at the publisher, or the inability of the publisher to select datastore content at the requested cadence.

If a request is rejected because the publisher is not able to serve it, the publisher SHOULD include in the returned error hints that help a subscriber understand what subscription parameters might have been accepted for the request. These hints would be included in the yang-data structure "establish-subscription-error-datastore". However, even with these hints, there are no guarantees that subsequent requests will in fact be accepted.

The specific parameters to be returned as part of the RPC error response depend on the specific transport that is used to manage the subscription. For NETCONF, those parameters are defined in [RFC8640]. For example, for the following NETCONF request:

  <rpc message-id="101"
      xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
    <establish-subscription
        xmlns=
          "urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications"
        xmlns:yp="urn:ietf:params:xml:ns:yang:ietf-yang-push">
      <yp:datastore
          xmlns:ds="urn:ietf:params:xml:ns:yang:ietf-datastores">
        ds:operational
      </yp:datastore>
      <yp:datastore-xpath-filter
          xmlns:ex="https://example.com/sample-data/1.0">
        /ex:foo
      </yp:datastore-xpath-filter>
      <yp:on-change>
      </yp:on-change>
    </establish-subscription>
  </rpc>

      Figure 12: "establish-subscription" Request: Example 2

A publisher that cannot serve on-change updates but can serve periodic updates might return the following NETCONF response:

 <rpc-reply message-id="101"
   xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"
   xmlns:yp="urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications">
   <rpc-error>
     <error-type>application</error-type>
     <error-tag>operation-failed</error-tag>
     <error-severity>error</error-severity>
     <error-path>/yp:periodic/yp:period</error-path>
     <error-info>
       <yp:establish-subscription-error-datastore>
         <yp:reason>yp:on-change-unsupported</yp:reason>
       </yp:establish-subscription-error-datastore>
     </error-info>
   </rpc-error>
 </rpc-reply>

       Figure 13: "establish-subscription" Error Response: Example 2

D.4.3. "delete-subscription" RPC

To stop receiving updates from a subscription and effectively delete a subscription that had previously been established using an "establish-subscription" RPC, a subscriber can send a "delete-subscription" RPC, which takes as its only input the subscription's "id". This RPC is unmodified from [RFC8639].

D.5. Distributed Notifications Subscription

This simple example illustrates how messages may look like when using distributed notifications, as described in Section 13. This example is for a very simple periodic subscription to the ietf-interfaces YANG data model.

The first message is a subscription started message that indicates that there are 2 additional Publisher Agents with publisher-ids of 4 and 7, e.g., perhaps representing a device with two linecards inserted into slots 4 and 7, each with their owner separate Message Publisher process. This message has a publisher-id of 0 because it is sent by the Publisher Parent, which, because this field has the default value, could have been elided from the message.

{
  "ietf-yang-push-2:envelope": {
    "event-time": "2025-10-10T08:00:05.22Z",
    "hostname": "example-router",
    "sequence-number": 1,
    "contents": {
      "subscription-started": {
        "id": "interfaces",
        "target": {
          "datastore": "ietf-datastores:operational",
          "path": "/ietf-interfaces:interfaces"
        },
        "update-trigger": {
          "periodic": {
            "period": 3000,
            "anchor-time": "2025-01-01T00:00:00.00Z"
          }
        },
        "message-publishers": {
          "publisher-id": [0, 4, 7]
        }
      }
    }
  }
}
Figure 35: Example distributed notification subscription started message

The second message is an example of a periodic update message sent from one of the Publisher Agents on the linecard. In this case the message is sent from the publisher agent on linecard 4, and it has set the complete leaf to indicate that the message represents all data for that periodic collection from that publisher.

{
  "ietf-yang-push-2:envelope": {
    "event-time": "2025-10-10T08:00:05.22Z",
    "hostname": "example-router",
    "publisher-id": 4,
    "sequence-number": 18,
    "contents": {
      "update": {
        "id": "interfaces",
        "snapshot-type": "periodic",
        "observation-time": "2025-10-10T08:00:05.11Z",
        "updates": [
          {
            "target": "/ietf-interfaces:interfaces/interface",
            "update": {
              "ietf-interfaces:interfaces": {
                "interface": [
                  {
                    "name": "eth4/0",
                    "type": "iana-if-type:ethernetCsmacd",
                    "enabled": true,
                    "oper-status": "up",
                    "admin-status": "up"
                  },
                  {
                    "name": "eth4/1",
                    "type": "iana-if-type:ethernetCsmacd",
                    "enabled": true,
                    "oper-status": "down",
                    "admin-status": "up"
                  }
                ]
              }
            }
          }
        ],
        "complete": true
      }
    }
  }
}
Figure 36: Example distributed notification update message

Not shown here, but because there were 3 publisher-ids listed in the subscription-started message means that each Message Publisher must send at least one message for each periodic subscription returning any data associated with the subscription from that Message Publisher and also indicating that the periodic collection is complete by either setting complete = true or sending an update-complete notification.

Appendix E. Summary of Open Issues & Potential Enhancements

This temporary section lists open issues and enhancements that require further discussion by the authors, or the WG. Detailed discussion is tracked in GitHub.

The issues are ordered/grouped by the sections in the current document. I.e., to make it easier to review/update sections of the document.

E.15. Summary of closed/resolved issues

This appendix is only intended while the authors/WG are working on the document, and should be deleted prior to WG LC.

  1. Rename subscription-terminated to subscription-stopped (Change rejected 21 Feb 25, unnecessary renaming.)

  2. MUST use envelope, hostname and sequence-number (and event-time) (Decided 21 Feb 25)

  3. Don't mandate configured or dynamic subscriptions, allow implementations to implement one or both of them. (Decided 21 Feb 25)

  4. Dynamic subscriptions require the encoding to be specified. (Decided 21 Feb 25)

  5. DSCP settings are only specified under the receiver (for configured subscriptions) (Decided 21 Feb 25)

  6. Config and dynamic subscriptions should be aligned as much as possible.

  7. Subscription changes use subscription-modified or require termination/recreation as specified in Section 9.1.3.

  8. Dynamic subscriptions support the modify-subscription RPC.

  9. Lifecycle messages are sent per subscription rather than per receiver, and we only support a single receiver per subscription.

  10. Encoding is set on the receiver for configured subscriptions and in the establishing RPC for dynamic subscriptions.

  11. We have a complete flag/update-complete notification to allow deleted data to be implicitly detected. Something similar may be added to gNMI. issue 12

  12. We use a string identifier to uniquely identify a subscription rather than a numeric id. Reserve 'dyn-' for server allocated dynamic subscription ids. Agreed config/dynamic conflict policy. Restricted names for fitler-id and receiver name. Don't use a union type (could be added in future). (Dec 8th)

  13. Draft renamed from Yang Push Lite to Yang Push 2. (Dec 8th)

  14. Dynamic subscriptions cannot reference configured filters. Lifecycle notifications include the inline filter and may also identify its configured reference. Issue 20

  15. Publisher MUST NOT send more notifications after a subscription terminated message Issue 13.

  16. on-change notifications SHOULD send a minimal update but MAY send additional unchanged fields.

Authors' Addresses

Robert Wilton (editor)
Cisco Systems
Holger Keller
Deutsche Telekom
Benoit Claise
Everything OPS
Ebben Aries
HPE
James Cumming
Nokia
Thomas Graf
Swisscom