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."; } } }