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";
}
import ietf-yp-notification {
prefix iypn;
reference
"draft-ietf-netconf-notif-envelope: Extensible YANG Model for
YANG-Push Notifications
TODO: RFC Editor please replace with latest draft/RFC version
at publication time.";
}
organization
"IETF NETCONF (Network Configuration) Working Group";
contact
"WG Web:
WG List:
Author: Robert Wilton
";
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 2025-08-03 {
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 configurable-encoding {
description
"If a transport identity derives from this identity, it means
that it supports configurable encodings. An example of a
configurable encoding might be a new identity such as
'encode-cbor'. Such an identity could use
'configurable-encoding' as its base. This would allow a
dynamic subscription encoded in JSON (RFC 8259) to request
that notification messages be encoded via the Concise Binary
Object Representation (CBOR) (RFC 7049). Further details for
any specific configurable encoding would be explored in a
transport document based on this specification.
TODO - Clear up this text or use YANG-CBOR reference";
reference
"RFC 8259: The JavaScript Object Notation (JSON) Data
Interchange Format
RFC 7049: Concise Binary Object Representation (CBOR)";
}
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 9245,
without using YANG SIDs";
reference
"RFC 9245: Encoding of Data Modeled with YANG in the
Concise Binary Object Representation (CBOR).";
}
identity cbor-sids {
base encoding;
description
"Encode data using JSON as described in RFC 7951, using YANG
SIDs.";
reference
"RFC 9245: 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.";
}
}
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 to use for the subscription 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;
description
"Specifies the common prefix that all other paths and data
are encoded relative to.
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-update" {
description
"The update message is due to an on-change update. This
means that one or more fields have changed under the
snapshot path.
TODO - Split this into a on-change-delete msg?";
}
enum "on-change-delete" {
description
"The update message is due to an on-change event where
the data node at the target path has been delete.";
}
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.
TODO - In the distributed notification case, need a
notification to indicate that all child subscriptions
have been sent.";
}
}
mandatory true;
description
"This indicates the type of notification message that is
being sent.";
}
leaf observation-time {
type yang:date-and-time;
description
"The time that the update was observed by the publisher.";
}
list updates {
key "target-path";
description
"This list contains the updated data. It constitutes a
snapshot at the time of update of the set of data that has
been subscribed to. The snapshot corresponds to the same
snapshot that would be returned in a corresponding 'get'
operation with the same selection filter parameters
applied.";
leaf target-path {
type string;
description
"The target path of the data that is being replaced, i.e.,
updated or deleted. The path is given relative to the
path-prefix.";
}
choice data {
description
"This choice indicates the type of update that is being
performed at the target path.";
anydata merge {
description
"This contains the updated data that is to be merged with
the existing data at the target path. It constitutes a
snapshot at the time of update of the set of data that
has been subscribed to. The snapshot corresponds to the
same snapshot that would be returned in a corresponding
'get' operation with the same selection filter parameters
applied.
The snapshot is encoded relative to the combined path
defined by the common path-prefix and target-path";
}
anydata replaced-by {
description
"This contains the updated data that is to replace all
existing data at the target path. It constitutes a
snapshot at the time of update of the set of data that
has been subscribed to. The snapshot corresponds to the
same snapshot that would be returned in a corresponding
'get' operation with the same selection filter parameters
applied.
The snapshot is encoded relative to the combined path
defined by the common path-prefix and target-path";
}
leaf deleted {
type empty;
description
"This indicates that the data at the target path has been
deleted.";
}
}
}
leaf complete {
type boolean;
default "false";
description
"This flag indicates that this is the last
notification in a series of notifications that together
constitute a complete snapshot of the subscribed data at
the event-time.
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 a periodic collection
or resync event for an on-change subscription, and can be used
to indicate that the receiver has a complete snapshot of the
subscribed data at the event-time, and hence the client MAY
use this as a signal that it can purge stale state
information.
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:augment-structure "/iypn:envelope" {
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.";
}
}
}