RFC 8639
Subscription to YANG Notifications
RFC 8639: Subscription to YANG Notifications ๐
Okay bestie, this one is a real main character spec ๐ It's Request for Comments 8639, published by the IETF in September 2019, and its ISSN is 2070-1721. The title is "Subscription to YANG Notifications" โจ
The authors are E. Voit (Cisco Systems), A. Clemm (Futurewei), A. Gonzalez Prieto (Microsoft), E. Nilsen-Nygaard (Cisco Systems), and A. Tripathy (Cisco Systems) ๐ซถ It's on the Standards Track, so it's an Internet Standards Track document. Its header has no Obsoletes or Updates lines, so it doesn't list anything it replaces or amends ๐ฆ
Part 1 of 14 is below, and more is coming, so stay tuned ๐ธ
Abstract โจ
Okay so this doc defines a YANG data model plus the mechanisms that let a subscriber ask for its own subscriptions to a publisher's event streams. Once that's in place, the subscriber can request and receive a continuous feed of publisher-generated info that's customized just for them ๐
Status of This Memo ๐
This is an Internet Standards Track document ๐
It's a product of the Internet Engineering Task Force (IETF), and it represents the consensus of the IETF community. It got public review and was approved for publication by the Internet Engineering Steering Group (IESG). For more on Internet Standards, check Section 2 of RFC 7841 ๐ง
For the current status, any errata, and how to send feedback, go to https://www.rfc-editor.org/info/rfc8639 ๐
Copyright Notice ๐
Copyright (c) 2019 IETF Trust and the persons identified as the document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they stand on the publication date. Please read these carefully, because they spell out your rights and restrictions for this document. Code Components pulled out of this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions, and they come without warranty, as described in the Simplified BSD License ๐
This document may contain material from IETF Documents or IETF Contributions that were published or made publicly available before November 10, 2008. The people who control the copyright in some of that material may not have given the IETF Trust permission to allow modifications outside the IETF Standards Process. Unless you get an adequate license from those copyright controllers, this document may not be modified outside the IETF Standards Process, and derivative works of it may not be made outside the IETF Standards Process. The exceptions are formatting it for publication as an RFC or translating it into languages other than English ๐
Table of Contents ๐บ๏ธ
1. Introduction ....................................................3
1.1. Motivation .................................................4
1.2. Terminology ................................................4
1.3. Solution Overview ..........................................6
1.4. Relationship to RFC 5277 ...................................7
2. Solution ........................................................8
2.1. Event Streams ..............................................8
2.2. Event Stream Filters .......................................9
2.3. QoS ........................................................9
2.4. Dynamic Subscriptions .....................................10
2.5. Configured Subscriptions ..................................19
2.6. Event Record Delivery .....................................27
2.7. Subscription State Change Notifications ...................28
2.8. Subscription Monitoring ...................................33
2.9. Support for the "ietf-subscribed-notifications"
YANG Module ...............................................34
3. YANG Data Model Tree Diagrams ..................................34
3.1. The "streams" Container ...................................34
3.2. The "filters" Container ...................................35
3.3. The "subscriptions" Container .............................35
4. Event Notification Subscription YANG Module ....................37
5. IANA Considerations ............................................66
6. Implementation Considerations ..................................66
7. Transport Requirements .........................................67
8. Security Considerations ........................................68
9. References .....................................................72
9.1. Normative References ......................................72
9.2. Informative References ....................................74
Appendix A. Example Configured Transport Augmentation .............75
Acknowledgments ...................................................77
Authors' Addresses ................................................77
1. Introduction ๐ฆ
1.1. Motivation ๐ญ
Things get interesting here because this doc defines a YANG data model and mechanisms that enable subscriber-specific subscriptions to a publisher's event streams. That effectively gives you a "subscribe, then publish" capability: the publisher understands each target receiver's customized information needs and access permissions before it marshals and pushes the subscribed event records ๐ฅ The receiver then gets a continuous, customized feed of publisher-generated information โจ
Transport-wise, this works with any transport, which is very iykyk-level flexible ๐ธ Transports like the Network Configuration Protocol (NETCONF) [RFC6241] or RESTCONF [RFC8040] can be used to configure or dynamically signal subscriptions. Bindings for subscribed event record delivery over NETCONF and RESTCONF are defined in [RFC8640] and [RESTCONF-Notif], respectively ๐
The YANG data model in this document conforms to the Network Management Datastore Architecture defined in [RFC8342] ๐ง
The original is pretty clear on this, but to be extra: this doc is the leveled-up version of older subscription stuff ๐
1.1. Motivation ๐
Okay so there were various limitations to subscriptions as described in [RFC5277], and the requirements in [RFC7923] alleviated some of them to a degree. Fixing whatever's still broken is the main reason for this work ๐ The key capabilities this document supports are:
- multiple subscriptions on a single transport session
- support for dynamic and configured subscriptions
- modification of an existing subscription in progress
- per-subscription operational counters
- negotiation of subscription parameters (through the use of hints returned as part of declined subscription requests)
- subscription state change notifications (e.g., publisher-driven suspension, parameter modification)
- independence from transport
Honestly this list is giving everything a good subscription should be ๐ญ๐ซถ
1.2. Terminology ๐
Here's the key word situation ๐ฅ 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 ๐
Now the vocab, bestie ๐
- Client: Defined in [RFC8342].
- Configuration: Defined in [RFC8342].
- Configuration datastore: Defined in [RFC8342].
- Configured subscription: A subscription installed via configuration into a configuration datastore.
- Dynamic subscription: A subscription created dynamically by a subscriber via a Remote Procedure Call (RPC).
- Event: An occurrence of something that may be of interest. Examples include a configuration change, a fault, a change in status, crossing a threshold, or an external input to the system.
- Event occurrence time: A timestamp matching the time an originating process identified as when an event happened.
- Event record: A set of information detailing an event.
- Event stream: A continuous, chronologically ordered set of events aggregated under some context.
- Event stream filter: Evaluation criteria that may be applied against event records in an event stream. Event records pass the filter when specified criteria are met.
- Notification message: Information intended for a receiver indicating that one or more events have occurred.
- Publisher: An entity responsible for streaming notification messages per the terms of a subscription.
- Receiver: A target to which a publisher pushes subscribed event records. For dynamic subscriptions, the receiver and subscriber are the same entity.
- Subscriber: A client able to request and negotiate a contract for the generation and push of event records from a publisher. For dynamic subscriptions, the receiver and subscriber are the same entity.
- Subscription: A contract with a publisher, stipulating the information that one or more receivers wish to have pushed from the publisher without the need for further solicitation.
All YANG tree diagrams used in this document follow the notation defined in [RFC8340] ๐
Part 1 of 14 is done, bestie, and part 2 is next ๐ฆ๐
1.3. Solution Overview โจ
okay so this doc describes a transport-agnostic mechanism ๐ฆ for subscribing to and receiving content from an event stream in a publisher. The whole thing runs on something called a subscription ๐
There are two types of subscriptions ๐:
- Dynamic subscriptions ๐ : a subscriber starts a subscription negotiation with a publisher via an RPC. If the publisher can serve it, it says yes and then starts pushing notification messages back to the subscriber ๐ซถ. If the publisher can't serve it as requested, you get an error response ๐ญ. That response MAY include hints for subscription parameters that, had they been present, may have enabled the dynamic subscription request to be accepted.
- Configured subscriptions ๐: these let you manage subscriptions through configuration, so a publisher can send notification messages to a receiver. Support is optional, and you can tell if it's there because it's advertised via a YANG feature ๐.
Dynamic and configured subscriptions are different in a few lowkey important ways ๐:
- The lifetime of a dynamic subscription is bound by the transport session used to establish it. For connection-oriented stateful transports like NETCONF, losing the transport session immediately terminates any associated dynamic subscriptions ๐. For connectionless or stateless transports like HTTP, a lack of receipt acknowledgment of a sequential set of notification messages and/or keep-alives can be used to trigger termination of a dynamic subscription. Now contrast that with configured subscriptions, whose lifetime is driven by relevant configuration being present in the publisher's applied configuration. Being tied to configuration operations implies that (1) configured subscriptions can be configured to persist across reboots and (2) a configured subscription can persist even when its publisher is fully disconnected from any network ๐ง.
- Configured subscriptions can be modified by any configuration client with write permission on the configuration of the subscription. Dynamic subscriptions can only be modified via an RPC request made by the original subscriber, or by a change to configuration data referenced by the subscription ๐.
Note that there is no mixing and matching of dynamic and configured operations on a single subscription ๐ซ. Specifically, a configured subscription cannot be modified or deleted using RPCs defined in this document. Similarly, a dynamic subscription cannot be directly modified or deleted by configuration operations. It is, however, possible to perform a configuration operation that indirectly impacts a dynamic subscription. By changing the value of a preconfigured filter referenced by an existing dynamic subscription, the selected event records passed to a receiver might change ๐.
Also note that transport-specific specifications based on this specification MUST detail the lifecycle of dynamic subscriptions as well as the lifecycle of configured subscriptions (if supported) ๐.
A publisher MAY terminate a dynamic subscription at any time. Similarly, it MAY decide to temporarily suspend the sending of notification messages for any dynamic subscription, or for one or more receivers of a configured subscription. Such termination or suspension is driven by internal considerations of the publisher ๐ธ.
1.4. Relationship to RFC 5277
this doc is meant to be a superset of the subscription capabilities first defined in [RFC5277] ๐. It's important to know what got reused and what got replaced, especially if you're extending an existing implementation that's based on [RFC5277]. The key relationships between the two documents are:
- This document defines a transport-independent capability; [RFC5277] is specific to NETCONF.
- For the new operations, the data model defined in this document is used instead of the data model defined in Section 3.4 of [RFC5277].
- The RPC operations in this document replace the operation
<create-subscription>as defined in [RFC5277], Section 4. - The
<notification>message of [RFC5277], Section 4 is used. - The included contents of the
"NETCONF"event stream are identical between this document and [RFC5277]. - A publisher MAY implement both the Notification Management Schema and RPCs defined in [RFC5277] and this document concurrently.
- Unlike [RFC5277], this document enables a single transport session to intermix notification messages and RPCs for different subscriptions ๐ฅ.
- A subscription
"stop-time"can be specified as part of a notification replay. This supports a capability analogous to the<stopTime>parameter of [RFC5277]. However, in this specification, a"stop-time"parameter can also be applied without replay โฐ.
2. Solution
Per the overview in Section 1.3, this section details the overall context, state machines, and subsystems that may be assembled to allow the subscription of events from a publisher ๐งฉ.
2.1. Event Streams
An event stream is a named entity on a publisher. This entity exposes a continuously updating set of YANG-defined event records ๐ก. An event record is an instantiation of a "notification" YANG statement. If the "notification" is defined as a child to a data node, the instantiation includes the hierarchy of nodes that identifies the data node in the datastore (see Section 7.16.2 of [RFC7950]). Each event stream is available for subscription. Identifying a) how event streams are defined (other than the NETCONF stream), b) how event records are defined/generated, and c) how event records are assigned to event streams is out of scope for this document ๐
.
There is only one reserved event stream name in this document: "NETCONF". The "NETCONF" event stream contains all NETCONF event record information supported by the publisher, except where an event record has explicitly been excluded from the stream. Beyond the "NETCONF" stream, implementations MAY define additional event streams โจ.
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(s) 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 Section 3.4.6 of [RFC8341] 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 ๐ซฃ.
If no access control permissions are in place for event records on an event stream, then a receiver MUST be allowed access to all the event records. If subscriber permissions change during the lifecycle of a subscription and event stream access is no longer permitted, then the subscription MUST be terminated ๐ช.
Event records MUST NOT be delivered to a receiver in a different order than the order in which they were placed on an event stream ๐ซถ.
2.2. Event Stream Filters
This document defines an extensible filtering mechanism ๐. The filter itself is a boolean test that is placed on the content of an event record. A "false" filtering result causes the event record to be excluded from delivery to a receiver. A filter never results in information being stripped from an event record prior to that event record being encapsulated in a notification message. The two optional event stream filtering syntaxes supported are [XPATH] and subtree [RFC6241] ๐
.
If no event stream filter is provided in a subscription, all event records on an event stream are to be sent ๐ฌ.
2.3. QoS
This document provides for several Quality of Service (QoS) parameters ๐ฆ. These parameters indicate the treatment of a subscription relative to other traffic between publisher and receiver. Included are:
- A
"dscp"marking to differentiate prioritization of notification messages during network transit. - A
"weighting"so that bandwidth proportional to this weighting can be allocated to this subscription relative to other subscriptions. - A
"dependency"upon another subscription.
If the publisher supports the "dscp" feature, then a subscription with a "dscp" leaf MUST result in a corresponding Differentiated Services Code Point (DSCP) marking [RFC2474] being placed in the IP header of any resulting notification messages and subscription state change notifications. A publisher MUST respect the DSCP markings for subscription traffic egressing that publisher ๐ท๏ธ.
Different DSCP code points require different transport connections. As a result, where TCP is used, a publisher that supports the "dscp" feature must ensure that a subscription's notification messages are returned in a single TCP transport session where all traffic shares the subscription's "dscp" leaf value. If this cannot be guaranteed, any "establish-subscription" RPC request SHOULD be rejected with a "dscp-unavailable" error ๐.
For the "weighting" parameter, when concurrently dequeuing notification messages from multiple subscriptions to a receiver, the publisher MUST allocate bandwidth to each subscription proportional to the weights assigned to those subscriptions. "Weighting" is an optional capability of the publisher. Support for it is identified via the "qos" feature โ๏ธ.
If a subscription has the "dependency" parameter set, then any buffered notification messages containing event records selected by the parent subscription MUST be dequeued prior to the notification messages of the dependent subscription. If notification messages have dependencies on each other, the notification message queued the longest MUST go first. If a "dependency" included in an RPC references a subscription that does not exist or is no longer accessible to that subscriber, that "dependency" MUST be silently removed. "Dependency" is an optional capability of the publisher. Support for it is identified via the "qos" feature ๐.
"Dependency" and "weighting" parameters will only be respected and enforced between subscriptions that share the same "dscp" leaf value ๐ฏ.
There are additional types of publisher capacity overload that this specification does not address, as they are out of scope. For example, the prioritization of which subscriptions have precedence when the publisher CPU is overloaded is not discussed. As a result, implementation choices will need to be made to address such considerations ๐คทโโ๏ธ.
2.4. Dynamic Subscriptions
Dynamic subscriptions are managed via protocol operations (in the form of RPCs, per Section 7.14 of [RFC7950]) made against targets located in the publisher ๐. These RPCs have been designed extensibly so that they may be augmented for subscription targets beyond event streams. For examples of such augmentations, see the RPC augmentations in the YANG data model provided in [RFC8641] ๐.
2.4.1. Dynamic Subscription State Machine ๐ฆ
okay so this is the publisher's state machine for a dynamic subscription ๐
each state gets its own little box. The big tea is that a subscription doesn't exist at the publisher at all until an establish-subscription RPC gets accepted. A subscriber just asking for one isn't enough to make it externally visible ๐ The start and end states are there to show when a subscription gets created and deleted.
.........
: start :
:.......:
|
establish-subscription
|
| .-------modify-subscription--------.
v v |
.-----------. .-----------.
.--------. | receiver |--insufficient CPU, b/w-->| receiver |
modify- '| active | | suspended |
subscription | |<----CPU, b/w sufficient--| |
---------->'-----------' '-----------'
| |
delete/kill-subscription delete/kill-
| subscription
| |
v |
......... |
: end :<---------------------------------'
:.......:
Figure 1: Publisher's State Machine for a Dynamic Subscription
Here's what's important in this state machine โจ
- Successful
establish-subscriptionormodify-subscriptionRPCs move the subscription to the "active" state. ๐ - Failed
modify-subscriptionRPCs leave the subscription in its previous state, with no visible change to any streaming updates. ๐ - A
delete-subscriptionorkill-subscriptionRPC ends the subscription, and so does reaching astop-time. ๐ - A publisher may choose to suspend a subscription when there isn't sufficient CPU or bandwidth available to service it. The subscriber hears about this through the
subscription-suspendedsubscription state change notification. ๐ซถ - A suspended subscription may be modified by the subscriber (for example, to try using fewer resources). A successful modification returns the subscription to the "active" state. ๐ธ
- Even without a
modify-subscriptionrequest, a publisher may return a subscription to the "active" state once sufficient resources are available again. The subscriber gets told about this through thesubscription-resumedsubscription state change notification. ๐
2.4.2. Establishing a Dynamic Subscription ๐ง
the establish-subscription RPC is how a subscriber asks for a subscription to be created ๐
these are the input parameters of the operation:
- A
streamname, which identifies the targeted event stream the subscription is applied against. ๐ - An event stream filter, which may reduce the set of event records pushed. โจ
- If the transport used by the RPC supports multiple encodings, an optional
encodingfor the event records pushed. If noencodingis included, the encoding of the RPC MUST be used. ๐ - An optional
stop-timefor the subscription. If nostop-timeis present, notification messages keep getting sent until the subscription is terminated. โญ - An optional
replay-start-timefor the subscription. Thereplay-start-timeMUST be in the past, and it means the subscription is asking for a replay of previously generated information from the event stream. More on replay in Section 2.4.2.1. If there's noreplay-start-time, the subscription starts right away. ๐ฅ
If the publisher can satisfy the establish-subscription request, it replies with an identifier for the subscription and then immediately starts streaming notification messages ๐
here's a tree diagram for establish-subscription. Everything in this tree is described in the YANG module in Section 4 ๐ธ
+---x establish-subscription
+---w input
| +---w (target)
| | +--:(stream)
| | +---w (stream-filter)?
| | | +--:(by-reference)
| | | | +---w stream-filter-name
| | | | stream-filter-ref
| | | +--:(within-subscription)
| | | +---w (filter-spec)?
| | | +--:(stream-subtree-filter)
| | | | +---w stream-subtree-filter? <anydata>
| | | | {subtree}?
| | | +--:(stream-xpath-filter)
| | | +---w stream-xpath-filter?
| | | yang:xpath1.0 {xpath}?
| | +---w stream stream-ref
| | +---w replay-start-time?
| | yang:date-and-time {replay}?
| +---w stop-time?
| | yang:date-and-time
| +---w dscp? inet:dscp
| | {dscp}?
| +---w weighting? uint8
| | {qos}?
| +---w dependency?
| | subscription-id {qos}?
| +---w encoding? encoding
+--ro output
+--ro id subscription-id
+--ro replay-start-time-revision? yang:date-and-time
{replay}?
Figure 2: "establish-subscription" RPC Tree Diagram
A publisher MAY reject the establish-subscription RPC for lots of reasons, as described in Section 2.4.6 ๐
โโ๏ธ The resulting RPC error response MAY include details on input parameters that, if considered in a subsequent establish-subscription RPC, may result in a successful subscription. Any such hints MUST be transported in a yang-data establish-subscription-stream-error-info container included in the RPC error response. this is the good stuff for retrying ๐ซถ
here's a tree diagram for the establish-subscription-stream-error-info RPC yang-data. Same deal: everything in it is described in the YANG module in Section 4 โจ
yang-data establish-subscription-stream-error-info
+--ro establish-subscription-stream-error-info
+--ro reason? identityref
+--ro filter-failure-hint? string
Figure 3: "establish-subscription-stream-error-info"
RPC yang-data Tree Diagram
2.4.2.1. Requesting a Replay of Event Records ๐ฐ๏ธ
replay is giving "time travel but make it networking" ๐ฎ It lets a subscription that's just starting also pass along event records that were generated in the recent past. As the subscription initializes, it sends any event records in the target event stream that meet the filter criteria and have an event time after the replay-start-time and before the stop-time, if there is one. The end of those historical records gets marked by the replay-completed subscription state change notification. Any event records generated since the subscription was established can follow after that. For a particular subscription, all event records are delivered in the order they were placed in the event stream ๐
Replay is optional, and it depends on an event stream that supports some form of logging. This document doesn't put any restrictions on the size or form of the log, where it lives in the publisher, or when log entries get purged ๐
Including a replay-start-time in an establish-subscription RPC is what signals a replay request. If the replay-start-time is earlier than what the publisher's retained history supports, then, if the subscription is accepted, the publisher's actual revised start time MUST be set in the returned replay-start-time-revision object ๐
A stop-time can be included in a replay subscription too. For a replay subscription, the stop-time MAY be earlier than the current time, but it MUST be later than the replay-start-time ๐
If the given replay-start-time is later than the time marked in any event records retained in the replay buffer, then the publisher MUST send a replay-completed notification immediately after a successful establish-subscription RPC response. โญ
If an event stream supports replay, the replay-support leaf is present in the /streams/stream list entry for that event stream. An event stream that does support replay isn't expected to have an unlimited supply of saved notifications for any given replay request ๐ญ To figure out the timeframe available for replay, subscribers can read the leafs replay-log-creation-time and replay-log-aged-time. See Figure 18 for the YANG tree and Section 4 for the YANG module describing these elements. The actual size of the replay log at any given time is a publisher-specific matter. Control parameters for the replay log are outside the scope of this document ๐
2.4.3. Modifying a Dynamic Subscription โ๏ธ
Okay so the "modify-subscription" operation lets you change the terms of a subscription that already exists ๐ . You can do it as many times as you want, bestie ๐, but ONLY through a transport session that's connecting to the subscriber, so no sneaking it in from somewhere else ๐ โโ๏ธ. If the publisher says yes, it confirms success back to you and then immediately starts sending event records based on the new terms โจ. No cap, that's an instant glow-up ๐.
Subscriptions made through configuration can't be modified with this RPC ๐. BUT you can still use configuration to tweak the stuff the subscription points at, like a filter it references ๐ง.
Here's the tree diagram for "modify-subscription". All the objects in this tree are described in the YANG module in Section 4 ๐.
+---x modify-subscription
+---w input
+---w id
| subscription-id
+---w (target)
| +--:(stream)
| +---w (stream-filter)?
| +--:(by-reference)
| | +---w stream-filter-name
| | stream-filter-ref
| +--:(within-subscription)
| +---w (filter-spec)?
| +--:(stream-subtree-filter)
| | +---w stream-subtree-filter? <anydata>
| | {subtree}?
| +--:(stream-xpath-filter)
| +---w stream-xpath-filter?
| yang:xpath1.0 {xpath}?
+---w stop-time?
yang:date-and-time
Figure 4: "modify-subscription" RPC Tree Diagram
If the publisher accepts the changes on a subscription that's currently suspended ๐ด, the subscription gets resumed right away (aka the modified subscription goes back to the "active" state ๐ข). The publisher MAY immediately suspend this newly modified subscription through the "subscription-suspended" notification before any event records are sent ๐. Plot twist, but it's allowed ๐.
If the publisher rejects the RPC request, the subscription stays exactly as it was before. Like, the request has zero impact whatsoever ๐ซ . Rejection for any reason shows up as an RPC error, as described in Section 2.4.6. The contents of a rejected RPC MAY include hints on inputs that (if considered) may result in a successfully modified subscription ๐ก. These hints MUST be transported in a yang-data "modify-subscription-stream-error-info" container inserted into the RPC error response ๐.
Here's the tree diagram for the "modify-subscription-stream-error-info" RPC yang-data. Again, everything in this tree is described in the YANG module in Section 4 ๐งพ.
yang-data modify-subscription-stream-error-info
+--ro modify-subscription-stream-error-info
+--ro reason? identityref
+--ro filter-failure-hint? string
Figure 5: "modify-subscription-stream-error-info"
RPC yang-data Tree Diagram
2.4.4. Deleting a Dynamic Subscription ๐๏ธ
The "delete-subscription" operation is how you cancel an existing subscription ๐ โโ๏ธ. If the publisher accepts the request and has indicated success, the publisher MUST NOT send any more notification messages for that subscription. Done and dusted ๐.
Here's the tree diagram for "delete-subscription". The YANG module in Section 4 has the details on all these objects ๐.
+---x delete-subscription
+---w input
+---w id subscription-id
Figure 6: "delete-subscription" RPC Tree Diagram
Dynamic subscriptions can only be deleted with this RPC, and only through a transport session connecting to the subscriber ๐. Configured subscriptions can't be deleted using RPCs at all ๐.
2.4.5. Killing a Dynamic Subscription ๐ช
The "kill-subscription" operation lets an operator end a dynamic subscription that is NOT tied to the transport session they used for the RPC ๐. A publisher MUST terminate any dynamic subscription identified by the "id" parameter in the RPC request, if such a subscription exists. Iconic energy โจ.
Configured subscriptions can't be killed with this RPC. Instead, they get deleted as part of regular configuration operations ๐ ๏ธ. Publishers MUST reject any RPC attempt to kill a configured subscription. Nice try, though ๐ .
Here's the tree diagram for "kill-subscription". Everything in it is described in the YANG module in Section 4 ๐งฉ.
+---x kill-subscription
+---w input
+---w id subscription-id
Figure 7: "kill-subscription" RPC Tree Diagram
2.4.6. RPC Failures ๐จ
Whenever an RPC doesn't work out, the publisher sends back relevant info as part of the RPC error response ๐ฌ. Transport-level error processing MUST be done before the RPC error processing described in this section. In every case, the RPC error info the publisher returns will use existing transport-layer RPC structures, like the ones you see with NETCONF (Appendix A of [RFC6241]) or RESTCONF (Section 7.1 of [RFC8040]) ๐ง. These structures MUST be able to encode the subscription-specific errors identified below and defined in this document's YANG data model ๐ฏ.
Because there's so much variety, how subscription errors get encoded in an RPC error response depends on the transport ๐. Here are the valid errors for each RPC:
establish-subscription modify-subscription
---------------------- ----------------------
dscp-unavailable filter-unsupported
encoding-unsupported insufficient-resources
filter-unsupported no-such-subscription
insufficient-resources
replay-unsupported
delete-subscription kill-subscription
---------------------- ----------------------
no-such-subscription no-such-subscription
For a NETCONF-based example of the "no-such-subscription" error response from the list above, check out [RFC8640], Figure 10 ๐.
There's one final set of transport-independent RPC error elements in the YANG data model defined in this document ๐. These are three yang-data structures that let the publisher pass along any error info that doesn't fit into the existing transport-layer RPC structures:
- "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. ๐ง
- "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. ๐ ๏ธ
- "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. ๐ซถ
2.5. Configured Subscriptions ๐ฎ
A configured subscription is one installed via configuration โ๏ธ. Any configuration client with the proper permissions can modify configured subscriptions ๐. You can modify or terminate them via configuration at any point during their lifetime โณ. Multiple configured subscriptions MUST be supportable over a single transport session ๐งต.
Configured subscriptions have a few characteristics that set them apart from dynamic subscriptions ๐:
- persistence across publisher reboots, ๐
- persistence even when the transport is unavailable, and ๐
- an ability to send notification messages to more than one receiver. (Heads up: receivers are unaware of the existence of any other receivers ๐.)
On the publisher, support for configured subscriptions is optional and advertised using the "configured" feature ๐ฆ. On a receiver of a configured subscription, support for dynamic subscriptions is optional. However, if replaying missed event records is required for a configured subscription, support for dynamic subscriptions is highly recommended ๐. In that case, a separate dynamic subscription can be established to retransmit the missing event records ๐.
On top of the subscription parameters available to dynamic subscriptions (see Section 2.4.2), configured subscriptions also get these extra parameters โจ:
- A "transport", which identifies the transport protocol to use to connect with all subscription receivers. ๐
- One or more receivers, each intended as the destination for event records. Note that each individual receiver is identifiable by its "name". ๐ฌ
- Optional parameters to identify where traffic should egress a publisher: ๐ช
- A "source-interface", which identifies the egress interface to use from the publisher. Publisher support for this parameter is optional and advertised using the "interface-designation" feature. ๐
- A "source-address" address, which identifies the IP address to stamp on notification messages destined for the receiver. ๐ท๏ธ
- A "source-vrf", which identifies 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. ๐
If none of the above parameters are set, notification messages MUST egress the publisher's default interface ๐ฃ๏ธ.
A tree diagram that includes these parameters is provided in Figure 20 in Section 3.3 ๐บ๏ธ. These parameters are described in the YANG module in Section 4 ๐๐ .
2.5.1. Configured Subscription State Machine ๐ฆ
Okay bestie, here's the state machine for a configured subscription on the publisher ๐ It has three states, "valid", "invalid", and "concluded", plus all the transitions between them. The start and end states show when a configured subscription gets created or deleted. Creating or modifying one kicks off an evaluation by the publisher to decide whether it's "valid" or "invalid". The publisher uses its own criteria for that, and if it lands in "valid", the subscription becomes operational. That's (1) in the diagram โจ
.........
: start :-.
:.......: |
create .---modify-----.----------------------------------.
| | | |
V V .-------. ....... .---------.
.----[evaluate]--no--->|invalid|-delete->: end :<-delete-|concluded|
| '-------' :.....: '---------'
|-[evaluate]--no-(2). ^ ^ ^
| ^ | | | |
yes | '->unsupportable delete stop-time
| modify (subscription- (subscription- (subscription-
| | terminated*) terminated*) concluded*)
| | | | |
(1) | (3) (4) (5)
| .---------------------------------------------------------------.
'-->| valid |
'---------------------------------------------------------------'
Legend:
Dotted boxes: subscription added or removed via configuration
Dashed boxes: states for a subscription
[evaluate]: decision point on whether the subscription
is supportable
(*): resulting subscription state change notification
Figure 8: Publisher's State Machine for a Configured Subscription
A subscription in "valid" can slide over to "invalid" in two ways ๐ญ First, it might get modified in a way that fails a re-evaluation (that's (2)). Second, the publisher might decide it's no longer supportable. That could happen because of an unexpected but sustained increase in an event stream's event records, degraded CPU capacity, a more complex referenced filter, or other subscriptions that have usurped resources (that's (3)). Either way, a "subscription-terminated" notification goes out to any receivers in the "active" or "suspended" state ๐ A "valid" subscription can also move to "concluded" via (5) if a configured stop time has been reached, and then "subscription-concluded" goes to receivers in "active" or "suspended". Last but not least, configuration can delete the subscription (4) ๐ซถ
When a subscription is "valid", the publisher will try to connect with all receivers of that configured subscription and push notification messages ๐ธ The receiver state machine is fully contained in the configured subscription's state machine, and it only matters while the configured subscription is "valid". Here it is:
.-----------------------------------------------------------------.
| valid |
| .----------. .------------. |
| | receiver |---timeout---------------->| receiver | |
| |connecting|<----------------reset--(c)|disconnected| |
| | |<-transport '------------' |
| '----------' loss,reset------------------------------. |
| (a) | | |
| subscription- (b) (b) |
| started* .--------. .---------. |
| '----->| |(d)-insufficient CPU,------->| | |
| |receiver| buffer overflow |receiver | |
| subscription-| active | |suspended| |
| modified* | |<----CPU, b/w sufficient,-(e)| | |
| '---->'--------' subscription-modified* '---------' |
'-----------------------------------------------------------------'
Legend:
Dashed boxes that include the word "receiver" show the possible
states for an individual receiver of a valid configured
subscription.
* indicates a subscription state change notification
Figure 9: Receiver State Machine for a Configured Subscription
on a Publisher
When a configured subscription first hits "valid", the "state" leaf of each receiver starts out at "connecting" ๐ If there's no transport connectivity to any receivers and there's stuff to deliver, a transport session gets set up (e.g., per [RFC8071]). Receivers hop over to "active" once a "subscription-started" notification gets successfully passed to them (a). Event records only go to active receivers. A receiver stays active if (1) transport connectivity to it is active and (2) event records aren't being dropped because the publisher's sending capacity is maxed out โจ A receiver of a configured subscription MUST be moved to the "connecting" state if it gets reset via the "reset" action (b), (c). For more on the "reset" action, see Section 2.5.5. If transport connectivity can't be achieved while in "connecting", the receiver MAY be moved to "disconnected" ๐
A receiver of a configured subscription MUST be moved to "suspended" if there's transport connectivity between the publisher and receiver, but (1) delivery of notification messages is failing because the publisher's buffer capacity has been reached, or (2) notification messages can't be generated for that receiver because of insufficient CPU (d). The receiver gets told about this with the "subscription-suspended" subscription state change notification ๐ง
A receiver of a configured subscription MUST be returned to "active" from "suspended" when notification messages can be generated, bandwidth is sufficient to handle them, and the receiver has successfully been sent a "subscription-resumed" or "subscription-modified" subscription state change notification (e). Which one gets sent depends on whether the subscription was modified during the suspension ๐
Modifying a configured subscription is possible at any time ๐ A "subscription-modified" notification goes to all active receivers, and it's immediately followed by notification messages that match the new parameters. Suspended receivers get informed of the modification too, but that notification waits until their suspension ends (e). Iconic patience ๐
The mechanisms above are mirrored in the RPCs and notifications defined in this document. These RPCs and notifications were designed to be extensible, so they can allow subscriptions into targets other than event streams ๐ For instance, the YANG module defined in Section 5 of [RFC8641] augments /sn:modify-subscription/sn:input/sn:target.
2.5.2. Creating a Configured Subscription ๐
Configured subscriptions get established using configuration operations against the top-level subscriptions subtree.
Here's the thing: there's no explicit association with an existing transport session, so configuration operations MUST include extra parameters beyond the ones dynamic subscriptions use ๐ซถ Those parameters identify each receiver, how to connect with that receiver, and possibly whether the notification messages need to come from a specific egress interface on the publisher. Receiver-specific transport connectivity parameters MUST be configured via transport-specific augmentations to this specification. See Section 2.5.7 for details ๐ธ
Once a subscription is successfully established, the publisher immediately sends a "subscription-started" subscription state change notification to each receiver โจ It's totally possible that, at configuration, reboot, or even during steady-state operations, a transport session isn't available to the receiver yet. In that case, once there's something to transport for an active subscription, transport-specific "call home" operations [RFC8071] get used to set up the connection. When transport connectivity is available, notification messages can then be pushed ๐ฆ
With active configured subscriptions, it's allowable to buffer event records even after a "subscription-started" has been sent ๐ However, if events get lost (rather than just delayed) because replay buffer capacity was reached, a new "subscription-started" must be sent. That new "subscription-started" signals an event record discontinuity ๐ญ
To see an example of subscription creation using configuration operations over NETCONF, check out Appendix A ๐
2.5.3. Modifying a Configured Subscription ๐
Configured subscriptions can be modified using configuration operations against the top-level subscriptions subtree ๐
If the modification involves adding receivers, the added receivers get placed in the "connecting" state. If a receiver is removed, the "subscription-terminated" subscription state change notification is sent to that receiver if it's active or suspended ๐
If the modification involves changing the policies for the subscription, the publisher sends a "subscription-modified" notification to the currently active receivers โจ For any suspended receivers, the "subscription-modified" notification gets delayed until that receiver's subscription has been resumed. (Note: in this case, the "subscription-modified" notification tells the receiver that the subscription has been resumed, so no additional "subscription-resumed" needs to be sent. Also note that if multiple modifications happen during the suspension, only the "subscription-modified" notification describing the latest one needs to be sent to the receiver ๐ง)
2.5.4. Deleting a Configured Subscription ๐ซถ
Subscriptions can be deleted through configuration against the top-level subscriptions subtree ๐
Immediately after a subscription is successfully deleted, the publisher sends a subscription state change notification to all receivers of that subscription, stating that the subscription has ended (i.e., "subscription-terminated") ๐ฅ
2.5.5. Resetting a Configured Subscription's Receiver
okay so sometimes a configured subscription to a receiver needs a reset ๐. You do it with the "reset" action in the YANG module at /subscriptions/subscription/receivers/receiver/reset. This comes in handy when a publisher has timed out trying to reach a receiver ๐ญ. When a reset happens, a transport session gets initiated if it's needed, and a new "subscription-started" notification gets sent ๐. If the connectivity it needs already exists, this action doesn't touch transport connectivity at all โจ.
2.5.6. Replay for a Configured Subscription
replay works on configured subscriptions too ๐. You set it up through the "configured-replay" object on the subscription. Turning it on makes the publisher stream the buffered event records for the subscribed event stream ๐. Every buffered record that's been kept since the last publisher restart gets sent to each configured receiver ๐.
replay of event records created since restart is seriously useful ๐. It lets event records that were generated before transport connectivity was set up still reach a receiver. Setting the restart time as the earliest configured replay time means old records from before the restart can't get resent ๐ซ. It also makes sure every configured receiver gets the same records, no matter how fast each one's transport connectivity comes up ๐โโ๏ธ. And by making restart the earliest possible time for event records to show up in notification messages, you get a well-understood timeframe for replay ๐.
so when any configured subscription's receivers become active, the buffered event records get sent right after the "subscription-started" notification ๐. If the publisher knows the last event record a receiver got, and the publisher hasn't rebooted, the next event record on the event stream that matches the filter criteria is the leading event record sent. Otherwise, the leading event record is the first one matching the filter criteria that comes after the latest of three different times: the "replay-log-creation-time", the "replay-log-aged-time", or the most recent publisher boot time ๐ฐ๏ธ. The "replay-log-creation-time" and "replay-log-aged-time" are covered in Section 2.4.2.1. The most recent boot time makes sure duplicate event records don't get replayed from an earlier boot ๐ โโ๏ธ.
it's totally possible a receiver wants event records from before the latest boot ๐. If those records exist and there's a configured replay, the publisher MUST send the time of the event record right before the "replay-start-time" in the "replay-previous-event-time" leaf ๐ฏ. That "replay-previous-event-time" leaf is how the receiver finds out that earlier events from before the reboot exist ๐ง. And if the subscriber was already getting event records with the same subscription "id", the receiver can tell whether there was a gap where records generated on the publisher never arrived ๐ณ๏ธ. With that info, the receiver can decide to dynamically subscribe to pull down any event records that landed in the event stream before the most recent boot time ๐ฅ.
All other replay functionality stays the same as it is for dynamic subscriptions, as described in Section 2.4.2.1 ๐ .
2.5.7. Transport Connectivity for a Configured Subscription
this spec doesn't care what transport you use ๐คทโโ๏ธ. Still, supporting a configured subscription usually means setting up transport connectivity, and the parameters for that are transport specific ๐. So the YANG module in Section 4 can't directly define or expose those transport parameters on its own.
An implementation has to support the connection establishment process ๐ ๏ธ. To make that work, the YANG data model in this document has a node where transport-specific parameters for a particular receiver can be augmented: "/subscriptions/subscription/receivers/receiver" ๐งฉ. By augmenting transport parameters onto that node, system developers can bring in the YANG objects they need for transport connectivity establishment ๐.
which leads to this requirement ๐ฃ: a publisher that supports the feature "configured" MUST also support at least one YANG data model that augments transport connectivity parameters on "/subscriptions/subscription/receivers/receiver". For an example of that kind of augmentation, see Appendix A ๐.
2.6. Event Record Delivery
whether a subscription is dynamic or configured, once it's set up, the publisher streams event records through notification messages based on the subscription's terms ๐. For dynamic subscriptions, the notification messages go over the session that was used to set up the subscription ๐ฌ. For configured subscriptions, they go over the connections specified by the transport and by each receiver of the configured subscription ๐ฃ๏ธ.
a notification message gets sent to a receiver when an event record isn't blocked by the specified filter criteria or by receiver permissions ๐ฆ. This notification message MUST include an <eventTime> object, as shown in [RFC5277], Section 4 โฐ. That <eventTime> MUST be at the top level of a YANG structured event record ๐.
here's an example of a compliant message, adapted from Section 4.2.10 of [RFC7950] and written in XML [W3C.REC-xml-20081126] ๐งพ:
<notification
xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
<eventTime>2007-09-01T10:00:00Z</eventTime>
<link-failure xmlns="https://acme.example.com/system">
<if-name>so-1/2/3.0</if-name>
<if-admin-status>up</if-admin-status>
<if-oper-status>down</if-oper-status>
</link-failure>
</notification>
Figure 10: Subscribed Notification Message
[RFC5277], Section 2.2.1 says a notification message is sent to a subscriber that started a <create-subscription> ๐. With this document, that statement from [RFC5277] should be read more broadly ๐. It means notification messages can also go to a subscriber that started an "establish-subscription", and to a configured receiver that was sent a "subscription-started" ๐.
when a dynamic subscription has been started or modified with "establish-subscription" or "modify-subscription", respectively, event records matching the newly applied filter criteria MUST NOT be sent until after the RPC reply has been sent ๐ โโ๏ธ.
when a configured subscription has been started or modified, event records matching the newly applied filter criteria MUST NOT be sent until after the "subscription-started" or "subscription-modified" notification has been sent, respectively ๐.
2.7. Subscription State Change Notifications
on top of sending event records to receivers, a publisher MUST also send subscription state change notifications whenever subscription-management events happen ๐ข.
these notifications are different from every other notification ๐ . They're never included in any event stream. Instead, they get inserted (as defined in this section) into the sequence of notification messages sent to a particular receiver ๐ฌ. Subscription state change notifications can't be dropped or filtered out, they can't be stored in replay buffers, and they're only delivered to the receivers a subscription actually affects ๐. You can easily spot them among other notification messages because they're tagged with the YANG extension "subscription-state-notif" ๐ท๏ธ.
the full set of subscription state change notifications is described in the subsections below ๐๏ธ.
2.7.1. "subscription-started"
this notification says a configured subscription has started and event records may be sent ๐. It includes all of the subscription's parameters, except for (1) transport connection information for one or more receivers and (2) origin information showing where notification messages will leave the publisher ๐. If the subscription used a referenced filter from the "filters" container, the notification still includes that filter's contents under the "within-subscription" subtree ๐ง.
Heads up: no "subscription-started" notifications are ever sent for dynamic subscriptions ๐ โโ๏ธ.
Here's the tree diagram for "subscription-started". Every object in this tree is described in the YANG module in Section 4 ๐ณ.
+---n subscription-started {configured}?
+--ro id
| subscription-id
+--ro (target)
| +--:(stream)
| +--ro (stream-filter)?
| | +--:(by-reference)
| | | +--ro stream-filter-name
| | | stream-filter-ref
| | +--:(within-subscription)
| | +--ro (filter-spec)?
| | +--:(stream-subtree-filter)
| | | +--ro stream-subtree-filter? <anydata>
| | | {subtree}?
| | +--:(stream-xpath-filter)
| | +--ro stream-xpath-filter? yang:xpath1.0
| | {xpath}?
| +--ro stream stream-ref
| +--ro replay-start-time?
| | yang:date-and-time {replay}?
| +--ro replay-previous-event-time?
| yang:date-and-time {replay}?
+--ro stop-time?
| yang:date-and-time
+--ro dscp? inet:dscp
| {dscp}?
+--ro weighting? uint8 {qos}?
+--ro dependency?
| subscription-id {qos}?
+--ro transport? transport
| {configured}?
+--ro encoding? encoding
+--ro purpose? string
{configured}?
Figure 11: "subscription-started" Notification Tree Diagram
2.7.2. "subscription-modified" ๐ง
okay so this one is the "hey, something about your sub just changed" notification ๐ It shows up right after the last event records that used the old subscription parameters, and before any event records that use the new ones. Clean handoff, no mix-ups โจ
Here's the tree for "subscription-modified". Everything inside it is defined in the YANG module in Section 4 ๐
+---n subscription-modified
+--ro id
| subscription-id
+--ro (target)
| +--:(stream)
| +--ro (stream-filter)?
| | +--:(by-reference)
| | | +--ro stream-filter-name
| | | stream-filter-ref
| | +--:(within-subscription)
| | +--ro (filter-spec)?
| | +--:(stream-subtree-filter)
| | | +--ro stream-subtree-filter? <anydata>
| | | {subtree}?
| | +--:(stream-xpath-filter)
| | +--ro stream-xpath-filter? yang:xpath1.0
| | {xpath}?
| +--ro stream stream-ref
| +--ro replay-start-time?
| yang:date-and-time {replay}?
+--ro stop-time?
| yang:date-and-time
+--ro dscp? inet:dscp
| {dscp}?
+--ro weighting? uint8 {qos}?
+--ro dependency?
| subscription-id {qos}?
+--ro transport? transport
| {configured}?
+--ro encoding? encoding
+--ro purpose? string
{configured}?
Figure 12: "subscription-modified" Notification Tree Diagram
Publishers usually send this right after someone changes a config parameter that affects a configured subscription. It can also pop up at two other moments:
- If a configured subscription gets modified while a receiver is suspended, the notification waits until that suspension is lifted. Then it tells the receiver that the subscription has been both modified and resumed ๐ฆ
- A "subscription-modified" subscription state change notification MUST be sent if the contents of the filter pointed to by the subscription's "stream-filter-ref" leaf have changed. This one goes out for any filter change that hits an active receiver of a configured or dynamic subscription ๐ซถ
2.7.3. "subscription-terminated" ๐
This one says "bye bye, no more event records for this subscription, don't wait up" ๐ญ A publisher can stop sending event records to a receiver for these reasons:
- A configuration change removes a configured subscription, or a "kill-subscription" RPC ends a dynamic subscription. Both are identified with the reason "no-such-subscription".
- A referenced filter is no longer accessible. This is identified by the "filter-unavailable" identity.
- The event stream a subscription references is no longer accessible to the receiver. This is identified by the "stream-unavailable" identity.
- A suspended subscription has gone over some timeout. This is identified by the "suspension-timeout" identity.
Every reason above derives from the "subscription-terminated-reason" base identity, which is specified in the YANG data model in this document ๐ธ
Here's the tree for "subscription-terminated". Everything in it is described in the YANG module in Section 4 ๐
+---n subscription-terminated
+--ro id subscription-id
+--ro reason identityref
Figure 13: "subscription-terminated" Notification Tree Diagram
Note: This subscription state change notification MUST be sent to a dynamic subscription's receiver when the subscription ends unexpectedly. That can happen when a "kill-subscription" RPC succeeds, or when something else (not reaching the subscription's "stop-time") makes the publisher end the subscription. It's giving "surprise, we're done" ๐
2.7.4. "subscription-suspended" โธ๏ธ
This notification means the publisher has paused sending event records to a receiver, and it also flags that events might get lost ๐ฌ Suspension happens when capacity limits stop a publisher from serving a valid subscription. There are two conditions where that can happen:
- "insufficient-resources", when the publisher can't produce the requested event stream of notification messages, and
- "unsupportable-volume", when the bandwidth needed to deliver generated notification messages to a receiver goes over a threshold.
Both conditions are encoded in the "reason" object. No more notifications get sent until the subscription resumes or gets terminated ๐ง
Here's the tree for "subscription-suspended". Everything in it is described in the YANG module in Section 4 ๐
+---n subscription-suspended
+--ro id subscription-id
+--ro reason identityref
Figure 14: "subscription-suspended" Notification Tree Diagram
2.7.5. "subscription-resumed" โถ๏ธ
This is the "we're back, baby" notification โจ It means a previously suspended subscription has resumed under the same terms it had before. Event records generated after this notification is issued can now be sent again ๐
Here's the tree for "subscription-resumed". Everything in it is described in the YANG module in Section 4 ๐
+---n subscription-resumed
+--ro id subscription-id
Figure 15: "subscription-resumed" Notification Tree Diagram
2.7.6. "subscription-completed" ๐
This one is the victory lap ๐ A subscription that has a "stop-time" has successfully finished passing event records once it reached that time.
Here's the tree for "subscription-completed". Everything in it is described in the YANG module in Section 4 ๐
+---n subscription-completed {configured}?
+--ro id subscription-id
Figure 16: "subscription-completed" Notification Tree Diagram
2.7.7. "replay-completed" โช
This notification says "all the old event records up to now have been delivered to the receiver" ๐ผ It gets sent before any notification message that carries an event record with a timestamp later than either (1) the "stop-time" or (2) the subscription's start time.
If a subscription has no "stop-time", or its "stop-time" hasn't been reached yet, then once "replay-completed" has been sent, new event records keep coming in sequence as they naturally happen on the publisher โจ
Here's the tree for "replay-completed". Everything in it is described in the YANG module in Section 4 ๐ฆ
+---n replay-completed {replay}?
+--ro id subscription-id
Figure 17: "replay-completed" Notification Tree Diagram
2.8. Subscription Monitoring ๐
In the operational state datastore, the "subscriptions" container keeps track of the state of every dynamic subscription and every configured subscription ๐ You can use datastore retrieval operations [RFC8641], or subscribe to the "subscriptions" container (Section 3.3), to monitor subscription state and how each one is connected to its receivers.
Every subscription in the operational state datastore is a list element. That list includes event counters for each receiver, the state of each receiver, and the subscription parameters currently in effect. If the leaf "configured-subscription-state" shows up, that means the subscription came into being through configuration. This leaf also tells you whether the subscription's current state is "valid", "invalid", or "concluded" ๐
To follow the flow of event records in a subscription, there are two counters for each receiver. The first is "sent-event-records", which counts the events identified for sending to a receiver. The second is "excluded-event-records", which counts the event records that were not sent to a receiver. "excluded-event-records" shows the combined results of both access control and per-subscription filtering. For configured subscriptions, these counters get reset whenever the subscription's state is evaluated as "valid" (see (1) in Figure 8) ๐
Dynamic subscriptions are removed from the operational state datastore once they expire (reaching "stop-time") or when they are terminated. A lot of subscription objects look configurable, but dynamic subscriptions only live in the operational state datastore, so they can't be configured ๐
2.9. Support for the "ietf-subscribed-notifications" YANG Module ๐
Publishers that support this document MUST indicate support of the YANG module "ietf-subscribed-notifications" in the publisher's YANG library. On top of that, if supported, the optional features "encode-xml", "encode-json", "configured", "supports-vrf", "qos", "xpath", "subtree", "interface-designation", "dscp", and "replay" MUST be indicated ๐
3. YANG Data Model Tree Diagrams ๐ณ
This section has the tree diagrams for nodes defined in Section 4. For the tree diagrams of subscription state change notifications, check Section 2.7. For the RPC tree diagrams, check Section 2.4 ๐
3.1. The "streams" Container ๐
A publisher keeps a list of available event streams as operational data. That list includes both standardized and vendor-specific event streams. This is how subscribers figure out which streams a publisher supports ๐
Here's the tree for the "streams" container. Everything in it is described in the YANG module in Section 4 ๐งโโ๏ธ
+--ro streams
+--ro stream* [name]
+--ro name string
+--ro description string
+--ro replay-support? empty {replay}?
+--ro replay-log-creation-time yang:date-and-time
| {replay}?
+--ro replay-log-aged-time? yang:date-and-time
{replay}?
Figure 18: "streams" Container Tree Diagram
3.2. The "filters" Container ๐งฉ
The "filters" container keeps a list of all subscription filters that live on beyond the lifecycle of a single subscription. That means predefined filters can be referenced by more than one subscription ๐ซง
Here's the tree for the "filters" container. Everything in it is described in the YANG module in Section 4 ๐ท
+--rw filters
+--rw stream-filter* [name]
+--rw name string
+--rw (filter-spec)?
+--:(stream-subtree-filter)
| +--rw stream-subtree-filter? <anydata> {subtree}?
+--:(stream-xpath-filter)
+--rw stream-xpath-filter? yang:xpath1.0 {xpath}?
Figure 19: "filters" Container Tree Diagram
3.3. The "subscriptions" Container ๐
okay so the "subscriptions" container is basically the master list ๐ of every subscription on a publisher. that includes the configured ones AND the dynamic ones ๐ฆ. you can use it to pull up info about all the subscriptions a publisher is currently serving, so it's giving full overview energy โจ
here's the tree diagram for it! every object in this tree gets described in the YANG module in Section 4 ๐ง
+--rw subscriptions
+--rw subscription* [id]
+--rw id
| subscription-id
+--rw (target)
| +--:(stream)
| +--rw (stream-filter)?
| | +--:(by-reference)
| | | +--rw stream-filter-name
| | | stream-filter-ref
| | +--:(within-subscription)
| | +--rw (filter-spec)?
| | +--:(stream-subtree-filter)
| | | +--rw stream-subtree-filter? <anydata>
| | | {subtree}?
| | +--:(stream-xpath-filter)
| | +--rw stream-xpath-filter?
| | yang:xpath1.0 {xpath}?
| +--rw stream stream-ref
| +--ro replay-start-time?
| | yang:date-and-time {replay}?
| +--rw configured-replay? empty
| {configured,replay}?
+--rw stop-time?
| yang:date-and-time
+--rw dscp? inet:dscp
| {dscp}?
+--rw weighting? uint8 {qos}?
+--rw dependency?
| subscription-id {qos}?
+--rw transport? transport
| {configured}?
+--rw encoding? encoding
+--rw purpose? string
| {configured}?
+--rw (notification-message-origin)? {configured}?
| +--:(interface-originated)
| | +--rw source-interface?
| | if:interface-ref {interface-designation}?
| +--:(address-originated)
| +--rw source-vrf?
| | -> /ni:network-instances/network-instance/name
| | {supports-vrf}?
| +--rw source-address?
| inet:ip-address-no-zone
+--ro configured-subscription-state? enumeration
| {configured}?
+--rw receivers
+--rw receiver* [name]
+--rw name string
+--ro sent-event-records?
| yang:zero-based-counter64
+--ro excluded-event-records?
| yang:zero-based-counter64
+--ro state enumeration
+---x reset {configured}?
+--ro output
+--ro time yang:date-and-time
Figure 20: "subscriptions" Container Tree Diagram
4. Event Notification Subscription YANG Module โจ
okay so this module imports typedefs from [RFC6991], [RFC8343], [RFC8341], [RFC8529], and [RFC8040] ๐ซถ and it references [RFC6241], [XPATH] ("XML Path Language (XPath) Version 1.0"), [RFC7049], [RFC8259], [RFC7950], [RFC7951], and [RFC7540] ๐
<CODE BEGINS> file "ietf-subscribed-notifications@2019-09-09.yang"
module ietf-subscribed-notifications {
yang-version 1.1;
namespace "urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications";
prefix sn;
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-netconf-acm {
prefix nacm;
reference
"RFC 8341: Network Configuration Access Control Model";
}
import ietf-network-instance {
prefix ni;
reference
"RFC 8529: YANG Data Model for Network Instances";
}
import ietf-restconf {
prefix rc;
reference
"RFC 8040: RESTCONF Protocol";
}
import ietf-yang-types {
prefix yang;
reference
"RFC 6991: Common YANG Data Types";
}
organization
"IETF NETCONF (Network Configuration) Working Group";
contact
"WG Web: <https:/datatracker.ietf.org/wg/netconf/>
WG List: <mailto:netconf@ietf.org>
Author: Alexander Clemm
<mailto:ludwig@clemm.org>
Author: Eric Voit
<mailto:evoit@cisco.com>
Author: Alberto Gonzalez Prieto
<mailto:alberto.gonzalez@microsoft.com>
Author: Einar Nilsen-Nygaard
<mailto:einarnn@cisco.com>
Author: Ambika Prasad Tripathy
<mailto:ambtripa@cisco.com>";
description
"This module defines a YANG data model for subscribing to event
records and receiving matching content in notification messages.
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) 2019 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 Simplified 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 8639; see the
RFC itself for full legal notices.";
revision 2019-09-09 {
description
"Initial version.";
reference
"RFC 8639: A YANG Data Model for Subscriptions to
Event Notifications";
}
/*
* FEATURES
*/
feature configured {
description
"This feature indicates that configuration of subscriptions is
supported.";
}
feature dscp {
description
"This feature indicates that a publisher supports the ability
to set the Differentiated Services Code Point (DSCP) value in
outgoing packets.";
}
feature encode-json {
description
"This feature indicates that JSON encoding of notification
messages is supported.";
}
feature encode-xml {
description
"This feature indicates that XML encoding of notification
messages is supported.";
}
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 qos {
description
"This feature indicates that a publisher supports absolute
dependencies of one subscription's traffic over another
as well as weighted bandwidth sharing between subscriptions.
Both of these are Quality of Service (QoS) features that allow
differentiated treatment of notification messages between a
publisher and a specific receiver.";
}
feature replay {
description
"This feature indicates that historical event record replay is
supported. With replay, it is possible for past event records
to be streamed in chronological order.";
}
feature subtree {
description
"This feature indicates support for YANG subtree filtering.";
reference
"RFC 6241: Network Configuration Protocol (NETCONF),
Section 6";
}
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";
}
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)";
}
/*
* EXTENSIONS
*/
extension subscription-state-notification {
description
"This statement applies only to notifications. It indicates
that the notification is a subscription state change
notification. Therefore, it does not participate in a regular
event stream and does not need to be specifically subscribed
to in order to be received. This statement can only occur as
a substatement of the YANG 'notification' statement. This
statement is not for use outside of this YANG module.";
}
/*
* 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 modify-subscription-error {
description
"Base identity for the problem found while attempting to
fulfill a 'modify-subscription' RPC request.";
}
identity subscription-suspended-reason {
description
"Base identity for the problem condition communicated to a
receiver as part of a 'subscription-suspended'
notification.";
}
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;
if-feature "dscp";
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;
base modify-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;
base modify-subscription-error;
base subscription-suspended-reason;
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 modify-subscription-error;
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.";
}
okay so we're still deep in the YANG module, and this bit is giving me everything ๐ฆโจ first up are the extra failure reasons (replay can't happen, the stream isn't subscribable, a suspended sub timed out, the publisher ran out of bandwidth) ๐, then the encoding and transport identities, then a few typedefs and groupings that tie it all together ๐
identity replay-unsupported {
base establish-subscription-error;
if-feature "replay";
description
"Replay cannot be performed for this subscription. This means
the publisher will not provide the requested historic
information from the event stream via replay to this
receiver.";
}
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-suspended-reason;
description
"The publisher does not have the network bandwidth needed to
get the volume of generated information intended for a
receiver.";
}
/* 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.";
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 encode-xml {
base encoding;
if-feature "encode-xml";
description
"Encode data using XML as described in RFC 7950.";
reference
"RFC 7950: The YANG 1.1 Data Modeling Language";
}
identity encode-json {
base encoding;
if-feature "encode-json";
description
"Encode data using JSON as described in RFC 7951.";
reference
"RFC 7951: JSON Encoding of Data Modeled with YANG";
}
/* Identities for transports */
identity transport {
description
"An identity that represents the underlying mechanism for
passing notification messages.";
}
/*
* TYPEDEFs
*/
typedef encoding {
type identityref {
base encoding;
}
description
"Specifies a data encoding, e.g., for a data subscription.";
}
typedef stream-filter-ref {
type leafref {
path "/sn:filters/sn:stream-filter/sn:name";
}
description
"This type is used to reference an event stream filter.";
}
typedef stream-ref {
type leafref {
path "/sn:streams/sn:stream/sn:name";
}
description
"This type is used to reference a system-provided
event stream.";
}
typedef subscription-id {
type uint32;
description
"A type for subscription identifiers.";
}
typedef transport {
type identityref {
base transport;
}
description
"Specifies the transport used to send notification messages
to a receiver.";
}
/*
* GROUPINGS
*/
grouping stream-filter-elements {
description
"This grouping defines the base for filters applied to event
streams.";
choice filter-spec {
description
"The content filter specification for this request.";
anydata stream-subtree-filter {
if-feature "subtree";
description
"Event stream evaluation criteria encoded in the syntax of
a subtree filter as defined in RFC 6241, Section 6.
The subtree filter is applied to the representation of
individual, delineated event records as contained in the
event stream.
If the subtree filter returns a non-empty node set, the
filter matches the event record, and the event record is
included in the notification message sent to the
receivers.";
reference
"RFC 6241: Network Configuration Protocol (NETCONF),
Section 6";
}
leaf stream-xpath-filter {
if-feature "xpath";
type yang:xpath1.0;
description
"Event stream evaluation criteria encoded in the syntax of
an XPath 1.0 expression.
The XPath expression is evaluated on the representation of
individual, delineated event records as contained in
the event stream.
The result of the XPath expression is converted to a
boolean value using the standard XPath 1.0 rules. If the
boolean value is 'true', the filter matches the event
record, and the event record is included in the
notification message sent to the receivers.
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.";
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-qos {
description
"This grouping describes QoS information concerning a
subscription. This information is passed to lower layers
for transport prioritization and treatment.";
leaf dscp {
if-feature "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.";
}
leaf weighting {
if-feature "qos";
type uint8 {
range "0 .. 255";
}
description
"Relative weighting for a subscription. Larger weights get
more resources. Allows an underlying transport layer to
perform informed load-balance allocations between various
subscriptions.";
reference
"RFC 7540: Hypertext Transfer Protocol Version 2 (HTTP/2),
Section 5.3.2";
}
leaf dependency {
if-feature "qos";
type subscription-id;
description
"Provides the 'subscription-id' of a parent subscription.
The parent subscription has absolute precedence should
that parent have push updates ready to egress the publisher.
In other words, there should be no streaming of objects from
the current subscription if the parent has something ready
to push.
If a dependency is asserted via configuration or via an RPC
but the referenced 'subscription-id' does not exist, the
dependency is silently discarded. If a referenced
subscription is deleted, this dependency is removed.";
reference
"RFC 7540: Hypertext Transfer Protocol Version 2 (HTTP/2),
Section 5.3.1";
}
}
grouping subscription-policy-modifiable {
description
"This grouping describes all objects that may be changed
in a subscription.";
choice target {
mandatory true;
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.";
case stream {
choice stream-filter {
description
"An event stream filter can be applied to a subscription.
That filter will either come referenced from a global
list or be provided in the subscription itself.";
case by-reference {
description
"Apply a filter that has been configured separately.";
leaf stream-filter-name {
type stream-filter-ref;
mandatory true;
description
"References an existing event stream filter that is
to be applied to an event stream for the
subscription.";
}
}
case within-subscription {
description
"A local definition allows a filter to have the same
lifecycle as the subscription.";
uses stream-filter-elements;
}
}
}
}
leaf stop-time {
type yang:date-and-time;
description
"Identifies a time after which notification messages for a
subscription should not be sent. If 'stop-time' is not
present, the notification messages will continue until the
subscription is terminated. If 'replay-start-time' exists,
'stop-time' must be for a subsequent time. If
'replay-start-time' doesn't exist, 'stop-time', when
established, must be for a future time.";
}
}
grouping subscription-policy-dynamic {
description
"This grouping describes the only information concerning a
subscription that can be passed over the RPCs defined in this
data model.";
uses subscription-policy-modifiable {
augment "target/stream" {
description
"Adds additional objects that can be modified by an RPC.";
leaf stream {
type stream-ref {
require-instance false;
}
mandatory true;
description
"Indicates the event stream to be considered for
this subscription.";
}
leaf replay-start-time {
if-feature "replay";
type yang:date-and-time;
config false;
description
"Used to trigger the 'replay' feature for a dynamic
subscription, where event records that are selected
need to be at or after the specified starting time. If
'replay-start-time' is not present, this is not a replay
subscription and event record push should start
immediately. It is never valid to specify start times
that are later than or equal to the current time.";
}
}
}
uses update-qos;
}
okay the groupings at the bottom are where the bits come together ๐ง the filter stuff can be a reference or live right inside the subscription, the QoS knobs ride along, and the stop-time and replay-start-time stuff got its own vibe ๐
grouping subscription-policy { description "This grouping describes the full set of policy information concerning both dynamic and configured subscriptions, with the exclusion of both receivers and networking information specific to the publisher, such as what interface should be used to transmit notification messages."; uses subscription-policy-dynamic; leaf transport { if-feature "configured"; type transport; description "For a configured subscription, this leaf specifies the transport used to deliver messages destined for all receivers of that subscription."; } leaf encoding { when 'not(../transport) or derived-from(../transport, "sn:configurable-encoding")'; type encoding; description "The type of encoding for notification messages. For a
dynamic subscription, if not included as part of an 'establish-subscription' RPC, the encoding will be populated with the encoding used by that RPC. For a configured subscription, if not explicitly configured, the encoding will be the default encoding for an underlying transport."; } leaf purpose { if-feature "configured"; type string; description "Open text allowing a configuring entity to embed the originator or other specifics of this subscription."; } }
/*
- RPCs */
rpc establish-subscription { 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 subscription-policy-dynamic; leaf encoding { type encoding; description "The type of encoding for the subscribed data. If not included as part of the RPC, the encoding MUST be set by the publisher to be the encoding used by this RPC."; } } output { leaf id { type subscription-id; mandatory true; description "Identifier used for this subscription.";
} leaf replay-start-time-revision { if-feature "replay"; type yang:date-and-time; description "If a replay has been requested, this object represents the earliest time covered by the event buffer for the requested event stream. The value of this object is the 'replay-log-aged-time' if it exists. Otherwise, it is the 'replay-log-creation-time'. All buffered event records after this time will be replayed to a receiver. This object will only be sent if the starting time has been revised to be later than the time requested by the subscriber."; } } }
rc:yang-data 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 modify-subscription { 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. In that case, the RPC error MAY include 'error-info' suggested parameter hints that would have a high likelihood of succeeding in a subsequent 'modify-subscription' request. A successful 'modify-subscription' will return a suspended subscription to the 'active' state."; input { leaf id { type subscription-id; mandatory true; description "Identifier to use for this subscription."; } uses subscription-policy-modifiable; } }
rc:yang-data modify-subscription-stream-error-info { container modify-subscription-stream-error-info { description "This yang-data MAY be provided as part of a subscription's RPC error response when there is a failure of a 'modify-subscription' RPC that has been made against an event stream. This yang-data MUST be used if hints are to be provided back to the subscriber."; leaf reason { type identityref { base modify-subscription-error; } description "Information in a 'modify-subscription' RPC error response that indicates the reason why the subscription to an event stream has failed to be modified."; } 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 { description "This RPC allows a subscriber to delete a subscription that was previously created by that same subscriber using the 'establish-subscription' 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 "Identifier of the subscription that is to be deleted. Only subscriptions that were created using 'establish-subscription' from the same origin as this RPC can be deleted via this RPC."; } } }
rpc kill-subscription { 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.
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 "Identifier of the subscription that is to be deleted. Only subscriptions that were created using 'establish-subscription' can be deleted via this RPC."; } }
}
rc:yang-data 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 */
notification replay-completed { sn:subscription-state-notification; if-feature "replay"; description "This notification is sent to indicate that all of the replay notifications have been sent."; leaf id { type subscription-id; mandatory true; description "This references the affected subscription."; } }
notification subscription-completed { sn:subscription-state-notification; if-feature "configured"; description "This notification is sent to indicate that a subscription has finished passing event records, as the 'stop-time' has been reached.";
leaf id { type subscription-id; mandatory true; description "This references the gracefully completed subscription."; } }
notification subscription-modified { sn:subscription-state-notification; description "This notification indicates that a subscription has been modified. Notification messages sent from this point on will conform to the modified terms of the subscription. For completeness, this subscription state change notification includes both modified and unmodified aspects of a subscription."; leaf id { type subscription-id; mandatory true; description "This references the affected subscription."; } uses subscription-policy { refine "target/stream/stream-filter/within-subscription" { description "Filter applied to the subscription. If the 'stream-filter-name' is populated, the filter in the subscription came from the 'filters' container. Otherwise, it is populated in-line as part of the subscription."; } } }
notification subscription-resumed { sn:subscription-state-notification; description "This notification indicates that a subscription that had previously been suspended has resumed. Notifications will once again be sent. In addition, a 'subscription-resumed' indicates that no modification of parameters has occurred since the last time event records have been sent."; leaf id { type subscription-id; mandatory true; description "This references the affected subscription.";
} }
notification subscription-started { sn:subscription-state-notification; if-feature "configured"; description "This notification indicates that a subscription has started and notifications will now be sent."; leaf id { type subscription-id; mandatory true; description "This references the affected subscription."; } uses subscription-policy { refine "target/stream/replay-start-time" { description "Indicates the time that a replay is using for the streaming of buffered event records. This will be populated with the most recent of the following: the event time of the previous event record sent to a receiver, the 'replay-log-creation-time', the 'replay-log-aged-time', or the most recent publisher boot time."; } refine "target/stream/stream-filter/within-subscription" { description "Filter applied to the subscription. If the 'stream-filter-name' is populated, the filter in the subscription came from the 'filters' container. Otherwise, it is populated in-line as part of the subscription."; } augment "target/stream" { description "This augmentation adds additional parameters specific to a 'subscription-started' notification."; leaf replay-previous-event-time { when '../replay-start-time'; if-feature "replay"; type yang:date-and-time; description "If there is at least one event in the replay buffer prior to 'replay-start-time', this gives the time of the event generated immediately prior to the 'replay-start-time'.
If a receiver previously received event records for this configured subscription, it can compare this time to the last event record previously received. If the two are not the same (perhaps due to a reboot), then a dynamic replay can be initiated to acquire any missing event records."; } } } }
notification subscription-suspended { sn:subscription-state-notification; description "This notification indicates that a suspension of the subscription by the publisher has occurred. No further notifications will be sent until the subscription resumes. This notification shall only be sent to receivers of a subscription; it does not constitute a general-purpose notification."; leaf id { type subscription-id; mandatory true; description "This references the affected subscription."; } leaf reason { type identityref { base subscription-suspended-reason; } mandatory true; description "Identifies the condition that resulted in the suspension."; } }
notification subscription-terminated { sn:subscription-state-notification; description "This notification indicates that a subscription has been terminated."; leaf id { type subscription-id; mandatory true; description "This references the affected subscription."; } leaf reason {
type identityref { base subscription-terminated-reason; } mandatory true; description "Identifies the condition that resulted in the termination."; } }
/*
- DATA NODES */
container streams { config false; description "Contains information on the built-in event streams provided by the publisher."; list stream { key "name"; description "Identifies the built-in event streams that are supported by the publisher."; leaf name { type string; description "A handle for a system-provided event stream made up of a sequential set of event records, each of which is characterized by its own domain and semantics."; } leaf description { type string; description "A description of the event stream, including such information as the type of event records that are available in this event stream."; } leaf replay-support { if-feature "replay"; type empty; description "Indicates that event record replay is available on this event stream."; } leaf replay-log-creation-time { when '../replay-support'; if-feature "replay"; type yang:date-and-time; mandatory true; description "The timestamp of the creation of the log used to support the replay function on this event stream. This time might be earlier than the earliest available information contained in the log. This object is updated if the log resets for some reason."; } leaf replay-log-aged-time { when '../replay-support'; if-feature "replay"; type yang:date-and-time; description "The timestamp associated with the last event record that has been aged out of the log. This timestamp identifies how far back in history this replay log extends, if it doesn't extend back to the 'replay-log-creation-time'. This object MUST be present if replay is supported and any event records have been aged out of the log."; } } } 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 stream-filter { key "name"; description "A list of preconfigured filters that can be applied to subscriptions."; leaf name { type string; description "A name to differentiate between filters."; } uses stream-filter-elements; } } 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.";
leaf id {
type subscription-id;
description
"Identifier of a subscription; unique in a given
publisher.";
}
uses subscription-policy {
refine "target/stream/stream" {
description
"Indicates the event stream to be considered for this
subscription. If an event stream has been removed
and can no longer be referenced by an active
subscription, send a 'subscription-terminated'
notification with 'stream-unavailable' as the reason.
If a configured subscription refers to a nonexistent
event stream, move that subscription to the
'invalid' state.";
}
refine "transport" {
description
"For a configured subscription, this leaf specifies the
transport used to deliver messages destined for all
receivers of that subscription. This object is
mandatory for subscriptions in the configuration
datastore. This object (1) is not mandatory for dynamic
subscriptions in the operational state datastore and
(2) should not be present for other types of dynamic
subscriptions.";
}
augment "target/stream" {
description
"Enables objects to be added to a configured stream
subscription.";
leaf configured-replay {
if-feature "configured";
if-feature "replay";
type empty;
description
"The presence of this leaf indicates that replay for
the configured subscription should start at the
earliest time in the event log or at the publisher
boot time, whichever is later.";
}
}
}
choice notification-message-origin {
if-feature "configured";
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.";
}
}
}
leaf configured-subscription-state {
if-feature "configured";
type enumeration {
enum valid {
value 1;
description
"The subscription is supportable with its current
parameters.";
}
enum invalid {
value 2;
description
"The subscription as a whole is unsupportable with its
current parameters.";
}
enum concluded {
value 3;
description
"A subscription is inactive, as it has hit a
stop time. It no longer has receivers in the
'active' or 'suspended' state, but the subscription
has not yet been removed from configuration.";
}
}
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.";
}
container receivers {
description
"Set of receivers in a subscription.";
list receiver {
key "name";
min-elements 1;
description
"A host intended as a recipient for the notification
messages of a subscription. For configured
subscriptions, transport-specific network parameters
(or a leafref to those parameters) may be augmented to a
specific receiver in this list.";
leaf name {
type string;
description
"Identifies a unique receiver for a subscription.";
}
leaf sent-event-records {
type yang:zero-based-counter64;
config false;
description
"The number of event records sent to the receiver. The
count is initialized when a dynamic subscription is
established or when a configured receiver
transitions to the 'valid' state.";
}
leaf excluded-event-records {
type yang:zero-based-counter64;
config false;
description
"The number of event records explicitly removed via
either an event stream filter or an access control
filter so that they are not passed to a receiver.
This count is set to zero each time
'sent-event-records' is initialized.";
}
leaf state {
type enumeration {
enum active {
value 1;
description
"The receiver is currently being sent any
applicable notification messages for the
subscription.";
}
enum suspended {
value 2;
description
"The receiver state is 'suspended', so the
publisher is currently unable to provide
notification messages for the subscription.";
}
enum connecting {
value 3;
if-feature "configured";
description
"A subscription has been configured, but a
'subscription-started' subscription state change
notification needs to be successfully received
before notification messages are sent.
If the 'reset' action is invoked for a receiver of
an active configured subscription, the state
must be moved to 'connecting'.";
}
enum disconnected {
value 4;
if-feature "configured";
description
"A subscription has failed to send a
'subscription-started' state change to the
receiver. Additional connection attempts are not
currently being made.";
}
}
config false;
mandatory true;
description
"Specifies the state of a subscription from the
perspective of a particular receiver. With this
information, it is possible to determine whether a
publisher is currently generating notification
messages intended for that receiver.";
}
action reset {
if-feature "configured";
description
"Allows the reset of this configured subscription's
receiver to the 'connecting' state. This enables the
connection process to be reinitiated.";
output {
leaf time {
type yang:date-and-time;
mandatory true;
description
"Time at which a publisher returned the receiver to
the 'connecting' state.";
}
}
}
}
}
}
}
}
<CODE ENDS>
5. IANA Considerations ๐ง
okay so IANA (the folks who keep the official registries ๐) registered one URI in the "ns" subregistry of the "IETF XML Registry" [RFC3688], which lives at <https://www.iana.org/assignments/xml-registry>. The registration followed the format in [RFC3688], and it looks like this:
URI: urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications
Registrant Contact: The NETCONF WG of the IETF.
XML: N/A; the requested URI is an XML namespace.
IANA also registered one YANG module in the "YANG Module Names" registry [RFC6020], maintained at <https://www.iana.org/assignments/yang-parameters>. That registration followed the format in [RFC6020] too, and it's giving very organized energy ๐ :
Name: ietf-subscribed-notifications
Namespace: urn:ietf:params:xml:ns:yang:ietf-subscribed-notifications
Prefix: sn
Reference: RFC 8639
6. Implementation Considerations ๐
okay bestie, this part is all about the stuff that makes deployments run smoothly โจ If you've got both configured and dynamic subscriptions in the same box, it's recommended that you split the subscription id domain into a static half and a dynamic half ๐. That way, a configured subscription trying to set a subscription-id can never collide with one that was already dynamically allocated. The best practice is to use the lower half of the id integer space whenever an external entity assigns that id (like with a configured subscription). That leaves the upper half free for the publisher to hand out dynamically ๐ฆ.
If a subscription can't turn a series of filtered event records into transmittable notification messages, the receiver should be suspended with the reason "unsupportable-volume" ๐ญ.
For configured subscriptions, operations are done against the whole set of receivers, using the subscription id as a handle for that set ๐ง. But streaming updates are different: subscription state change notifications are local to each receiver ๐ธ. In this spec, receivers don't get any info from the publisher about the other receivers existing at all. Still, if a network operator wants the receivers to be able to correlate their results, it's useful to reuse the subscription id across all of them ๐ฅ. Heads up though: because access control permissions can differ per receiver, each receiver might actually end up with a different set of event records ๐.
For configured replay subscriptions, the receiver is protected from duplicated events being pushed after a publisher reboots ๐ซถ. However, a receiver might still want event records that failed to be delivered right before the reboot. You can get those by using the <eventTime> [RFC5277] from the last event record received before the "subscription-started" subscription state change notification arrived ๐. With that <eventTime> and the replay-start-time from the "subscription-started" notification, you can set up an independent dynamic subscription that pulls any event records that were generated but never sent to the receiver ๐. Main character energy, literally ๐.
7. Transport Requirements โจ
okay bestie, this section is the transport checklist ๐ It lays out what any transport built on this solution needs to be able to do ๐
The transport the subscriber picks to reach the publisher MUST be able to support multiple "establish-subscription" requests made in the same transport session ๐ฆ
For both configured and dynamic subscriptions, the publisher MUST authenticate a receiver via some transport-level mechanism before sending any event records that the receiver is authorized to see. And the receiver MUST authenticate the publisher at the transport level too ๐ซถ So the result is mutual authentication, both sides checking each other, no cap ๐
A secure transport is highly recommended ๐ Beyond that, the publisher MUST ensure that the receiver has sufficient authorization to perform the function it is requesting against the specific subset of content involved. Access check, periodt ๐
A specification for a transport built on this document may or may not choose to require the same logical channel for the RPCs and the event records. That part is up to them ๐ธ But the event records and the subscription state change notifications MUST be sent on the same transport session so they arrive in properly ordered delivery. Order matters, bestie ๐ญ
A specification for a transport MUST identify any encodings that are supported. If a configured subscription's transport allows different encodings, the specification MUST identify the default encoding ๐
A subscriber that includes a dscp leaf in an establish-subscription request will need to understand and consider what the corresponding DSCP value represents in the domain of the publisher ๐ง Same number, different meaning, iykyk.
Additional transport requirements will be dictated by the choice of transport used with a subscription. For an example of such requirements, see [RFC8640] โจ
8. Security Considerations ๐ฅ
This part is serious, so I'm putting on my detective hat ๐ต๏ธโโ๏ธ
The YANG module in this document defines a schema for data that is designed to be accessed via network management protocols such as NETCONF [RFC6241] or RESTCONF [RFC8040]. The lowest NETCONF layer is the secure transport layer, and the mandatory-to-implement secure transport is Secure Shell (SSH) [RFC6242]. The lowest RESTCONF layer is HTTPS, and the mandatory-to-implement secure transport is TLS [RFC5246] ๐
The Network Configuration Access Control Model (NACM) [RFC8341] gives you the tools to restrict access for particular NETCONF or RESTCONF users to a preconfigured subset of all available NETCONF or RESTCONF protocol operations and content ๐
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 only need to 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 momentarily disrupted receiver connectivity ๐ To grab the events lost during that gap, the receiver SHOULD retrieve any event records generated since the last event record was received. One way to do that is a separate dynamic replay subscription with the same filtering criteria, as long as the publisher supports the "replay" feature ๐ฆ
For dynamic subscriptions, implementations need to protect against malicious or buggy subscribers that may send a large number of "establish-subscription" requests and use up system resources. Operators SHOULD monitor for this, and if they spot it, take remedial action to limit the resources used, like suspending or terminating a subset of the subscriptions or, if the underlying transport is session based, terminating the underlying transport session ๐จ
The replay mechanisms described in Sections 2.4.2.1 and 2.5.6 provide access to historical event records. By design, the access control model that protects these records could let subscribers view data they weren't authorized to see at the time of collection. Yikes ๐
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 ๐งญ
An attacker that can cause the publisher to use an incorrect time can induce message replay by setting the time in the past, and can introduce a risk of message loss by setting the time in the future โฐ
There are a number of data nodes defined in this YANG module that are writable, creatable, and deletable (that's config true, which is the default) ๐ These data nodes may be considered sensitive or vulnerable in some network environments. Write operations (e.g., edit-config) to these data nodes without proper protection can have a negative effect on network operations. Here are the subtrees and data nodes and their sensitivity/vulnerability:
Container: "/filters"
"stream-subtree-filter": Updating a filter could increase the computational complexity of all referencing subscriptions."stream-xpath-filter": Updating a filter could increase the computational complexity of all referencing subscriptions.
Container: "/subscriptions"
The following considerations are only relevant for configuration operations made upon configured subscriptions:
"configured-replay": Can be used to send a large number of event records to a receiver."dependency": Can be used to force important traffic to be queued behind updates that are not as important."dscp": If unvalidated, can result in the sending of traffic with a higher-priority marking than warranted."id": Can overwrite an existing subscription, perhaps one configured by another entity."name": Adding a new key entry can be used to attempt to send traffic to an unwilling receiver."replay-start-time": Can be used to push very large logs, wasting resources."source-address": The configured address might not be able to reach a desired receiver."source-interface": The configured interface might not be able to reach a desired receiver."source-vrf": Can place a subscription in a virtual network where receivers are not entitled to view the subscribed content."stop-time": Could be used to terminate content at an inopportune time."stream": Could set a subscription to an event stream that does not contain content permitted for the targeted receivers."stream-filter-name": Could be set to a filter that is not relevant to the event stream."stream-subtree-filter": A complex filter can increase the computational resources for this subscription."stream-xpath-filter": A complex filter can increase the computational resources for this subscription."weighting": Allocating a large weight can overwhelm the dequeuing of other subscriptions.
Some of the readable data nodes in this YANG module may be considered sensitive or vulnerable in some network environments ๐ It's thus important to control read access (e.g., via get, get-config, or notification) to these data nodes. Here are the subtrees and data nodes and their sensitivity/vulnerability:
Container: "/streams"
"name": If access control is not properly configured, can expose system internals to those who should not have access to this information."replay-support": If access control is not properly configured, can expose logs to those who should not have access.
Container: "/subscriptions"
"excluded-event-records": This leaf can provide information about filtered event records. A network operator should have the proper permissions to know about such filtering. However, exposing the count of excluded events to a receiver could leak information about the presence of access control filters that might be in place for that receiver ๐คซ"subscription": Different operational teams might have a desire to set varying subsets of subscriptions. Access control should be designed to permit read access to just the allowed set.
Some of the RPC operations in this YANG module may be considered sensitive or vulnerable in some network environments, so it's important to control access to these operations. Here are the operations and their sensitivity/vulnerability:
RPC: all
- If a malicious or buggy subscriber sends an unexpectedly large number of RPCs, the result might be excessive use of system resources on the publisher just to determine that these subscriptions should be declined. In such a situation, subscription interactions MAY be terminated by terminating the transport session ๐ซ
RPC: "delete-subscription"
- No special considerations โจ
RPC: "establish-subscription"
- Subscriptions could overload a publisher's resources. For this reason, publishers MUST ensure that they have sufficient resources to fulfill this request; otherwise, they MUST reject the request ๐
RPC: "kill-subscription"
- The
"kill-subscription"RPC MUST be secured so that only connections with administrative rights are able to invoke this RPC ๐
RPC: "modify-subscription"
- Subscriptions could overload a publisher's resources. For this reason, publishers MUST ensure that they have sufficient resources to fulfill this request; otherwise, they MUST reject the request ๐
9. References ๐
9.1. Normative References ๐
these are the must-reads, the specs this one leans on the hardest ๐
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
Requirement Levels", BCP 14, RFC 2119,
DOI 10.17487/RFC2119, March 1997,
<https://www.rfc-editor.org/info/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, December 1998,
<https://www.rfc-editor.org/info/rfc2474>.
[RFC3688] Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688,
DOI 10.17487/RFC3688, January 2004,
<https://www.rfc-editor.org/info/rfc3688>.
[RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security
(TLS) Protocol Version 1.2", RFC 5246,
DOI 10.17487/RFC5246, August 2008,
<https://www.rfc-editor.org/info/rfc5246>.
[RFC5277] Chisholm, S. and H. Trevino, "NETCONF Event
Notifications", RFC 5277, DOI 10.17487/RFC5277, July 2008,
<https://www.rfc-editor.org/info/rfc5277>.
[RFC6020] Bjorklund, M., Ed., "YANG - A Data Modeling Language for
the Network Configuration Protocol (NETCONF)", RFC 6020,
DOI 10.17487/RFC6020, October 2010,
<https://www.rfc-editor.org/info/rfc6020>.
[RFC6241] Enns, R., Ed., Bjorklund, M., Ed., Schoenwaelder, J., Ed.,
and A. Bierman, Ed., "Network Configuration Protocol
(NETCONF)", RFC 6241, DOI 10.17487/RFC6241, June 2011,
<https://www.rfc-editor.org/info/rfc6241>.
[RFC6242] Wasserman, M., "Using the NETCONF Protocol over Secure
Shell (SSH)", RFC 6242, DOI 10.17487/RFC6242, June 2011,
<https://www.rfc-editor.org/info/rfc6242>.
[RFC6991] Schoenwaelder, J., Ed., "Common YANG Data Types",
RFC 6991, DOI 10.17487/RFC6991, July 2013,
<https://www.rfc-editor.org/info/rfc6991>.
[RFC7950] Bjorklund, M., Ed., "The YANG 1.1 Data Modeling Language",
RFC 7950, DOI 10.17487/RFC7950, August 2016,
<https://www.rfc-editor.org/info/rfc7950>.
[RFC7951] Lhotka, L., "JSON Encoding of Data Modeled with YANG",
RFC 7951, DOI 10.17487/RFC7951, August 2016,
<https://www.rfc-editor.org/info/rfc7951>.
[RFC8040] Bierman, A., Bjorklund, M., and K. Watsen, "RESTCONF
Protocol", RFC 8040, DOI 10.17487/RFC8040, January 2017,
<https://www.rfc-editor.org/info/rfc8040>.
[RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in
RFC 2119 Key Words", BCP 14, RFC 8174,
DOI 10.17487/RFC8174, May 2017,
<https://www.rfc-editor.org/info/rfc8174>.
[RFC8341] Bierman, A. and M. Bjorklund, "Network Configuration
Access Control Model", STD 91, RFC 8341,
DOI 10.17487/RFC8341, March 2018,
<https://www.rfc-editor.org/info/rfc8341>.
[RFC8342] Bjorklund, M., Schoenwaelder, J., Shafer, P., Watsen, K.,
and R. Wilton, "Network Management Datastore Architecture
(NMDA)", RFC 8342, DOI 10.17487/RFC8342, March 2018,
<https://www.rfc-editor.org/info/rfc8342>.
[RFC8343] Bjorklund, M., "A YANG Data Model for Interface
Management", RFC 8343, DOI 10.17487/RFC8343, March 2018,
<https://www.rfc-editor.org/info/rfc8343>.
[RFC8529] Berger, L., Hopps, C., Lindem, A., Bogdanovic, D., and X.
Liu, "YANG Data Model for Network Instances", RFC 8529,
DOI 10.17487/RFC8529, March 2019,
<https://www.rfc-editor.org/info/rfc8529>.
[W3C.REC-xml-20081126]
Bray, T., Paoli, J., Sperberg-McQueen, M., Maler, E., and
F. Yergeau, "Extensible Markup Language (XML) 1.0 (Fifth
Edition)", World Wide Web Consortium Recommendation
REC-xml-20081126, November 2008,
<https://www.w3.org/TR/2008/REC-xml-20081126>.
[XPATH] Clark, J. and S. DeRose, "XML Path Language (XPath)
Version 1.0", November 1999,
<https://www.w3.org/TR/1999/REC-xpath-19991116>.
9.2. Informative References ๐ง
these ones are the extra-credit reading, good to know but not the core stuff โจ
[RESTCONF-Notif]
Voit, E., Rahman, R., Nilsen-Nygaard, E., Clemm, A.,
and A. Bierman, "Dynamic subscription to YANG Events
and Datastores over RESTCONF", Work in Progress,
draft-ietf-netconf-restconf-notif-15, June 2019.
[RFC7049] Bormann, C. and P. Hoffman, "Concise Binary Object
Representation (CBOR)", RFC 7049, DOI 10.17487/RFC7049,
October 2013, <https://www.rfc-editor.org/info/rfc7049>.
[RFC7540] Belshe, M., Peon, R., and M. Thomson, Ed., "Hypertext
Transfer Protocol Version 2 (HTTP/2)", RFC 7540,
DOI 10.17487/RFC7540, May 2015,
<https://www.rfc-editor.org/info/rfc7540>.
[RFC7923] Voit, E., Clemm, A., and A. Gonzalez Prieto, "Requirements
for Subscription to YANG Datastores", RFC 7923,
DOI 10.17487/RFC7923, June 2016,
<https://www.rfc-editor.org/info/rfc7923>.
[RFC8071] Watsen, K., "NETCONF Call Home and RESTCONF Call Home",
RFC 8071, DOI 10.17487/RFC8071, February 2017,
<https://www.rfc-editor.org/info/rfc8071>.
[RFC8259] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data
Interchange Format", STD 90, RFC 8259,
DOI 10.17487/RFC8259, December 2017,
<https://www.rfc-editor.org/info/rfc8259>.
[RFC8340] Bjorklund, M. and L. Berger, Ed., "YANG Tree Diagrams",
BCP 215, RFC 8340, DOI 10.17487/RFC8340, March 2018,
<https://www.rfc-editor.org/info/rfc8340>.
[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, September 2019,
<https://www.rfc-editor.org/info/rfc8640>.
[RFC8641] Clemm, A. and E. Voit, "Subscription to YANG Notifications
for Datastore Updates", RFC 8641, DOI 10.17487/RFC8641,
September 2019, <https://www.rfc-editor.org/info/rfc8641>.
Appendix A. Example Configured Transport Augmentation โจ
okay this appendix is a non-normative example, so it's more of a vibe check than a rule ๐ฆ it shows how the YANG module from Section 4 could be glowed up with the config parameters needed for the transport connection process. it's not a complete transport model, bestie ๐ the star here is an imaginary transport type called "foo". if you want the big-picture goals behind configuring transport connectivity for a configured subscription, check out Section 2.5.7.
the example module in this appendix has two main pieces ๐. first, there's a transport identity called "foo", which lets a configuration agent pick "foo" as the transport for a subscription. second, there's a YANG case augmentation also called "foo", plugged into the "/subscriptions/subscription/receivers/receiver" node from Section 4. inside it live the transport parameters "address" and "port", which are needed to actually connect to the receiver ๐ฅ
module example-foo-subscribed-notifications {
yang-version 1.1;
namespace
"urn:example:foo-subscribed-notifications";
prefix fsn;
import ietf-subscribed-notifications {
prefix sn;
}
import ietf-inet-types {
prefix inet;
}
description
"Defines 'foo' as a supported type of configured transport for
subscribed event notifications.";
identity foo {
base sn:transport;
description
"Transport type 'foo' is available for use as a configured
subscription's transport protocol for subscribed
notifications.";
}
augment
"/sn:subscriptions/sn:subscription/sn:receivers/sn:receiver" {
when 'derived-from(../../../transport, "fsn:foo")';
description
"This augmentation makes transport parameters specific to 'foo'
available for a receiver.";
leaf address {
type inet:host;
mandatory true;
description
"Specifies the address to use for messages destined for a
receiver.";
}
leaf port {
type inet:port-number;
mandatory true;
description
"Specifies the port number to use for messages destined for a
receiver.";
}
}
}
Figure 21: Example Transport Augmentation
for the Fictitious Protocol "foo"
this "foo" module is never gonna show up in a real-world deployment ๐ but if you're deploying an actual transport technology for real, you'll need a similar YANG module. it must be defined ๐ซถ
Acknowledgments ๐
huge thank yous to everyone who dropped valuable comments, discussions, and feedback ๐ธ this includes Andy Bierman, Tim Jenkins, Martin Bjorklund, Kent Watsen, Balazs Lengyel, Robert Wilton, Sharon Chisholm, Hector Trevino, Susan Hares, Michael Scharf, and Guangying Zheng. literal legends ๐
Authors' Addresses ๐ฆ
Eric Voit
Cisco Systems
Email: evoit@cisco.com
Alexander Clemm
Futurewei
Email: ludwig@clemm.org
Alberto Gonzalez Prieto
Microsoft
Email: alberto.gonzalez@microsoft.com
Einar Nilsen-Nygaard
Cisco Systems
Email: einarnn@cisco.com
Ambika Prasad Tripathy
Cisco Systems
Email: ambtripa@cisco.com
๐ฆ where this page comes from
- ietf: rfc8639 2019-09
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms