RFC 9835

A Network YANG Data Model for Attachment Circuits

📅 published September 2025, from ietf

RFC 9835: A Network YANG Data Model for Attachment Circuits 🎀

okay bestie, this is RFC 9835 and it's giving network model for attachment circuits 💅

Authors: M. Boucadair (Ed.) from Orange 🍊, R. Roberts from Juniper 🌸, O. Gonzalez de Dios from Telefonica 🦋, S. Barguil from Nokia 💜, and B. Wu from Huawei Technologies 🌈

Category: Standards Track ⭐ (it's an Internet Standards Track doc, so it's official-official)

Date: September 2025 📅

ISSN: 2070-1721

Obsoletes / Updates: the title block doesn't list anything it obsoletes or updates 🙈


Abstract ✨

okay so this doc specifies a network model for attachment circuits (ACs) 🔌. The model can be used for provisioning ACs prior to or during service provisioning, like for VPN or the RFC 9543 Network Slice Service 🍓. The companion service model is "YANG Data Models for Bearers and Attachment Circuits as a Service (ACaaS)" (RFC9834) 🫶.

The module augments the base network ('ietf-network') and the Service Attachment Point (SAP) models with the detailed info for provisioning ACs in Provider Edges (PEs) 🧚.


Status of This Memo 📝

This is an Internet Standards Track document.

This document is a product of the Internet Engineering Task Force (IETF). It represents the consensus of the IETF community. It has received public review and has been approved for publication by the Internet Engineering Steering Group (IESG). Further information on Internet Standards is available in Section 2 of RFC 7841 ✅.

Information about the current status of this document, any errata, and how to provide feedback on it may be obtained at https://www.rfc-editor.org/info/rfc9835 🔍.


Copyright (c) 2025 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) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License 📜.


Table of Contents 🗺️

1.  Introduction
2.  Conventions and Definitions
3.  Relationship to Other AC Data Models
4.  Sample Uses of the Attachment Circuit Data Models
  4.1.  ACs Terminated by One or Multiple CEs
  4.2.  Positioning the AC Network Model in the Overall Service
        Delivery Process
5.  Description of the Attachment Circuit YANG Module
  5.1.  Overall Structure of the Module
  5.2.  References
  5.3.  Provisioning Profiles
  5.4.  L2 Connection
  5.5.  IP Connection
  5.6.  Routing
    5.6.1.  Static Routing
    5.6.2.  BGP
    5.6.3.  OSPF
    5.6.4.  IS-IS
    5.6.5.  RIP
    5.6.6.  VRRP
  5.7.  OAM
  5.8.  Security
  5.9.  Service
6.  YANG Module
7.  Security Considerations
8.  IANA Considerations
9.  References
  9.1.  Normative References
  9.2.  Informative References
Appendix A.  Examples
  A.1.  VPLS
  A.2.  Parent AC
Appendix B.  Full Tree
Acknowledgments
Contributors
Authors' Addresses

1. Introduction 🦋

okay so connectivity services are provided by networks to customers through dedicated terminating points 🌐. Think Service Functions [RFC7665], Customer Edges (CEs), peer Autonomous System Border Routers (ASBRs), data center gateways, or Internet Exchange Points. Lots of places to plug in! 🔌

The way a service gets provisioned in a service provider network can depend on each provider's practices 💼. That includes the flow they set up for provisioning advanced network services and how those services are bound to an attachment circuit (AC). For example, the same AC might host multiple services, like a Layer 2 VPN (L2VPN), a Layer 3 VPN (L3VPN), or the RFC 9543 Network Slice Service [RFC9543]. 😭 To avoid service interference and redundant info all over the place, a service provider may expose an interface to manage ACs network-wide 🌸. Customers can then request a standalone AC and refer to it when they ask for services to be bound to it ✨. [RFC9834] specifies a data model for managing Attachment Circuits as a Service (ACaaS) 💅.

Section 6 specifies a network model for ACs ("ietf-ac-ntw") 🧚. The model can be used to provision ACs in a provider network prior to or during service provisioning. For example, [RFC9836] specifies augmentations to the L2VPN Network Model (L2NM) [RFC9291] and the L3VPN Network Model (L3NM) [RFC9182] to bind LxVPNs to ACs that are provisioned using the procedure defined in this document 🎀.

This document leverages [RFC9182] and [RFC9291] by adopting an AC provisioning structure that uses data nodes defined in those RFCs 🫶. Some refinements were added to cover not only conventional service provider networks but also the specifics of other target deployments, like cloud networks ☁️.

The AC network model is designed as augmentations of both the 'ietf-network' model [RFC8345] and the Service Attachment Point (SAP) model [RFC9408] 💜. An AC can be bound to a single SAP or to multiple SAPs. Likewise, the model accommodates deployments where a SAP can be bound to one or multiple ACs (for example, a Parent AC and its Child ACs) 🌈.

Here's the picture of all that (Figure 1) 👀:

                  .--.
                 |CE6|
                 '-+'
                ac |          .--.              .--.
                   |         |CE5+------+------+CE2|
             .-----+-----.   '--'       |      '--'
             |           |              |ac
             |           |              |
            .+.         .+.            .+.
         .-+sap+-------+sap+-.      .-+sap+-------------.
         |  '-'         '-'  |      |  '-'              |
         |        PE1        |      |        PE2        |
 .--.   .+.                  |      |                   |
|CE1+--+sap|                 |      |                   |
'--' ac '+'                  |      |                   |
         '-------------------'      '-------------------'

         .-------------------.      .-------------------.
         |                   |      |                  .+. ac .--.
         |         PE3       |      |        PE4      |sap+--+CE7|
         |                   |      |                  '-'   '--'
         |                   |      |                   |
         |              .-.  |      |  .-.   .-.   .-.  |
         '-------------+sap+-'      '-+sap+-+sap+-+sap+-'
                        '+'            '+'   '+'   '+'
                         |ac            |     |ac   |ac
                        .+-.            |    .+-.   |
                       |CE3+-----ac-----'   |CE4+---'
                       '--'                 '--'

Figure 1: Attachment Circuits Examples 🖼️

The AC network model uses the AC common model defined in [RFC9833] 🧩.

The YANG 1.1 [RFC7950] data model in this document conforms to the Network Management Datastore Architecture (NMDA) defined in [RFC8342] 🗂️.

Some examples are provided in Appendix A 💖.

2. Conventions and Definitions ✨

Okay bestie, the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" only mean what BCP 14 [RFC2119] [RFC8174] says they mean when they show up in all capitals, just like here 💅

You should already know the terms defined in Section 2 of [RFC9408] 🧠

This doc uses "network model" the way it's defined in Section 2.1 of [RFC8969] 🌸

The YANG tree diagram symbols have their meanings defined in [RFC8340] 🦋

LxSM is the umbrella term for both the L2VPN Service Model (L2SM) [RFC8466] and the L3VPN Service Model (L3SM) [RFC8299] 💜

LxNM is the umbrella term for both the L2VPN Network Model (L2NM) [RFC9291] and the L3VPN Network Model (L3NM) [RFC9182] 🎀

LxVPN just means L2VPN and L3VPN together 🍓

These are the prefixes used in the module names:

  • ac: Attachment circuit
  • ntw: Network
  • sap: Service Attachment Point
  • svc: Service

Here are the extra terms this doc uses too, so get ready, it's a lot but it's giving clarity ✨

Bearer: A physical or logical link that connects a customer node (or site) to a provider network.

A bearer can be a wireless or wired link. One or multiple technologies can be used to build a bearer. The bearer type can be specified by a customer.

The operator allocates a unique bearer reference to identify a bearer within its network (e.g., customer line identifier). Such a reference can be retrieved by a customer and then used in subsequent service placement requests to unambiguously identify where a service is to be bound.

The concept of a bearer can be generalized to refer to the required underlying connection for the provisioning of an AC.

One or multiple ACs may be hosted over the same bearer (e.g., multiple Virtual Local Area Networks (VLANs) on the same bearer that is provided by a physical link).

Network controller: Denotes a functional entity responsible for the management of the service provider network. One or multiple network controllers can be deployed in a service provider network.

Service orchestrator: Refers to a functional entity that interacts with the customer of a network service.

A service orchestrator is typically responsible for the ACs, the Provider Edge (PE) selection, and requesting the activation of the requested services to a network controller.

A service orchestrator may interact with one or more network controllers.

Service provider network: A network that is able to provide network services (e.g., LxVPN or RFC 9543 Network Slice Services).

Service provider: An entity that offers network services (e.g., LxVPN or RFC 9543 Network Slice Services).

The names of data nodes are prefixed using the prefix associated with the corresponding imported YANG module, as shown in Table 1 🌈

+=============+=====================+==========================+
| Prefix      | Module              | Reference                |
+=============+=====================+==========================+
| ac-common   | ietf-ac-common      | [RFC9833]                |
+-------------+---------------------+--------------------------+
| ac-svc      | ietf-ac-svc         | Section 6.2 of [RFC9834] |
+-------------+---------------------+--------------------------+
| dot1q-types | ieee802-dot1q-types | [IEEE802.1Qcp]           |
+-------------+---------------------+--------------------------+
| if          | ietf-interfaces     | [RFC8343]                |
+-------------+---------------------+--------------------------+
| inet        | ietf-inet-types     | Section 4 of [RFC6991]   |
+-------------+---------------------+--------------------------+
| key-chain   | ietf-key-chain      | [RFC8177]                |
+-------------+---------------------+--------------------------+
| nacm        | ietf-netconf-acm    | [RFC8341]                |
+-------------+---------------------+--------------------------+
| nw          | ietf-network        | [RFC8345]                |
+-------------+---------------------+--------------------------+
| rt-types    | ietf-routing-types  | [RFC8294]                |
+-------------+---------------------+--------------------------+
| rt-pol      | ietf-routing-policy | [RFC9067]                |
+-------------+---------------------+--------------------------+
| sap         | ietf-sap-ntw        | [RFC9408]                |
+-------------+---------------------+--------------------------+
| vpn-common  | ietf-vpn-common     | [RFC9181]                |
+-------------+---------------------+--------------------------+

         Table 1: Modules and Their Associated Prefixes

3. Relationship to Other AC Data Models 🦋

Figure 2 shows how all the AC data models are related to each other 👀

  • "ietf-ac-common" [RFC9833]
  • "ietf-bearer-svc" (Section 6.1 of [RFC9834])
  • "ietf-ac-svc" (Section 6.2 of [RFC9834])
  • "ietf-ac-ntw" (Section 6)
  • "ietf-ac-glue" [RFC9836]
                           ietf-ac-common
                            ^     ^     ^
                            |     |     |
                 .----------'     |     '----------.
                 |                |                |
                 |                |                |
           ietf-ac-svc <--- ietf-bearer-svc        |
              ^    ^                               |
              |    |                               |
              |    '------------------------ ietf-ac-ntw
              |                                    ^
              |                                    |
              |                                    |
              '------------ ietf-ac-glue ----------'

           X --> Y: X imports Y

                      Figure 2: AC Data Models

The "ietf-ac-common" module is imported by the "ietf-bearer-svc", "ietf-ac-svc", and "ietf-ac-ntw" modules 🫶 Bearers managed using the "ietf-bearer-svc" module may be referenced by service ACs managed using the "ietf-ac-svc" module. Similarly, a bearer managed using the "ietf-bearer-svc" module may list the set of ACs that use that bearer.

To make it easy to match an AC service request with the actual AC that gets provisioned in the network, "ietf-ac-ntw" leverages the AC references exposed by the "ietf-ac-svc" module. Furthermore, to bind L2VPN or L3VPN services with ACs, the "ietf-ac-glue" module augments the LxSM and LxNM with AC service references exposed by the "ietf-ac-svc" module and AC network references exposed by the "ietf-ac-ntw" module 🔥


4. Sample Uses of the Attachment Circuit Data Models 💖

4.1. ACs Terminated by One or Multiple CEs 🌸

Figure 3 shows a sample target topology that involves ACs 🧚

  • ACs are terminated by a SAP at the network side. See Figure 1 for an example of SAPs within a PE.
  • A CE can be either a physical device or a logical entity. Such a logical entity is typically a software component (e.g., a virtual Service Function that is hosted within the provider's network or a third-party infrastructure). A CE is seen by the network as a peer SAP [RFC9408].
  • CEs may be either dedicated to one single connectivity service or host multiple connectivity services (e.g., CEs with roles of Service Functions [RFC7665]).
  • A network provider may bind a single AC to one or multiple peer SAPs (e.g., CE1 and CE2 are tagged as peer SAPs for the same AC). For example, and as discussed in [RFC4364], multiple CEs can be attached to a PE over the same AC. This scenario is typically implemented when the Layer 2 infrastructure between the CE and the network is a multipoint service.
  • A single CE may terminate multiple ACs, which can be associated with the same bearer or distinct bearers (e.g., CE4).
  • Customers may request protection schemes in which the ACs associated with their endpoints are terminated by the same PE (e.g., CE3), distinct PEs (e.g., CE4), etc. The network provider uses this request to decide where to terminate the AC in the service provider network and also whether to enable specific capabilities (e.g., Virtual Router Redundancy Protocol (VRRP)).

"ietf-ac-ntw" is a network model that is used to manage the PE side of ACs at a provider network 🎀

                     .--------------------.
                     |                    |
   .------.          |                   .--.  (b1)   .-----.
  |       +----.     |                   |  +---AC---+      |
  |  CE1  |    |     |                   |PE+---AC---+  CE3 |
  '------'     |   .--.                  '--'  (b2)  '-----'
               +---AC--+PE|     Network       |
   .------.    |   '--'                  .--.  (b3)   .-----.
  |       |    |     |                   |  +---AC---+      |
  |  CE2  +----'     |                   |PE+---AC---+  CE4 |
  '------'           |                   '--'  (b3)  '---+-'
                     |      .--.          |              |
                     '-----+PE+------'              |
                            '--'                     |
                             |                       |
                             '-----------AC----------'
  (bx) = bearer Id x

Figure 3: Examples of ACs

4.2. Positioning the AC Network Model in the Overall Service Delivery Process ✨

Okay so, Figure 4 shows where the AC network model fits in the whole service delivery process 🗺️ The "ietf-ac-ntw" module is a network model that augments the SAP with a big, detailed set of parameters to reflect the ACs that are in place in a network 💅 It also keeps the mapping to the service references used to expose those ACs to customers, which are handled by the "ietf-ac-svc" module defined in [RFC9834] 🎀 Whether the same naming conventions to reference an AC are used in the service and network layers is deployment-specific, so it depends on each deployment 🦋

                                 .-------------.
                                |   Customer    |
                                 '------+------'
                Customer Service Models |
        ietf-l2vpn-svc, ietf-l3vpn-svc, | ietf-network-slice-service,
             ietf-ac-svc, ietf-ac-glue, | and ietf-bearer-svc
                                 .------+------.
                                |    Service    |
                                | Orchestration |
                                 '------+------'
                 Network Models         |
        ietf-l2vpn-ntw, ietf-l3vpn-ntw, | ietf-sap-ntw, ietf-ac-glue,
                 and ietf-ac-ntw        |
                                 .------+------.
                                |   Network     |
                                | Orchestration |
                                 '------+------'
          Network Configuration Model   |
                            .-----------+-----------.
                            |                       |
                    .-------+-----.         .-------+-----.
                   |    Domain     |       |     Domain    |
                   | Orchestration |       | Orchestration |
                    '--+--------+-'         '-------+-----'
        Device         |        |                   |
        Configuration  |        |                   |
        Models         |        |                   |
                   .---+---.    |                   |
                  | Config  |   |                   |
                  | Manager |   |                   |
                   '---+---'    |                   |
                       |        |                   |
                    NETCONF/CLI.......................
                       |        |                   |
                     .--------------------------------.
        .---. Bearer |                                | Bearer  .---.
       | CE1+--------+            Network             +--------+ CE2|
       '---'         |                                |        '---'
                     '--------------------------------'
        Site A                                                  Site B

Figure 4: An Example of the Network AC Model Usage

Similar to [RFC9408], the "ietf-ac-ntw" module can be used for both User-to-Network Interface (UNI) and Network-to-Network Interface (NNI) 🌈 For example, all the ACs shown in Figure 5 have a 'role' set to 'ietf-sap-ntw:nni'. Typically, ASBRs of each network are directly connected to ASBRs of a neighboring network via one or multiple links (bearers) 🔗 ASBRs of "Network#1" behave as a PE and treat the other adjacent ASBRs as if it were a CE 🤯

             .--------------------.         .-------------.
             |                    +---AC----+             |
             |                    |         |             |
             |                    +---AC----+  Network#2  |
             |                    |         |             |
             |     Network#1      |         '-------------'
             |                    |
             |                    |         .-------------.
             |                    |         |             |
             |                    |         |             |
             |                    +---AC----+  Network#3  |
             |                    |         |             |
             '--------------------'         '-------------'

Figure 5: An Example of the Network AC Model Usage Between Provider Networks


5. Description of the Attachment Circuit YANG Module 📚

The full tree diagram of the "ietf-ac-ntw" module is provided in Appendix B 🎀 Subtrees are provided in the following subsections for the reader's convenience 🫶

5.1. Overall Structure of the Module

The overall tree structure of the "ietf-ac-ntw" module is shown in Figure 6 👀

  augment /nw:networks/nw:network:
    +--rw specific-provisioning-profiles
    |  ...
    +--rw ac-profile* [name]
       ...
  augment /nw:networks/nw:network/nw:node:
    +--rw ac* [name]
       +--rw name                 string
       +--rw svc-ref?             ac-svc:attachment-circuit-reference
       +--rw profile* [ac-profile-ref]
       |  +--rw ac-profile-ref    leafref
       |  +--rw network-ref?      -> /nw:networks/network/network-id
       +--rw parent-ref
       |  +--rw ac-ref?        leafref
       |  +--rw node-ref?      leafref
       |  +--rw network-ref?   -> /nw:networks/network/network-id
       +--ro child-ref
       |  +--ro ac-ref*        leafref
       |  +--ro node-ref?      leafref
       |  +--ro network-ref?   -> /nw:networks/network/network-id
       +--rw peer-sap-id*         string
       +--rw group* [group-id]
       |  +--rw group-id      string
       |  +--rw precedence?   identityref
       +--rw status
       |  +--rw admin-status
       |  |  +--rw status?        identityref
       |  |  +--ro last-change?   yang:date-and-time
       |  +--ro oper-status
       |     +--ro status?        identityref
       |     +--ro last-change?   yang:date-and-time
       +--rw description?         string
       +--rw l2-connection  {ac-common:layer2-ac}?
       |  ...
       +--rw ip-connection  {ac-common:layer3-ac}?
       |  ...
       +--rw routing-protocols
       |  ...
       +--rw oam
       |  ...
       +--rw security
       |  ...
       +--rw service
          ...
  augment /nw:networks/nw:network/nw:node/sap:service/sap:sap:
    +--rw ac* [ac-ref]
       +--rw ac-ref         leafref
       +--rw node-ref?      leafref
       +--rw network-ref?   -> /nw:networks/network/network-id

Figure 6: Overall Tree Structure

A node can host one or more SAPs. Per [RFC9408], a SAP is an abstraction of the network reference point (the PE side of an AC, in the context of this document) where network services can be and/or are delivered to customers 🏢 Each SAP terminates one or multiple ACs. In turn, each AC may be terminated by one or more peer SAPs ('peer-sap') 🧩 In order to expose such AC/SAP binding information, the SAP model [RFC9408] is augmented with the required AC-related information 💖

Unlike the AC service model [RFC9834], an AC is uniquely identified by a name within the scope of a node, not a network 🙈 A textual description of the AC may be provided ('description') 📝

Also, in order to ease the correlation between the AC exposed at the service layer and the AC that is actually provisioned in the network operation, a reference to the AC exposed to the customer ('svc-ref') is stored in the "ietf-ac-ntw" module 🔍

ACs that are terminated by a SAP are listed in the 'ac' container under '/nw:networks/nw:network/nw:node/sap:service/sap:sap'. A controller may indicate a filter based on the service type (e.g., Network Slice or L3VPN) to retrieve the list of available SAPs, and thus ACs, for that service 🎯

In order to factorize common data that is provisioned for a group of ACs, a set of profiles (Section 5.3) can be defined at the network level and then called under the node level 🍓 The information contained in a profile is thus inherited, unless the corresponding data node is refined at the AC level. In such a case, the value provided at the AC level takes precedence over the global one 👑

In contexts where the same AC is terminated by multiple peer SAPs (e.g., an AC with multiple CEs) but a subset of them have specific information, the module allows operators to:

  • Define a Parent AC that may list all these CEs as peer SAPs.
  • Create individual ACs that are bound to the Parent AC using 'parent-ref'.
  • Indicate for each individual AC one or a subset of the CEs as peer SAPs. All these individual ACs will inherit the properties of the Parent AC.
Whenever a Parent AC is deleted, then all Child ACs of that AC MUST be deleted. Child ACs are referenced using 'child-ref'. 💀

An AC may belong to one or multiple groups [RFC9181]. For example, the 'group-id' is used to associate redundancy or protection constraints with ACs 🛡️

The status of an AC can be tracked using 'status'. Both operational status and administrative status are maintained. A mismatch between the administrative status vs. the operational status can be used as a trigger to detect anomalies 🚨

An AC can be characterized using Layer 2 connectivity (Section 5.4), Layer 3 connectivity (Section 5.5), routing protocols (Section 5.6), Operations, Administration, and Maintenance (OAM) (Section 5.7), security (Section 5.8), and service (Section 5.9) considerations. Features are used to tag conditional portions to accommodate various deployments (support of Layer 2 ACs, Layer 3 ACs, IPv4, IPv6, routing protocols, Bidirectional Forwarding Detection (BFD), etc.) ✨

5.2. References

The AC network module defines a set of groupings depicted in Figure 7 for referencing purposes 🦋 These references are used within or outside the AC network module. The use of such groupings is consistent with the design in [RFC8345] 🌸

  grouping attachment-circuit-reference:
    +-- ac-ref?        leafref
    +-- node-ref?      leafref
    +-- network-ref?   -> /nw:networks/network/network-id
  grouping attachment-circuit-references:
    +-- ac-ref*        leafref
    +-- node-ref?      leafref
    +-- network-ref?   -> /nw:networks/network/network-id
  grouping ac-profile-reference:
    +-- ac-profile-ref?   leafref
    +-- network-ref?      -> /nw:networks/network/network-id
  grouping encryption-profile-reference:
    +-- encryption-profile-ref?   leafref
    +-- network-ref?              -> /nw:networks/network/network-id
  grouping qos-profile-reference:
    +-- qos-profile-ref?   leafref
    +-- network-ref?       -> /nw:networks/network/network-id
  grouping failure-detection-profile-reference:
    +-- failure-detection-profile-ref?   leafref
    +-- network-ref?       -> /nw:networks/network/network-id
  grouping forwarding-profile-reference:
    +-- forwarding-profile-ref?   leafref
    +-- network-ref?              -> /nw:networks/network/network-id
  grouping routing-profile-reference:
    +-- routing-profile-ref?   leafref
    +-- network-ref?           -> /nw:networks/network/network-id

Figure 7: References Groupings

The groupings shown in Figure 7 contain the information necessary to reference:

  • an AC that is terminated by a specific node in a given network,
  • an AC profile of a specific network (Section 5.3), and
  • specific provisioning profiles that are bound to a specific network (Section 5.3).

5.3. Provisioning Profiles 🎀

Okay so the profiles tree is shown in Figure 8, and it's giving organized 🗂️

  augment /nw:networks/nw:network:
    +--rw specific-provisioning-profiles
    |  +--rw valid-provider-identifiers
    |     +--rw encryption-profile-identifier* [id]
    |     |  +--rw id    string
    |     +--rw qos-profile-identifier* [id]
    |     |  +--rw id    string
    |     +--rw failure-detection-profile-identifier* [id]
    |     |  +--rw id    string
    |     +--rw forwarding-profile-identifier* [id]
    |     |  +--rw id    string
    |     +--rw routing-profile-identifier* [id]
    |        +--rw id    string
    +--rw ac-profile* [name]
       +--rw name                 string
       +--rw routing-protocols
       |  +--rw routing-protocol* [id]
       |     +--rw id      string
       |     +--rw type?   identityref
       |     +--rw bgp {vpn-common:rtg-bgp}?
       |     |  +--rw peer-groups
       |     |     +--rw peer-group* [name]
       |     |        +--rw name                      string
       |     |        +--rw description?              string
       |     |        +--rw apply-policy
       |     |        |  +--rw import-policy*           leafref
       |     |        |  +--rw default-import-policy?
       |     |        |  |       default-policy-type
       |     |        |  +--rw export-policy*           leafref
       |     |        |  +--rw default-export-policy?
       |     |        |          default-policy-type
       |     |        +--rw local-as?                 inet:as-number
       |     |        +--rw peer-as                   inet:as-number
       |     |        +--rw address-family?           identityref
       |     |        +--rw role?                     identityref
       |     |        +--rw multihop?                 uint8
       |     |        +--rw as-override?              boolean
       |     |        +--rw allow-own-as?             uint8
       |     |        +--rw prepend-global-as?        boolean
       |     |        +--rw send-default-route?       boolean
       |     |        +--rw site-of-origin?
       |     |        |       rt-types:route-origin
       |     |        +--rw ipv6-site-of-origin?
       |     |        |       rt-types:ipv6-route-origin
       |     |        +--rw redistribute-connected* [address-family]
       |     |        |  +--rw address-family    identityref
       |     |        |  +--rw enabled?          boolean
       |     |        +--rw bgp-max-prefix
       |     |        |  +--rw max-prefix?          uint32
       |     |        |  +--rw warning-threshold?   decimal64
       |     |        |  +--rw violate-action?      enumeration
       |     |        |  +--rw restart-timer?       uint32
       |     |        +--rw bgp-timers
       |     |           +--rw keepalive?   uint16
       |     |           +--rw hold-time?   uint16
       |     +--rw ospf {vpn-common:rtg-ospf}?
       |     |  +--rw address-family?   identityref
       |     |  +--rw area-id           yang:dotted-quad
       |     |  +--rw metric?           uint16
       |     |  +--rw max-lsa?          uint32
       |     |  +--rw passive?          boolean
       |     +--rw isis {vpn-common:rtg-isis}?
       |     |  +--rw address-family?   identityref
       |     |  +--rw area-address      area-address
       |     |  +--rw level?            identityref
       |     |  +--rw metric?           uint32
       |     |  +--rw passive?          boolean
       |     +--rw rip {vpn-common:rtg-rip}?
       |     |  +--rw address-family?   identityref
       |     |  +--rw timers
       |     |  |  +--rw update-interval?     uint16
       |     |  |  +--rw invalid-interval?    uint16
       |     |  |  +--rw holddown-interval?   uint16
       |     |  |  +--rw flush-interval?      uint16
       |     |  +--rw default-metric?   uint8
       |     +--rw vrrp {vpn-common:rtg-vrrp}?
       |        +--rw address-family?   identityref
       |        +--rw ping-reply?       boolean
       +--rw oam
          +--rw bfd {vpn-common:bfd}?
             +--rw session-type?               identityref
             +--rw desired-min-tx-interval?    uint32
             +--rw required-min-rx-interval?   uint32
             +--rw local-multiplier?           uint8
             +--rw holdtime?                   uint32

                  Figure 8: Profiles Tree Structure

Okay so the exact definition of the specific provisioning profiles is local to each service provider, same energy as [RFC9182] and [RFC9291] 🫶 The model only includes an identifier for these profiles, which makes it easier to spot them and bind local policies when you're building an AC ✨ As Figure 8 shows, these identifiers can be included:

  • encryption-profile-identifier: an encryption profile refers to a set of policies related to the encryption schemes and setup that can be applied on the AC 🔐 See also Section 5.8.
  • qos-profile-identifier: a Quality of Service (QoS) profile refers to a set of policies such as classification, marking, and actions (e.g., [RFC3644]) 💅 See also Section 5.9.
  • failure-detection-profile-identifier: a failure detection profile refers to a set of failure detection policies such as Bidirectional Forwarding Detection (BFD) policies [RFC5880] that can be invoked when building an AC 🚨 Such a profile can be, for example, referenced in static routes (Section 5.6.1) or under the OAM level (Section 5.7). The use of this profile is similar to the detailed examples depicted in Appendices A.11.3 and A.12 of [RFC9834].
  • forwarding-profile-identifier: a forwarding profile refers to the policies that apply to the forwarding of packets conveyed over an AC 🚦 Such policies may consist of, for example, applying Access Control Lists (ACLs) as in Section 5.9.
  • routing-profile-identifier: a routing profile refers to a set of routing policies that will be invoked (e.g., BGP policies) for an AC 🧭 Refer to Section 5.6.

The ac-profile is the main character here 👑 It defines parameters that can be factorized among a set of ACs, so you don't have to repeat yourself. Each profile is identified by a name that is unique in a network. Some of the data nodes can be adjusted at the node level, and those adjusted values take precedence over the values in the profile, so the node-level value wins ✨


5.4. L2 Connection 🦋

The l2-connection container is used to manage the Layer 2 properties of an AC (mainly, the PE side of an AC) 🌸 The Layer 2 connection tree structure is shown in Figure 9.

  augment /nw:networks/nw:network/nw:node:
    +--rw ac* [name]
       +--rw name                 string
       + ...
       +--rw l2-connection  {ac-common:layer2-ac}?
       |  +--rw encapsulation
       |  |  +--rw encap-type?        identityref
       |  |  +--rw dot1q
       |  |  |  +--rw tag-type?         identityref
       |  |  |  +--rw cvlan-id?         uint16
       |  |  |  +--rw tag-operations
       |  |  |     +--rw (op-choice)?
       |  |  |     |  +--:(pop)
       |  |  |     |  |  +--rw pop?         empty
       |  |  |     |  +--:(push)
       |  |  |     |  |  +--rw push?        empty
       |  |  |     |  +--:(translate)
       |  |  |     |     +--rw translate?   empty
       |  |  |     +--rw tag-1?             dot1q-types:vlanid
       |  |  |     +--rw tag-1-type?
       |  |  |     |       dot1q-types:dot1q-tag-type
       |  |  |     +--rw tag-2?             dot1q-types:vlanid
       |  |  |     +--rw tag-2-type?
       |  |  |             dot1q-types:dot1q-tag-type
       |  |  +--rw priority-tagged
       |  |  |  +--rw tag-type?   identityref
       |  |  +--rw qinq
       |  |     +--rw tag-type?         identityref
       |  |     +--rw svlan-id?         uint16
       |  |     +--rw cvlan-id?         uint16
       |  |     +--rw tag-operations
       |  |        +--rw (op-choice)?
       |  |        |  +--:(pop)
       |  |        |  |  +--rw pop?         uint8
       |  |        |  +--:(push)
       |  |        |  |  +--rw push?        empty
       |  |        |  +--:(translate)
       |  |        |     +--rw translate?   uint8
       |  |        +--rw tag-1?             dot1q-types:vlanid
       |  |        +--rw tag-1-type?
       |  |        |       dot1q-types:dot1q-tag-type
       |  |        +--rw tag-2?             dot1q-types:vlanid
       |  |        +--rw tag-2-type?
       |  |                dot1q-types:dot1q-tag-type
       |  +--rw (l2-service)?
       |  |  +--:(l2-tunnel-service)
       |  |  |  +--rw l2-tunnel-service
       |  |  |     +--rw type?         identityref
       |  |  |     +--rw pseudowire
       |  |  |     |  +--rw vcid?      uint32
       |  |  |     |  +--rw far-end?   union
       |  |  |     +--rw vpls
       |  |  |     |  +--rw vcid?      uint32
       |  |  |     |  +--rw far-end*   union
       |  |  |     +--rw vxlan
       |  |  |        +--rw vni-id?            uint32
       |  |  |        +--rw peer-mode?         identityref
       |  |  |        +--rw peer-ip-address*   inet:ip-address
       |  |  +--:(l2vpn)
       |  |     +--rw l2vpn-id?            vpn-common:vpn-id
       |  +--rw l2-termination-point?      string
       |  +--rw local-bridge-reference?    string
       |  +--rw bearer-reference?          string
       |  |       {ac-common:server-assigned-reference}?
       |  +--rw lag-interface {vpn-common:lag-interface}?
       |     +--rw lag-interface-id?   string
       |     +--rw member-link-list
       |        +--rw member-link* [name]
       |           +--rw name    string
       +--rw ip-connection  {ac-common:layer3-ac}?
       |  ...
       +--rw routing-protocols
       |  ...
       +--rw oam
       |  ...
       +--rw security
       |  ...
       +--rw service
          ...

            Figure 9: Layer 2 Connection Tree Structure

Okay so the encapsulation container is where you specify the Layer 2 encapsulation to use (if any), and it lets you configure the relevant tags 🏷️ The model also supports tag manipulation operations, like tag rewrite, which is literally so useful 💖

The l2-tunnel-service container is used to specify the required parameters to set up a Layer 2 tunneling service 🚇 Think a Virtual Private LAN Service (VPLS), a Virtual eXtensible Local Area Network (VXLAN), or a pseudowire (Section 6.1 of [RFC8077]). l2vpn-id is used to identify an L2VPN service that is associated with an Integrated Routing and Bridging (IRB) interface 🧚

Some implementations and deployments may require specific Layer 2 sub-interfaces to be configured 🧩 A Layer-2-specific interface like that can be included in l2-termination-point.

To accommodate implementations that require internal bridging, you can specify a local bridge reference in local-bridge-reference 🌈 Such a reference may be a local bridge domain.

And a reference to the bearer used by this AC is maintained using bearer-reference 🫶

5.5. IP Connection ✨

okay so this ip-connection container is basically the group chat for all things Layer 3 🌸 it holds the IP addressing info for an AC, and it's giving organized 💅

The Layer 3 connection tree looks like this 🦋

     augment /nw:networks/nw:network/nw:node:
       +--rw ac* [name]
          +--rw name                 string
          + ...
          +--rw l2-connection  {ac-common:layer2-ac}?
          |  ...
          +--rw ip-connection  {ac-common:layer3-ac}?
          |  +--rw l3-termination-point?   string
          |  +--rw ipv4 {vpn-common:ipv4}?
          |  |  +--rw local-address?
          |  |  |       inet:ipv4-address
          |  |  +--rw prefix-length?                           uint8
          |  |  +--rw address-allocation-type?
          |  |  |       identityref
          |  |  +--rw (allocation-type)?
          |  |     +--:(dynamic)
          |  |     |  +--rw (address-assign)?
          |  |     |  |  +--:(number)
          |  |     |  |  |  +--rw number-of-dynamic-address?   uint16
          |  |     |  |  +--:(explicit)
          |  |     |  |     +--rw customer-addresses
          |  |     |  |        +--rw address-pool* [pool-id]
          |  |     |  |           +--rw pool-id          string
          |  |     |  |           +--rw start-address
          |  |     |  |           |       inet:ipv4-address
          |  |     |  |           +--rw end-address?
          |  |     |  |                   inet:ipv4-address
          |  |     |  +--rw (provider-dhcp)?
          |  |     |  |  +--:(dhcp-service-type)
          |  |     |  |  |  +--rw dhcp-service-type?
          |  |     |  |  |          enumeration
          |  |     |  |  +--:(service-type)
          |  |     |  |     +--rw (service-type)?
          |  |     |  |        +--:(relay)
          |  |     |  |           +--rw server-ip-address*
          |  |     |  |                   inet:ipv4-address
          |  |     |  +--rw (dhcp-relay)?
          |  |     |     +--:(customer-dhcp-servers)
          |  |     |        +--rw customer-dhcp-servers
          |  |     |           +--rw server-ip-address*
          |  |     |                   inet:ipv4-address
          |  |     +--:(static-addresses)
          |  |        +--rw address* [address-id]
          |  |           +--rw address-id                       string
          |  |           +--rw customer-address?
          |  |           |       inet:ipv4-address
          |  |           +--rw failure-detection-profile-ref?   leafref
          |  |           +--rw network-ref?
          |  |                   -> /nw:networks/network/network-id
          |  +--rw ipv6 {vpn-common:ipv6}?
          |     +--rw local-address?
          |     |       inet:ipv6-address
          |     +--rw prefix-length?                           uint8
          |     +--rw address-allocation-type?
          |     |       identityref
          |     +--rw (allocation-type)?
          |        +--:(dynamic)
          |        |  +--rw (address-assign)?
          |        |  |  +--:(number)
          |        |  |  |  +--rw number-of-dynamic-address?   uint16
          |        |  |  +--:(explicit)
          |        |  |     +--rw customer-addresses
          |        |  |        +--rw address-pool* [pool-id]
          |        |  |           +--rw pool-id          string
          |        |  |           +--rw start-address
          |        |  |           |       inet:ipv6-address
          |        |  |           +--rw end-address?
          |        |  |                   inet:ipv6-address
          |        |  +--rw (provider-dhcp)?
          |        |  |  +--:(dhcp-service-type)
          |        |  |  |  +--rw dhcp-service-type?
          |        |  |  |          enumeration
          |        |  |  +--:(service-type)
          |        |  |     +--rw (service-type)?
          |        |  |        +--:(relay)
          |        |  |           +--rw server-ip-address*
          |        |  |                   inet:ipv6-address
          |        |  +--rw (dhcp-relay)?
          |        |     +--:(customer-dhcp-servers)
          |        |        +--rw customer-dhcp-servers
          |        |           +--rw server-ip-address*
          |        |                   inet:ipv6-address
          |        +--:(static-addresses)
          |           +--rw address* [address-id]
          |              +--rw address-id                       string
          |              +--rw customer-address?
          |              |       inet:ipv6-address
          |              +--rw failure-detection-profile-ref?   leafref
          |              +--rw network-ref?
          |                      -> /nw:networks/network/network-id
          +--rw routing-protocols
          |  ...
          +--rw oam
          |  ...
          +--rw security
          |  ...
          +--rw service
             ...

                  Figure 10: IP Connection Tree Structure

so a distinct Layer 3 interface, other than the one under l2-connection, might be needed to terminate the Layer 3 connectivity 🧚 its identifier goes in l3-termination-point. for example, this data node can carry the identifier of a bridge domain interface 💜

this container can hold IPv4, IPv6, or both if dual-stack is enabled 🌈 for both IPv4 and IPv6, the IP connection supports three IP address assignment modes for customer addresses: provider DHCP, DHCP relay, and static addressing 🎀 also, for the IPv6 case, Stateless Address Autoconfiguration (SLAAC) [RFC4862] can be used ✨

for both IPv4 and IPv6, address-allocation-type is how you pick which IP address allocation mode is active for an AC 💖 the allocated address represents the PE interface address configuration. when address-allocation-type is set to provider-dhcp, DHCP assignments can be made locally or by an external DHCP server 🫶 which one happens is controlled by setting dhcp-service-type.

for IPv6, if address-allocation-type is set to slaac, the Prefix Information option of the Router Advertisements issued for SLAAC purposes carries the IPv6 prefix determined by local-address and prefix-length 🦋 for example, if local-address is 2001:db8:0:1::1 and prefix-length is 64, the IPv6 prefix used is 2001:db8:0:1::/64 🍓

in some deployment contexts (like network merging 🔥), multiple IP subnets may be used during a transition period. for those deployments, multiple ACs (typically two) with overlapping information may be maintained during the transition period 😭 the correlation between these ACs may rely on the same svc-ref 💅


5.6. Routing 🌸

the overall routing subtree structure is shown in Figure 11, and it's a whole vibe 👑

   module: ietf-ac-ntw
     augment /nw:networks/nw:network:
       +--rw ac-profile* [name]
          +--rw name                 string
          +--rw routing-protocols
          |  +--rw routing-protocol* [id]
          |     +--rw id      string
          |     +--rw type?   identityref
          |     +--rw bgp  {vpn-common:rtg-bgp}?
          |     |  ...
          |     +--rw ospf  {vpn-common:rtg-ospf}?
          |     |  ...
          |     +--rw isis  {vpn-common:rtg-isis}?
          |     |  ...
          |     +--rw rip  {vpn-common:rtg-rip}?
          |     |  ...
          |     +--rw vrrp  {vpn-common:rtg-vrrp}?
          |        ...
          +--rw oam
             ...
     augment /nw:networks/nw:network/nw:node:
       +--rw ac* [name]
          +--rw name                 string
          ...
          +--rw l2-connection  {ac-common:layer2-ac}?
          |  ...
          +--rw ip-connection  {ac-common:layer3-ac}?
          |  ...
          +--rw routing-protocols
          |  +--rw routing-protocol* [id]
          |     +--rw id                  string
          |     +--rw type?               identityref
          |     +--rw routing-profile* [routing-profile-ref]
          |     |  +--rw routing-profile-ref    leafref
          |     |  +--rw network-ref?
          |     |  |       -> /nw:networks/network/network-id
          |     |  +--rw type?                  identityref
          |     +--rw static
          |     |  ...
          |     +--rw bgp  {vpn-common:rtg-bgp}?
          |     |  ...
          |     +--rw ospf  {vpn-common:rtg-ospf}?
          |     |  ...
          |     +--rw isis  {vpn-common:rtg-isis}?
          |     |  ...
          |     +--rw rip  {vpn-common:rtg-rip}?
          |     |  ...
          |     +--rw vrrp  {vpn-common:rtg-vrrp}?
          |        ...
          +--rw oam
          |  ...
          +--rw security
          |  ...
          +--rw service
             ...

                     Figure 11: Routing Tree Structure

you can define multiple routing instances (routing-protocol), and each one is uniquely identified by an id 💖 this is so that multiple instances of the same routing protocol can be configured on the same AC, which is honestly iconic 🎀

the type of a routing instance goes in type 🧚 the values come from [RFC9181] (the routing-protocol-type identity), and specific data nodes are provided depending on the type. more details are in the following subsections 🫶

one or multiple routing profiles (routing-profile) can be provided for a given routing instance ✨ 🌈

5.6.1. Static Routing ✨

okay so static routing gets its own little tree, and it's giving organized 💅 The static routing subtree structure is shown in Figure 12.

   module: ietf-ac-ntw
             ...
     augment /nw:networks/nw:network/nw:node:
       +--rw ac* [name]
          +--rw name                 string
          ...
          +--rw l2-connection  {ac-common:layer2-ac}?
          |  ...
          +--rw ip-connection  {ac-common:layer3-ac}?
          |  ...
          +--rw routing-protocols
          |  +--rw routing-protocol* [id]
          |     +--rw id                 string
          |     +--rw type?              identityref
          |     +--rw routing-profile* [routing-profile-ref]
          |     |  +--rw routing-profile-ref    leafref
          |     |  +--rw network-ref?
          |     |  |       -> /nw:networks/network/network-id
          |     |  +--rw type?                  identityref
          |     +--rw static
          |     |  +--rw cascaded-lan-prefixes
          |     |     +--rw ipv4-lan-prefix* [lan next-hop]
          |     |     |       {vpn-common:ipv4}?
          |     |     |  +--rw lan           inet:ipv4-prefix
          |     |     |  +--rw lan-tag?      string
          |     |     |  +--rw next-hop      union
          |     |     |  +--rw metric?       uint32
          |     |     |  +--rw bfd {vpn-common:bfd}?
          |     |     |  |  +--rw enabled?
          |     |     |  |  |       boolean
          |     |     |  |  +--rw failure-detection-profile-ref?
          |     |     |  |  |       leafref
          |     |     |  |  +--rw network-ref?
          |     |     |  |          -> /nw:networks/network/network-id
          |     |     |  +--rw preference?   uint32
          |     |     |  +--rw status
          |     |     |     +--rw admin-status
          |     |     |     |  +--rw status?        identityref
          |     |     |     |  +--ro last-change?   yang:date-and-time
          |     |     |     +--ro oper-status
          |     |     |        +--ro status?        identityref
          |     |     |        +--ro last-change?   yang:date-and-time
          |     |     +--rw ipv6-lan-prefix* [lan next-hop]
          |     |             {vpn-common:ipv6}?
          |     |        +--rw lan           inet:ipv6-prefix
          |     |        +--rw lan-tag?      string
          |     |        +--rw next-hop      union
          |     |        +--rw metric?       uint32
          |     |        +--rw bfd {vpn-common:bfd}?
          |     |        |  +--rw enabled?
          |     |        |  |       boolean
          |     |        |  +--rw failure-detection-profile-ref?
          |     |        |  |       leafref
          |     |        |  +--rw network-ref?
          |     |        |          -> /nw:networks/network/network-id
          |     |        +--rw preference?   uint32
          |     |        +--rw status
          |     |           +--rw admin-status
          |     |           |  +--rw status?        identityref
          |     |           |  +--ro last-change?   yang:date-and-time
          |     |           +--ro oper-status
          |     |              +--ro status?        identityref
          |     |              +--ro last-change?   yang:date-and-time
          |     +--rw bgp  {vpn-common:rtg-bgp}?
          |     |  ...
          |     +--rw ospf  {vpn-common:rtg-ospf}?
          |     |  ...
          |     +--rw isis  {vpn-common:rtg-isis}?
          |     |  ...
          |     +--rw rip  {vpn-common:rtg-rip}?
          |     |  ...
          |     +--rw vrrp  {vpn-common:rtg-vrrp}?
          |        ...
          +--rw oam
          |  ...
          +--rw security
          |  ...
          +--rw service
             ...

Figure 12: Static Routing Tree Structure 🌸

The following data nodes can be defined for a given IP prefix:

  • 'lan-tag': Indicates a local tag (e.g., 'myfavorite-lan') that is used to enforce local policies. 🎀
  • 'next-hop': Indicates the next hop to be used for the static route. It can be identified by an IP address, a predefined next-hop type (e.g., 'discard' or 'local-link'), etc. 🦋
  • 'bfd': Indicates whether BFD is enabled or disabled for this static route entry. A BFD profile may also be provided. ✨
  • 'metric': Indicates the metric associated with the static route entry. This metric is used when the route is exported into an IGP. 🧚
  • 'preference': Indicates the preference associated with the static route entry. This preference is used to select a preferred route among routes to the same destination prefix. 👑
  • 'status': Used to convey the status of a static route entry. This data node can also be used to control the (de)activation of individual static route entries. 💖

5.6.2. BGP 🌈

The BGP routing subtree structure is shown in Figure 13. 🫶

Okay bestie, here's the whole BGP routing tree in one glance 🌳✨ The peer-group branch is the one we're looking at, and the neighbor stuff sits right underneath it 💅

module: ietf-ac-ntw
  augment /nw:networks/nw:network:
    +--rw ac-profile* [name]
       +--rw name                 string
       +--rw routing-protocols
       |  +--rw routing-protocol* [id]
       |     +--rw id      string
       |     +--rw type?   identityref
       |     +--rw bgp  {vpn-common:rtg-bgp}?
       |     |  +--rw peer-groups
       |     |     +--rw peer-group* [name]
       |     |        +--rw name                      string
       |     |        +--rw description?              string
       |     |        +--rw apply-policy
       |     |        |  +--rw import-policy*           leafref
       |     |        |  +--rw default-import-policy?
       |     |        |  |       default-policy-type
       |     |        |  +--rw export-policy*           leafref
       |     |        |  +--rw default-export-policy?
       |     |        |          default-policy-type
       |     |        +--rw local-as?                 inet:as-number
       |     |        +--rw peer-as                   inet:as-number
       |     |        +--rw address-family?           identityref
       |     |        +--rw role?                     identityref
       |     |        +--rw multihop?                 uint8
       |     |        +--rw as-override?              boolean
       |     |        +--rw allow-own-as?             uint8
       |     |        +--rw prepend-global-as?        boolean
       |     |        +--rw send-default-route?       boolean
       |     |        +--rw site-of-origin?
       |     |        |       rt-types:route-origin
       |     |        +--rw ipv6-site-of-origin?
       |     |        |       rt-types:ipv6-route-origin
       |     |        +--rw redistribute-connected* [address-family]
       |     |        |  +--rw address-family    identityref
       |     |        |  +--rw enabled?          boolean
       |     |        +--rw bgp-max-prefix
       |     |        |  +--rw max-prefix?          uint32
       |     |        |  +--rw warning-threshold?   decimal64
       |     |        |  +--rw violate-action?      enumeration
       |     |        |  +--rw restart-timer?       uint32
       |     |        +--rw bgp-timers
       |     |           +--rw keepalive?   uint16
       |     |           +--rw hold-time?   uint16
       |     +--rw ospf  {vpn-common:rtg-ospf}?
       |     |  ...
       |     +--rw isis  {vpn-common:rtg-isis}?
       |     |  ...
       |     +--rw rip  {vpn-common:rtg-rip}?
       |     |  ...
       |     +--rw vrrp  {vpn-common:rtg-vrrp}?
       |        ...
       +--rw oam
          ...
  augment /nw:networks/nw:network/nw:node:
    +--rw ac* [name]
       +--rw name                 string
       ...
       +--rw l2-connection  {ac-common:layer2-ac}?
       |  ...
       +--rw ip-connection  {ac-common:layer3-ac}?
       |  ...
       +--rw routing-protocols
       |  +--rw routing-protocol* [id]
       |     +--rw id                  string
       |     +--rw type?               identityref
       |     +--rw routing-profile* [routing-profile-ref]
       |     |  +--rw routing-profile-ref    leafref
       |     |  +--rw network-ref?
       |     |  |       -> /nw:networks/network/network-id
       |     |  +--rw type?                  identityref
       |     +--rw static
       |     |  ...
       |     +--rw bgp {vpn-common:rtg-bgp}?
       |     |  +--rw peer-groups
       |     |  |  +--rw peer-group* [name]
       |     |  |     +--rw name                      string
       |     |  |     +--rw local-address?            union
       |     |  |     +--rw description?              string
       |     |  |     +--rw apply-policy
       |     |  |     |  +--rw import-policy*           leafref
       |     |  |     |  +--rw default-import-policy?
       |     |  |     |  |       default-policy-type
       |     |  |     |  +--rw export-policy*           leafref
       |     |  |     |  +--rw default-export-policy?
       |     |  |     |          default-policy-type
       |     |  |     +--rw local-as?                 inet:as-number
       |     |  |     +--rw peer-as                   inet:as-number
       |     |  |     +--rw address-family?           identityref
       |     |  |     +--rw role?                     identityref
       |     |  |     +--rw multihop?                 uint8
       |     |  |     +--rw as-override?              boolean
       |     |  |     +--rw allow-own-as?             uint8
       |     |  |     +--rw prepend-global-as?        boolean
       |     |  |     +--rw send-default-route?       boolean
       |     |  |     +--rw site-of-origin?
       |     |  |     |       rt-types:route-origin
       |     |  |     +--rw ipv6-site-of-origin?
       |     |  |     |       rt-types:ipv6-route-origin
       |     |  |     +--rw redistribute-connected* [address-family]
       |     |  |     |  +--rw address-family    identityref
       |     |  |     |  +--rw enabled?          boolean
       |     |  |     +--rw bgp-max-prefix
       |     |  |     |  +--rw max-prefix?          uint32
       |     |  |     |  +--rw warning-threshold?   decimal64
       |     |  |     |  +--rw violate-action?      enumeration
       |     |  |     |  +--rw restart-timer?       uint32
       |     |  |     +--rw bgp-timers
       |     |  |     |  +--rw keepalive?   uint16
       |     |  |     |  +--rw hold-time?   uint16
       |     |  |     +--rw authentication
       |     |  |        +--rw enabled?           boolean
       |     |  |        +--rw keying-material
       |     |  |           +--rw (option)?
       |     |  |              +--:(ao)
       |     |  |              |  +--rw enable-ao?          boolean
       |     |  |              |  +--rw ao-keychain?
       |     |  |              |          key-chain:key-chain-ref
       |     |  |              +--:(md5)
       |     |  |              |  +--rw md5-keychain?
       |     |  |              |          key-chain:key-chain-ref
       |     |  |              +--:(explicit)
       |     |  |                 +--rw key-id?             uint32
       |     |  |                 +--rw key?                string
       |     |  |                 +--rw crypto-algorithm?
       |     |  |                         identityref
       |     |  +--rw neighbor* [remote-address]
       |     |     +--rw remote-address            inet:ip-address
       |     |     +--rw local-address?            union
       |     |     +--rw peer-group?
       |     |     |       -> ../../peer-groups/peer-group/name
       |     |     +--rw description?              string
       |     |     +--rw apply-policy
       |     |     |  +--rw import-policy*           leafref
       |     |     |  +--rw default-import-policy?
       |     |     |  |       default-policy-type
       |     |     |  +--rw export-policy*           leafref
       |     |     |  +--rw default-export-policy?
       |     |     |          default-policy-type
       |     |     +--rw local-as?                 inet:as-number
       |     |     +--rw peer-as                   inet:as-number
       |     |     +--rw address-family?           identityref
       |     |     +--rw role?                     identityref
       |     |     +--rw multihop?                 uint8
       |     |     +--rw as-override?              boolean
       |     |     +--rw allow-own-as?             uint8
       |     |     +--rw prepend-global-as?        boolean
       |     |     +--rw send-default-route?       boolean
       |     |     +--rw site-of-origin?
       |     |     |       rt-types:route-origin
       |     |     +--rw ipv6-site-of-origin?
       |     |     |       rt-types:ipv6-route-origin
       |     |     +--rw redistribute-connected* [address-family]
       |     |     |  +--rw address-family    identityref
       |     |     |  +--rw enabled?          boolean
       |     |     +--rw bgp-max-prefix
       |     |     |  +--rw max-prefix?          uint32
       |     |     |  +--rw warning-threshold?   decimal64
       |     |     |  +--rw violate-action?      enumeration
       |     |     |  +--rw restart-timer?       uint32
       |     |     +--rw bgp-timers
       |     |     |  +--rw keepalive?   uint16
       |     |     |  +--rw hold-time?   uint16
       |     |     +--rw bfd {vpn-common:bfd}?
       |     |     |  +--rw enabled?                         boolean
       |     |     |  +--rw failure-detection-profile-ref?   leafref
       |     |     |  +--rw network-ref?
       |     |     |          -> /nw:networks/network/network-id
       |     |     +--rw authentication
       |     |     |  +--rw enabled?           boolean
       |     |     |  +--rw keying-material
       |     |     |     +--rw (option)?
       |     |     |        +--:(ao)
       |     |     |        |  +--rw enable-ao?          boolean
       |     |     |        |  +--rw ao-keychain?
       |     |     |        |          key-chain:key-chain-ref
       |     |     |        +--:(md5)
       |     |     |        |  +--rw md5-keychain?
       |     |     |        |          key-chain:key-chain-ref
       |     |     |        +--:(explicit)
       |     |     |           +--rw key-id?             uint32
       |     |     |           +--rw key?                string
       |     |     |           +--rw crypto-algorithm?   identityref
       |     |     +--rw status
       |     |        +--rw admin-status
       |     |        |  +--rw status?        identityref
       |     |        |  +--ro last-change?   yang:date-and-time
       |     |        +--ro oper-status
       |     |           +--ro status?        identityref
       |     |           +--ro last-change?   yang:date-and-time
       |     +--rw ospf  {vpn-common:rtg-ospf}?
       |     |  ...
       |     +--rw isis  {vpn-common:rtg-isis}?
       |     |  ...
       |     +--rw rip  {vpn-common:rtg-rip}?
       |     |  ...
       |     +--rw vrrp  {vpn-common:rtg-vrrp}?
       |        ...
       +--rw oam
       |  ...
       +--rw security
       |  ...
       +--rw service
          ...

Figure 13: BGP Routing Tree Structure

Now the good stuff! 💖 The following data nodes are supported for each peer-group:

  • name: Defines a name for the peer group. 🏷️
  • local-address: Specifies an address or a reference to an interface to use when establishing the BGP transport session. 🔌
  • description: Includes a description of the peer group. 📝
  • apply-policy: Lists a set of import/export policies [RFC9067] to apply for this group. 🎀
  • local-as: Indicates a local Autonomous System Number (ASN). 👑
  • peer-as: Indicates the peer's ASN. 🫶
  • address-family: Indicates the address family of the peer. It can be set to ipv4, ipv6, or dual-stack. 🌈
    • Okay, this one is giving main character energy 💅 This address family might be used together with the service type that uses an AC (e.g., vpn-type [RFC9182]) to derive the appropriate Address Family Identifiers (AFIs) / Subsequent Address Family Identifiers (SAFIs) that will be part of the derived device configurations (e.g., unicast IPv4 MPLS L3VPN (AFI,SAFI = 1,128) as defined in Section 4.3.4 of [RFC4364]).
  • role: Specifies the BGP role in a session. Role values are taken from the list defined in Section 4 of [RFC9234]. 🦋
  • multihop: How many IP hops are allowed to reach a BGP peer. 🛰️
  • as-override: If this is set, it tells you whether ASN override is turned on. That means swapping the customer's ASN in the AS_PATH BGP attribute for the ASN from the local-as attribute. 🔄
  • allow-own-as: Shows up in some topologies (hub-and-spoke is the classic one) and lets the provider's own ASN appear in the AS_PATH BGP attribute received from a peer. Loops are stopped by setting allow-own-as to a maximum number of times the provider's ASN can show up. By default it's 0, which means reject any AS_PATH attribute that includes the provider's ASN. 🙅‍♀️
  • prepend-global-as: When different ASNs are configured at the node level and the AC level, this one decides whether the node-level ASN gets prepended to the AS_PATH attribute. 🎀
  • send-default-route: Controls whether default routes can be advertised to the peer. 🛣️
  • site-of-origin: Uniquely identifies the set of routes learned from a site through a particular AC. It's used to prevent routing loops (Section 7 of [RFC4364]). The Site of Origin attribute is encoded as a Route Origin Extended Community. 🪪
  • ipv6-site-of-origin: Carries an IPv6 Address Specific BGP Extended Community that's used to indicate the Site of Origin [RFC5701]. It's also used to prevent routing loops. 💜
  • redistribute-connected: Controls whether the AC gets advertised to other PEs. 📣
  • bgp-max-prefix: Controls what happens when a prefix maximum is reached. 🚧
  • max-prefix: The maximum number of BGP prefixes allowed in a session for this group. If that limit gets hit, the action in violate-action kicks in. 🧱
  • warning-threshold: A warning notification gets triggered when this limit is reached. ⚠️
  • violate-action: Says which action to run when the maximum number of BGP prefixes is reached. Examples include sending a warning message, discarding extra paths from the peer, or restarting the session. 💅
  • restart-timer: The time in seconds after which the BGP session gets reestablished. ⏲️
  • bgp-timers: This container can hold two timers. (1) hold-time is the interval used for the Hold Timer (Section 4.2 of [RFC4271]) when establishing a BGP session. (2) keepalive is the interval for the KeepaliveTimer between a PE and a BGP peer (Section 4.4 of [RFC4271]). 🫶

Both timers are expressed in seconds. ⏱️

  • bfd: Indicates whether BFD is enabled or disabled for this neighbor. You can also provide a BFD profile to apply. 🦋
  • authentication: Okay, this one is giving responsible security energy 🔐. The module follows the recommendations in Section 13.2 of [RFC4364] because it lets you enable the TCP Authentication Option (TCP-AO) [RFC5925] and still works with the installed base that uses MD5.

This version of the model assumes the TCP-AO parameters are preconfigured as part of the key chain referenced in the model. It makes no assumption about how that key chain gets preconfigured. The structure of the key chain should still cover data nodes beyond the ones in [RFC8177], mainly SendID and RecvID (Section 3.1 of [RFC5925]). 🗝️

For each neighbor, the following data nodes are supported on top of the similar parameters that are provided for a peer group: 👯

  • remote-address: Specifies the remote IP address of a BGP neighbor. 📍
  • peer-group: The name of a peer group. 🧁

Parameters provided at the neighbor level take precedence over the ones provided in the peer group. 👑

  • status: Indicates the status of the BGP session. 🌈

5.6.3. OSPF 🦋

The OSPF routing subtree structure is shown in Figure 14. 🧚

   module: ietf-ac-ntw
     augment /nw:networks/nw:network:
       +--rw ac-profile* [name]
          +--rw name                 string
          +--rw routing-protocols
          |  +--rw routing-protocol* [id]
          |     +--rw id      string
          |     +--rw type?   identityref
          |     +--rw bgp  {vpn-common:rtg-bgp}?
          |     |  ...
          |     +--rw ospf  {vpn-common:rtg-ospf}?
          |     |  +--rw address-family?   identityref
          |     |  +--rw area-id           yang:dotted-quad
          |     |  +--rw metric?           uint16
          |     |  +--rw max-lsa?          uint32
          |     +--rw isis  {vpn-common:rtg-isis}?
          |     |  ...
          |     +--rw rip  {vpn-common:rtg-rip}?
          |     |  ...
          |     +--rw vrrp  {vpn-common:rtg-vrrp}?
          |        ...
          +--rw oam
             ...
     augment /nw:networks/nw:network/nw:node:
       +--rw ac* [name]
          +--rw name                 string
          ...
          +--rw l2-connection  {ac-common:layer2-ac}?
          |  ...
          +--rw ip-connection  {ac-common:layer3-ac}?
          |  ...
          +--rw routing-protocols
          |  +--rw routing-protocol* [id]
          |     +--rw id                  string
          |     +--rw type?               identityref
          |     +--rw routing-profile* [routing-profile-ref]
          |     |  +--rw routing-profile-ref    leafref
          |     |  +--rw network-ref?
          |     |  |       -> /nw:networks/network/network-id
          |     |  +--rw type?                  identityref
          |     +--rw static
          |     |  ...
          |     +--rw bgp  {vpn-common:rtg-bgp}?
          |     |  ...
          |     +--rw ospf {vpn-common:rtg-ospf}?
          |     |  +--rw address-family?   identityref
          |     |  +--rw area-id           yang:dotted-quad
          |     |  +--rw metric?           uint16
          |     |  +--rw sham-links {vpn-common:rtg-ospf-sham-link}?
          |     |  |  +--rw sham-link* [target-site]
          |     |  |     +--rw target-site    string
          |     |  |     +--rw metric?        uint16
          |     |  +--rw max-lsa?          uint32
          |     |  +--rw passive?          boolean
          |     |  +--rw authentication
          |     |  |  +--rw enabled?           boolean
          |     |  |  +--rw keying-material
          |     |  |     +--rw (option)?
          |     |  |        +--:(auth-key-chain)
          |     |  |        |  +--rw key-chain?
          |     |  |        |          key-chain:key-chain-ref
          |     |  |        +--:(auth-key-explicit)
          |     |  |           +--rw key-id?             uint32
          |     |  |           +--rw key?                string
          |     |  |           +--rw crypto-algorithm?   identityref
          |     |  +--rw status
          |     |     +--rw admin-status
          |     |     |  +--rw status?        identityref
          |     |     |  +--ro last-change?   yang:date-and-time
          |     |     +--ro oper-status
          |     |        +--ro status?        identityref
          |     |        +--ro last-change?   yang:date-and-time
          |     +--rw isis  {vpn-common:rtg-isis}?
          |     |  ...
          |     +--rw rip  {vpn-common:rtg-rip}?
          |     |  ...
          |     +--rw vrrp  {vpn-common:rtg-vrrp}?
          |        ...
          +--rw oam
          |  ...
          +--rw security
          |  ...
          +--rw service
             ...

Figure 14: OSPF Routing Tree Structure 🌳

The following OSPF data nodes are supported: 💖

  • address-family: Indicates whether IPv4, IPv6, or both address families get activated. 🌐

When the IPv4 or dual-stack address family is requested, it's up to the implementation (for example, the network orchestrator) to decide whether OSPFv2 [RFC4577] or OSPFv3 [RFC6565] gets used to announce IPv4 routes. 🤷‍♀️

  • area-id: Indicates the OSPF Area ID. 🍓
  • metric: Associates a metric with OSPF routes. 📏
  • sham-links: Used to create OSPF sham links between two ACs that share the same area and have a backdoor link (Section 4.2.7 of [RFC4577] and Section 5 of [RFC6565]). 🔗
  • max-lsa: Sets the maximum number of Link State Advertisements (LSAs) that the OSPF instance will accept. 📬
  • passive: Controls whether an OSPF interface is passive or active. 😴
  • authentication: Controls which authentication schemes get enabled for the OSPF instance. The module supports the authentication options common to both OSPF versions: the Authentication Trailer for OSPFv2 [RFC5709] [RFC7474] and OSPFv3 [RFC7166]. Because of that, the model does not support [RFC4552]. 🔐
  • status: Indicates the status of the OSPF routing instance. ✨

5.6.4. IS-IS ✨

okay so the IS-IS routing subtree structure is shown in Figure 15 💅🌸

   module: ietf-ac-ntw
     augment /nw:networks/nw:network:
       +--rw ac-profile* [name]
          +--rw name                 string
          +--rw routing-protocols
          |  +--rw routing-protocol* [id]
          |     +--rw id      string
          |     +--rw type?   identityref
          |     +--rw bgp  {vpn-common:rtg-bgp}?
          |     |  ...
          |     +--rw ospf  {vpn-common:rtg-ospf}?
          |     |  ...
          |     +--rw isis  {vpn-common:rtg-isis}?
          |     |  +--rw address-family?   identityref
          |     |  +--rw area-address      area-address
          |     |  +--rw level?            identityref
          |     |  +--rw metric?           uint32
          |     |  +--rw passive?          boolean
          |     +--rw rip  {vpn-common:rtg-rip}?
          |     |  ...
          |     +--rw vrrp  {vpn-common:rtg-vrrp}?
          |        ...
          +--rw oam
             ...
     augment /nw:networks/nw:network/nw:node:
       +--rw ac* [name]
          +--rw name                 string
          ...
          +--rw l2-connection
          |  ...
          +--rw ip-connection
          |  ...
          +--rw routing-protocols
          |  +--rw routing-protocol* [id]
          |     +--rw id                  string
          |     +--rw type?               identityref
          |     +--rw routing-profile* [routing-profile-ref]
          |     |  +--rw routing-profile-ref    leafref
          |     |  +--rw network-ref?
          |     |  |       -> /nw:networks/network/network-id
          |     |  +--rw type?                  identityref
          |     +--rw static
          |     |  ...
          |     +--rw bgp  {vpn-common:rtg-bgp}?
          |     |  ...
          |     +--rw ospf  {vpn-common:rtg-ospf}?
          |     |  ...
          |     +--rw isis {vpn-common:rtg-isis}?
          |     |  +--rw address-family?   identityref
          |     |  +--rw area-address      area-address
          |     |  +--rw level?            identityref
          |     |  +--rw metric?           uint32
          |     |  +--rw passive?          boolean
          |     |  +--rw authentication
          |     |  |  +--rw enabled?           boolean
          |     |  |  +--rw keying-material
          |     |  |     +--rw (option)?
          |     |  |        +--:(auth-key-chain)
          |     |  |        |  +--rw key-chain?
          |     |  |        |          key-chain:key-chain-ref
          |     |  |        +--:(auth-key-explicit)
          |     |  |           +--rw key-id?             uint32
          |     |  |           +--rw key?                string
          |     |  |           +--rw crypto-algorithm?   identityref
          |     |  +--rw status
          |     |     +--rw admin-status
          |     |     |  +--rw status?        identityref
          |     |     |  +--ro last-change?   yang:date-and-time
          |     |     +--ro oper-status
          |     |        +--ro status?        identityref
          |     |        +--ro last-change?   yang:date-and-time
          |     +--rw rip  {vpn-common:rtg-rip}?
          |     |  ...
          |     +--rw vrrp  {vpn-common:rtg-vrrp}?
          |        ...
          +--rw oam
          |  ...
          +--rw security
          |  ...
          +--rw service
             ...

Figure 15: IS-IS Routing Tree Structure

the following IS-IS data nodes are supported, so here's the tea 🍓

  • address-family: Indicates whether IPv4, IPv6, or both address families are to be activated.
  • area-address: Indicates the IS-IS area address.
  • level: Indicates the IS-IS level: Level 1, Level 2, or both.
  • metric: Associates a metric with IS-IS routes.
  • passive: Controls whether an IS-IS interface is passive or active.
  • authentication: Controls the authentication schemes to be enabled for the IS-IS instance. Both the specification of a key chain [RFC8177] and the direct specification of key and authentication algorithms are supported. 🔥
  • status: Indicates the status of the IS-IS routing instance.

5.6.5. RIP 🦋

the RIP routing subtree structure is shown in Figure 16, and it's giving classic vibes 🧚

   module: ietf-ac-ntw
     augment /nw:networks/nw:network:
       +--rw ac-profile* [name]
          +--rw name                 string
          +--rw routing-protocols
          |  +--rw routing-protocol* [id]
          |     +--rw id      string
          |     +--rw type?   identityref
          |     +--rw bgp  {vpn-common:rtg-bgp}?
          |     |  ...
          |     +--rw ospf  {vpn-common:rtg-ospf}?
          |     |  ...
          |     +--rw isis  {vpn-common:rtg-isis}?
          |     |  ...
          |     +--rw rip  {vpn-common:rtg-rip}?
          |     |  +--rw address-family?   identityref
          |     |  +--rw timers
          |     |  |  +--rw update-interval?     uint16
          |     |  |  +--rw invalid-interval?    uint16
          |     |  |  +--rw holddown-interval?   uint16
          |     |  |  +--rw flush-interval?      uint16
          |     |  +--rw default-metric?   uint8
          |     +--rw vrrp  {vpn-common:rtg-vrrp}?
          |        ...
          +--rw oam
             ...
     augment /nw:networks/nw:network/nw:node:
       +--rw ac* [name]
          +--rw name                 string
          ...
          +--rw l2-connection  {ac-common:layer2-ac}?
          |  ...
          +--rw ip-connection  {ac-common:layer3-ac}?
          |  ...
          +--rw routing-protocols
          |  +--rw routing-protocol* [id]
          |     +--rw id                  string
          |     +--rw type?               identityref
          |     +--rw routing-profile* [routing-profile-ref]
          |     |  +--rw routing-profile-ref    leafref
          |     |  +--rw network-ref?
          |     |  |       -> /nw:networks/network/network-id
          |     |  +--rw type?                  identityref
          |     +--rw static
          |     |  ...
          |     +--rw bgp  {vpn-common:rtg-bgp}?
          |     |  ...
          |     +--rw ospf  {vpn-common:rtg-ospf}?
          |     |  ...
          |     +--rw isis  {vpn-common:rtg-isis}?
          |     |  ...
          |     +--rw rip  {vpn-common:rtg-rip}?
          |     |  +--rw address-family?   identityref
          |     |  +--rw timers
          |     |  |  +--rw update-interval?     uint16
          |     |  |  +--rw invalid-interval?    uint16
          |     |  |  +--rw holddown-interval?   uint16
          |     |  |  +--rw flush-interval?      uint16
          |     |  +--rw default-metric?   uint8
          |     |  +--rw authentication
          |     |  |  +--rw enabled?            boolean
          |     |  |  +--rw keying-material
          |     |  |     +--rw (option)?
          |     |  |        +--:(auth-key-chain)
          |     |  |        |  +--rw key-chain?
          |     |  |        |          key-chain:key-chain-ref
          |     |  |        +--:(auth-key-explicit)
          |     |  |           +--rw key?                string
          |     |  |           +--rw crypto-algorithm?   identityref
          |     |  +--rw status
          |     |     +--rw admin-status
          |     |     |  +--rw status?        identityref
          |     |     |  +--ro last-change?   yang:date-and-time
          |     |     +--ro oper-status
          |     |        +--ro status?        identityref
          |     |        +--ro last-change?   yang:date-and-time
          |     +--rw vrrp
          |        ...
          +--rw oam
          |  ...
          +--rw security
          |  ...
          +--rw service
             ...

Figure 16: RIP Routing Tree Structure

and now the RIP data nodes, bestie 💜

  • address-family: Indicates whether IPv4, IPv6, or both address families are to be activated. This parameter is used to determine whether RIPv2 [RFC2453], RIP Next Generation (RIPng) [RFC2080], or both are to be enabled. ✨
  • timers: Indicates the following timers (expressed in seconds):
    • update-interval: The interval at which RIP updates are sent.
    • invalid-interval: The interval before a RIP route is declared invalid.
    • holddown-interval: The interval before better RIP routes are released.
    • flush-interval: The interval before a route is removed from the routing table.
  • default-metric: Sets the default RIP metric. 🌈
  • authentication: Controls the authentication schemes to be enabled for the RIP instance. 🔐
  • status: Indicates the status of the RIP routing instance. 💅

5.6.6. VRRP 🦋

okay so VRRP's subtree is shown in Figure 17, bestie 🧚

   module: ietf-ac-ntw
     augment /nw:networks/nw:network:
       +--rw ac-profile* [name]
          +--rw name                 string
          +--rw routing-protocols
          |  +--rw routing-protocol* [id]
          |     +--rw id      string
          |     +--rw type?   identityref
          |     +--rw bgp  {vpn-common:rtg-bgp}?
          |     |  ...
          |     +--rw ospf  {vpn-common:rtg-ospf}?
          |     |  ...
          |     +--rw isis  {vpn-common:rtg-isis}?
          |     |  ...
          |     +--rw rip  {vpn-common:rtg-rip}?
          |     |  ...
          |     +--rw vrrp  {vpn-common:rtg-vrrp}?
          |        +--rw address-family?   identityref
          |        +--rw ping-reply?       boolean
          +--rw oam
             ...
     augment /nw:networks/nw:network/nw:node:
       +--rw ac* [name]
          +--rw name                 string
          ...
          +--rw l2-connection  {ac-common:layer2-ac}?
          |  ...
          +--rw ip-connection  {ac-common:layer3-ac}?
          |  ...
          +--rw routing-protocols
          |  +--rw routing-protocol* [id]
          |     +--rw id                  string
          |     +--rw type?               identityref
          |     +--rw routing-profile* [routing-profile-ref]
          |     |  +--rw routing-profile-ref    leafref
          |     |  +--rw network-ref?
          |     |  |       -> /nw:networks/network/network-id
          |     |  +--rw type?                  identityref
          |     +--rw static
          |     |  ...
          |     +--rw bgp  {vpn-common:rtg-bgp}?
          |     |  ...
          |     +--rw ospf  {vpn-common:rtg-ospf}?
          |     |  ...
          |     +--rw isis  {vpn-common:rtg-isis}?
          |     |  ...
          |     +--rw rip  {vpn-common:rtg-rip}?
          |     |  ...
          |     +--rw vrrp  {vpn-common:rtg-vrrp}?
          |        +--rw address-family?       identityref
          |        +--rw vrrp-group?           uint8
          |        +--rw backup-peer?          inet:ip-address
          |        +--rw virtual-ip-address*   inet:ip-address
          |        +--rw priority?             uint8
          |        +--rw ping-reply?           boolean
          |        +--rw status
          |           +--rw admin-status
          |           |  +--rw status?        identityref
          |           |  +--ro last-change?   yang:date-and-time
          |           +--ro oper-status
          |              +--ro status?        identityref
          |              +--ro last-change?   yang:date-and-time
          +--rw oam
          |  ...
          +--rw security
          |  ...
          +--rw service
             ...

                       Figure 17: VRRP Tree Structure

these are the VRRP data nodes that are supported, no cap 💅

'address-family' 🌸: says whether IPv4, IPv6, or both address families get turned on. ngl VRRP version 3 [RFC9568] supports both IPv4 and IPv6, so it's giving options 🙌

'vrrp-group' 🎀: used to identify the VRRP group. main ID energy ✨

'backup-peer' 💜: carries the IP address of the peer.

'virtual-ip-address' 🍓: includes the virtual IP addresses for a single VRRP group. multiple allowed, iconic 👑

'priority' ⭐: assigns the VRRP election priority for the backup virtual router. higher wins the election, lowkey the drama 😭

'ping-reply' 🫶: controls whether the VRRP speaker should reply to ping requests.

'status' 🔥: indicates the status of the VRRP instance.

ngl this one's important: there's no authentication data node included for VRRP, bc there isn't any type of VRRP authentication at this time (see Section 9 of [RFC9568]). so don't go looking for one 🙈

5.7. OAM 🌈

okay the OAM subtree is shown in Figure 18, let's gooo 🧚‍♀️

     augment /nw:networks/nw:network:
       +--rw ac-profile* [name]
          +--rw name                 string
          +--rw routing-protocols
          |  ...
          +--rw oam
             +--rw bfd {vpn-common:bfd}?
                +--rw session-type?               identityref
                +--rw desired-min-tx-interval?    uint32
                +--rw required-min-rx-interval?   uint32
                +--rw local-multiplier?           uint8
                +--rw holdtime?                   uint32
     augment /nw:networks/nw:network/nw:node:
       +--rw ac* [name]
          +--rw name                 string
          + ...
          +--rw l2-connection  {ac-common:layer2-ac}?
          |  ...
          +--rw ip-connection  {ac-common:layer3-ac}?
          |  ...
          +--rw routing-protocols
          |  ...
          +--rw oam
          |  +--rw bfd {vpn-common:bfd}?
          |     +--rw session* [dest-addr]
          |        +--rw dest-addr                   inet:ip-address
          |        +--rw source-address?             union
          |        +--rw failure-detection-profile-ref?   leafref
          |        +--rw network-ref?
          |        |       -> /nw:networks/network/network-id
          |        +--rw session-type?               identityref
          |        +--rw desired-min-tx-interval?    uint32
          |        +--rw required-min-rx-interval?   uint32
          |        +--rw local-multiplier?           uint8
          |        +--rw holdtime?                   uint32
          |        +--rw authentication!
          |        |  +--rw key-chain?    key-chain:key-chain-ref
          |        |  +--rw meticulous?   boolean
          |        +--rw status
          |           +--rw admin-status
          |           |  +--rw status?        identityref
          |           |  +--ro last-change?   yang:date-and-time
          |           +--ro oper-status
          |              +--ro status?        identityref
          |              +--ro last-change?   yang:date-and-time
          +--rw security
          |  ...
          +--rw service
             ...

                       Figure 18: OAM Tree Structure

for each BFD session, these OAM data nodes can be specified 🎀

'dest-addr' 💖: specifies the BFD peer address. this one maps to 'remote-address' of the BFD container in [RFC9834]. 'dest-address' is used here to ease the mapping with the underlying device model defined in [RFC9127]. the mapping is the whole point, periodt 💅

'source-address' 🌷: specifies the local IP address or interface to use for the session. this maps to 'local-address' of the BFD container in [RFC9834]. 'source-address' is used here to ease the mapping with the underlying device model defined in [RFC9127]. same energy as dest-addr, iykyk 🧚

'failure-detection-profile-ref' 🦋: refers to a BFD profile in Section 5.3.

'network-ref' 🌸: includes a network reference to uniquely identify a BFD profile.

'session-type' ✨: indicates which BFD flavor is used to set up the session (e.g., classic BFD [RFC5880], Seamless BFD [RFC7880]). by default, it's assumed that the BFD session follows the behavior specified in [RFC5880]. classic is the default girlie 💜

'desired-min-tx-interval' ⭐: the minimum interval, in microseconds, to use when transmitting BFD Control packets, less any jitter applied.

'required-min-rx-interval' 🫶: the minimum interval, in microseconds, between received BFD Control packets, less any jitter applied by the sender.

'local-multiplier' 🔥: the negotiated transmit interval, multiplied by this value, provides the detection time for the peer. math is giving main character 🍓

'holdtime' 🌈: used to indicate the expected BFD holddown time, in milliseconds.

'authentication' 👑: includes the required information to enable the BFD authentication modes discussed in Section 6.7 of [RFC5880]. in particular, 'meticulous' controls the activation of meticulous mode as discussed in Sections 6.7.3 and 6.7.4 of [RFC5880]. very security-core, bestie 😭

'status' 💀: indicates the status of BFD.

5.8. Security 🔐

okay the security subtree is shown in Figure 19, and it's lowkey the most protective one 🛡️ the 'security' container specifies the encryption to be applied to traffic for a given AC. the model can be used to directly control the encryption to be applied (e.g., Layer 2 or Layer 3 encryption) or invoke a local encryption profile. you get to pick the vibe 💖

     augment /nw:networks/nw:network/nw:node:
       +--rw ac* [name]
          +--rw name                 string
          + ...
          +--rw l2-connection  {ac-common:layer2-ac}?
          |  ...
          +--rw ip-connection  {ac-common:layer3-ac}?
          |  ...
          +--rw routing-protocols
          |  ...
          +--rw oam
          |  ...
          +--rw security
          |  +--rw encryption {vpn-common:encryption}?
          |  |  +--rw enabled?   boolean
          |  |  +--rw layer?     enumeration
          |  +--rw encryption-profile
          |     +--rw (profile)?
          |        +--:(provider-profile)
          |        |  +--rw encryption-profile-ref?   leafref
          |        |  +--rw network-ref?
          |        |          -> /nw:networks/network/network-id
          |        +--:(customer-profile)
          |           +--rw customer-key-chain?  key-chain:key-chain-ref
          +--rw service
             ...

                     Figure 19: Security Tree Structure

5.9. Service ✨

Okay so, the service subtree is shown in Figure 20. Bestie, this is where all the fun service stuff lives 🎀

     augment /nw:networks/nw:network/nw:node:
       +--rw ac* [name]
          +--rw name                 string
          + ...
          +--rw l2-connection  {ac-common:layer2-ac}?
          |  ...
          +--rw ip-connection  {ac-common:layer3-ac}?
          |  ...
          +--rw routing-protocols
          |  ...
          +--rw oam
          |  ...
          +--rw security
          |  ...
          +--rw service
             +--rw mtu?                      uint32
             +--rw svc-pe-to-ce-bandwidth {vpn-common:inbound-bw}?
             |  +--rw bandwidth* [bw-type]
             |     +--rw bw-type      identityref
             |     +--rw (type)?
             |        +--:(per-cos)
             |        |  +--rw cos* [cos-id]
             |        |     +--rw cos-id    uint8
             |        |     +--rw cir?      uint64
             |        |     +--rw cbs?      uint64
             |        |     +--rw eir?      uint64
             |        |     +--rw ebs?      uint64
             |        |     +--rw pir?      uint64
             |        |     +--rw pbs?      uint64
             |        +--:(other)
             |           +--rw cir?   uint64
             |           +--rw cbs?   uint64
             |           +--rw eir?   uint64
             |           +--rw ebs?   uint64
             |           +--rw pir?   uint64
             |           +--rw pbs?   uint64
             +--rw svc-ce-to-pe-bandwidth {vpn-common:outbound-bw}?
             |  +--rw bandwidth* [bw-type]
             |     +--rw bw-type      identityref
             |     +--rw (type)?
             |        +--:(per-cos)
             |        |  +--rw cos* [cos-id]
             |        |     +--rw cos-id    uint8
             |        |     +--rw cir?      uint64
             |        |     +--rw cbs?      uint64
             |        |     +--rw eir?      uint64
             |        |     +--rw ebs?      uint64
             |        |     +--rw pir?      uint64
             |        |     +--rw pbs?      uint64
             |        +--:(other)
             |           +--rw cir?   uint64
             |           +--rw cbs?   uint64
             |           +--rw eir?   uint64
             |           +--rw ebs?   uint64
             |           +--rw pir?   uint64
             |           +--rw pbs?   uint64
             +--rw qos {vpn-common:qos}?
             |  +--rw qos-profiles
             |     +--rw qos-profile* [qos-profile-ref]
             |        +--rw qos-profile-ref    leafref
             |        +--rw network-ref?
             |        |       -> /nw:networks/network/network-id
             |        +--rw direction?         identityref
             +--rw access-control-list
                +--rw acl-profiles
                   +--rw acl-profile* [forwarding-profile-ref]
                      +--rw forwarding-profile-ref    leafref
                      +--rw network-ref?
                              -> /nw:networks/network/network-id

                     Figure 20: Service Tree Structure

Here's what the service data nodes are all about, okay 💅

'mtu': Specifies the Layer 2 MTU, in bytes, for the AC. 🌸

'svc-pe-to-ce-bandwidth' and 'svc-ce-to-pe-bandwidth': Specify the service bandwidth for the AC. 🦋

  • 'svc-pe-to-ce-bandwidth': Indicates the inbound bandwidth of the connection (i.e., download bandwidth from the service provider to the site). 📥
  • 'svc-ce-to-pe-bandwidth': Indicates the outbound bandwidth of the connection (i.e., upload bandwidth from the site to the service provider). 📤

Bestie, 'svc-pe-to-ce-bandwidth' and 'svc-ce-to-pe-bandwidth' can be represented using the Committed Information Rate (CIR), the Committed Burst Size (CBS), the Excess Information Rate (EIR), the Excess Burst Size (EBS), the Peak Information Rate (PIR), and the Peak Burst Size (PBS). CIR, EIR, and PIR are expressed in bps, while CBS, EBS, and PBS are expressed in bytes. 🧮✨

The following types, defined in [RFC9181], can be used to indicate the bandwidth type: 🍓

  • 'bw-per-cos': The bandwidth is per Class of Service (CoS).
  • 'bw-per-port': The bandwidth is per port.
  • 'bw-per-site': The bandwidth is for all peer SAPs that belong to the same site.
  • 'bw-per-service': The bandwidth is per service instance that is bound to an AC.

'qos': Specifies a list of QoS profiles to apply for this AC. 👑

'access-control-list': Specifies a list of ACL profiles to apply for this AC. 🫶


6. YANG Module 🧚

This module uses types defined in [RFC6991], [RFC8177], [RFC8294], [RFC8343], [RFC9067], [RFC9181], [RFC9833], and [IEEE802.1Qcp]. 💜

   <CODE BEGINS> file "ietf-ac-ntw@2025-09-29.yang"
   module ietf-ac-ntw {
     yang-version 1.1;
     namespace "urn:ietf:params:xml:ns:yang:ietf-ac-ntw";
     prefix ac-ntw;

     import ietf-vpn-common {
       prefix vpn-common;
       reference
         "RFC 9181: A Common YANG Data Model for Layer 2 and Layer 3
                    VPNs";
     }
     import ietf-inet-types {
       prefix inet;
       reference
         "RFC 6991: Common YANG Data Types, Section 4";
     }
     import ietf-key-chain {
       prefix key-chain;
       reference
         "RFC 8177: YANG Data Model for Key Chains";
     }
     import ietf-routing-types {
       prefix rt-types;
       reference
         "RFC 8294: Common YANG Data Types for the Routing Area";
     }
     import ietf-routing-policy {
       prefix rt-pol;
       reference
         "RFC 9067: A YANG Data Model for Routing Policy";
     }
     import ietf-interfaces {
       prefix if;
       reference
         "RFC 8343: A YANG Data Model for Interface Management";
     }
     import ieee802-dot1q-types {
       prefix dot1q-types;
       reference
         "IEEE Std 802.1Qcp: Bridges and Bridged Networks--
                             Amendment 30: YANG Data Model";
     }
     import ietf-network {
       prefix nw;
       reference
         "RFC 8345: A YANG Data Model for Network Topologies,
                    Section 6.1";
     }
     import ietf-sap-ntw {
       prefix sap;
       reference
         "RFC 9408: A YANG Network Data Model for Service Attachment
                    Points (SAPs)";
     }
     import ietf-ac-common {
       prefix ac-common;
       reference
         "RFC 9833: A Common YANG Data Model for Attachment Circuits";
     }
     import ietf-ac-svc {
       prefix ac-svc;
       reference
         "RFC 9834: YANG Data Models for Bearers and Attachment
                     Circuits as a Service (ACaaS)";
     }

     organization
       "IETF OPSAWG (Operations and Management Area Working Group)";
     contact
       "WG Web:   <https://datatracker.ietf.org/wg/opsawg/>
        WG List:  <mailto:opsawg@ietf.org>

        Editor:   Mohamed Boucadair
                  <mailto:mohamed.boucadair@orange.com>
        Author:   Richard Roberts
                  <mailto:rroberts@juniper.net>
        Author:   Oscar Gonzalez de Dios
                  <mailto:oscar.gonzalezdedios@telefonica.com>
        Author:   Samier Barguil
                  <mailto:ssamier.barguil_giraldo@nokia.com>
        Author:   Bo Wu
                  <mailto:lana.wubo@huawei.com>";
     description
       "This YANG module defines a YANG network model for the management
        of attachment circuits (ACs).

        Copyright (c) 2025 IETF Trust and the persons identified as
        authors of the code.  All rights reserved.

        Redistribution and use in source and binary forms, with or
        without modification, is permitted pursuant to, and subject
        to the license terms contained in, the Revised BSD License
        set forth in Section 4.c of the IETF Trust's Legal Provisions
        Relating to IETF Documents
        (https://trustee.ietf.org/license-info).

        This version of this YANG module is part of RFC 9835; see the
        RFC itself for full legal notices.";

     revision 2025-09-29 {
       description
         "Initial revision.";
       reference
         "RFC 9835: A YANG Network Data Model for Attachment Circuits";
     }

     // References

     /* A set of groupings to ease referencing cross-modules */

     grouping attachment-circuit-reference {
       description
         "This grouping can be used to reference an AC in a specific
          node.";
       leaf ac-ref {
         type leafref {
           path "/nw:networks/nw:network[nw:network-id=current()/../"
              + "network-ref]/nw:node[nw:node-id=current()/../"
              + "node-ref]/ac-ntw:ac/ac-ntw:name";
           require-instance false;
         }
         description
           "An absolute reference to an AC.";
       }
       uses nw:node-ref;
     }

     grouping attachment-circuit-references {
       description
         "This grouping can be used to reference a list of ACs in a
          specific node.";
       leaf-list ac-ref {
         type leafref {
           path "/nw:networks/nw:network[nw:network-id=current()/../"
              + "network-ref]/nw:node[nw:node-id=current()/../"
              + "node-ref]/ac-ntw:ac/ac-ntw:name";
           require-instance false;
         }
         description
           "An absolute reference to an AC.";
       }
       uses nw:node-ref;
     }

     grouping ac-profile-reference {
       description
         "This grouping can be used to reference an AC profile.";
       leaf ac-profile-ref {
         type leafref {
           path "/nw:networks/nw:network[nw:network-id=current()/../"
              + "network-ref]/ac-ntw:ac-profile/ac-ntw:name";
           require-instance false;
         }
         description
           "An absolute reference to an AC.";
       }
       uses nw:network-ref;
     }

     grouping encryption-profile-reference {
       description
         "This grouping can be used to reference an encryption
          profile.";
       leaf encryption-profile-ref {
         type leafref {
           path "/nw:networks/nw:network[nw:network-id=current()/../"
              + "network-ref]"
              + "/ac-ntw:specific-provisioning-profiles"
              + "/ac-ntw:valid-provider-identifiers"
              + "/ac-ntw:encryption-profile-identifier/ac-ntw:id";
           require-instance false;
         }
         description
           "An absolute reference to an encryption profile.";
       }
       uses nw:network-ref;
     }

     grouping qos-profile-reference {
       description
         "This grouping can be used to reference a QoS profile.";
       leaf qos-profile-ref {
         type leafref {
           path "/nw:networks/nw:network[nw:network-id=current()/../"
              + "network-ref]"
              + "/ac-ntw:specific-provisioning-profiles"
              + "/ac-ntw:valid-provider-identifiers"
              + "/ac-ntw:qos-profile-identifier/ac-ntw:id";
           require-instance false;
         }
         description
           "An absolute reference to a QoS profile.";
       }
       uses nw:network-ref;
     }

     grouping failure-detection-profile-reference {
       description
         "This grouping can be used to reference a failure detection
          profile.";
       leaf failure-detection-profile-ref {
         type leafref {
           path "/nw:networks/nw:network[nw:network-id=current()/../"
             + "network-ref]"
             + "/ac-ntw:specific-provisioning-profiles"
             + "/ac-ntw:valid-provider-identifiers"
             + "/ac-ntw:failure-detection-profile-identifier/ac-ntw:id";
           require-instance false;
         }
         description
           "An absolute reference to a failure detection profile.";
       }
       uses nw:network-ref;
     }

Okay so bestie, we're picking up right where the YANG module gets into the reference groupings 💅 These two groupings are like little name tags 🎀 They let you point at a forwarding profile or a routing profile, and the path does the detective work to find the exact one under the right network.

     grouping forwarding-profile-reference {
       description
         "This grouping can be used to reference a forwarding profile.";
       leaf forwarding-profile-ref {
         type leafref {
           path "/nw:networks/nw:network[nw:network-id=current()/../"
              + "network-ref]"
              + "/ac-ntw:specific-provisioning-profiles"
              + "/ac-ntw:valid-provider-identifiers"
              + "/ac-ntw:forwarding-profile-identifier/ac-ntw:id";
           require-instance false;
         }
         description
           "An absolute reference to a forwarding profile.";
       }
       uses nw:network-ref;
     }

     grouping routing-profile-reference {
       description
         "This grouping can be used to reference a routing profile.";
       leaf routing-profile-ref {
         type leafref {
           path "/nw:networks/nw:network[nw:network-id=current()/../"
              + "network-ref]"
              + "/ac-ntw:specific-provisioning-profiles"
              + "/ac-ntw:valid-provider-identifiers"
              + "/ac-ntw:routing-profile-identifier/ac-ntw:id";
           require-instance false;
         }
         description
           "An absolute reference to a routing profile.";
       }
       uses nw:network-ref;
     }

     // Layer 2 connection

Next up is the Layer 2 connection grouping, which is the big one 🦋 It's basically the whole L2 story for an AC, from the encapsulation type to the tag tricks and the service choice. The dot1q, priority-tagged, and qinq containers only show up when their matching encap type is picked, thanks to those when checks, so it's giving very organised ✨

     grouping l2-connection {
       description
         "Defines Layer 2 protocols and parameters that are required to
          enable AC connectivity on the network side.";
       container encapsulation {
         description
           "Container for Layer 2 encapsulation.";
         leaf encap-type {
           type identityref {
             base vpn-common:encapsulation-type;
           }
           description
             "Tagged interface type.";
         }
         container dot1q {
           when "derived-from-or-self(../encap-type, "
              + "'vpn-common:dot1q')" {
             description
               "Only applies when the type of the tagged interface is
                'dot1q'.";
           }
           description
             "Tagged interface.";
           uses ac-common:dot1q;
           container tag-operations {
             description
               "Sets the tag manipulation policy for this AC.  It
                defines a set of tag manipulations that allow for the
                insertion, removal, or rewriting of 802.1Q VLAN tags.
                These operations are indicated for the CE-PE direction.
                By default, tag operations are symmetric.  As such, the
                reverse tag operation is assumed on the PE-CE
                direction.";
             choice op-choice {
               description
                 "Selects the tag rewriting policy for an AC.";
               leaf pop {
                 type empty;
                 description
                   "Pop the outer tag.";
               }
               leaf push {
                 type empty;
                 description
                   "Pushes one or two tags defined by the tag-1 and
                    tag-2 leaves.  It is assumed that, absent any
                    policy, the default value of 0 will be used for
                    the Priority Code Point (PCP) setting.";
               }
               leaf translate {
                 type empty;
                 description
                   "Translates the outer tag to one or two tags.  PCP bits
                    are preserved.";
               }
             }
             leaf tag-1 {
               when 'not(../pop)';
               type dot1q-types:vlanid;
               description
                 "A first tag to be used for push or translate
                  operations.  This tag will be used as the outermost
                  tag as a result of the tag operation.";
             }
             leaf tag-1-type {
               type dot1q-types:dot1q-tag-type;
               default "dot1q-types:s-vlan";
               description
                 "Specifies a specific 802.1Q tag type of tag-1.";
             }
             leaf tag-2 {
               when '(../translate)';
               type dot1q-types:vlanid;
               description
                 "A second tag to be used for translation.";
             }
             leaf tag-2-type {
               type dot1q-types:dot1q-tag-type;
               default "dot1q-types:c-vlan";
               description
                 "Specifies a specific 802.1Q tag type of tag-2.";
             }
           }
         }
         container priority-tagged {
           when "derived-from-or-self(../encap-type, "
              + "'vpn-common:priority-tagged')" {
             description
               "Only applies when the type of the tagged interface is
                'priority-tagged'.";
           }
           description
             "Priority tagged container.";
           uses ac-common:priority-tagged;
         }
         container qinq {
           when "derived-from-or-self(../encap-type, "
              + "'vpn-common:qinq')" {
             description
               "Only applies when the type of the tagged interface is
                'QinQ'.";
           }
           description
             "Includes QinQ parameters.";
           uses ac-common:qinq;
           container tag-operations {
             description
               "Sets the tag manipulation policy for this AC.  It
                defines a set of tag manipulations that allow for the
                insertion, removal, or rewriting of 802.1Q VLAN tags.
                These operations are indicated for the CE-PE direction.
                By default, tag operations are symmetric.  As such, the
                reverse tag operation is assumed on the PE-CE
                direction.";
             choice op-choice {
               description
                 "Selects the tag rewriting policy for an AC.";
               leaf pop {
                 type uint8 {
                   range "1|2";
                 }
                 description
                   "Pops one or two tags as a function of the indicated
                    pop value.";
               }
               leaf push {
                 type empty;
                 description
                   "Pushes one or two tags defined by the tag-1 and
                    tag-2 leaves.  It is assumed that, absent any
                    policy, the default value of 0 will be used for
                    PCP setting.";
               }
               leaf translate {
                 type uint8 {
                   range "1|2";
                 }
                 description
                   "Translates one or two outer tags.  PCP bits are
                    preserved.  The following operations are supported:

                    - translate 1 with tag-1 leaf is provided: only the
                      outermost tag is translated to the value in tag-1.

                    - translate 2 with both tag-1 and tag-2 leaves are
                      provided: both outer and inner tags are translated
                      to the values in tag-1 and tag-2, respectively.

                    - translate 2 with tag-1 leaf is provided: the
                      outer tag is popped while the inner tag is
                      translated to the value in tag-1.";
               }
             }
             leaf tag-1 {
               when 'not(../pop)';
               type dot1q-types:vlanid;
               description
                 "A first tag to be used for push or translate
                  operations.  This tag will be used as the outermost
                  tag as a result of the tag operation.";
             }
             leaf tag-1-type {
               type dot1q-types:dot1q-tag-type;
               default "dot1q-types:s-vlan";
               description
                 "Specifies a specific 802.1Q tag type of tag-1.";
             }
             leaf tag-2 {
               when 'not(../pop)';
               type dot1q-types:vlanid;
               description
                 "A second tag to be used for push or translate
                  operations.";
             }
             leaf tag-2-type {
               type dot1q-types:dot1q-tag-type;
               default "dot1q-types:c-vlan";
               description
                 "Specifies a specific 802.1Q tag type of tag-2.";
             }
           }
         }
       }
       choice l2-service {
         description
           "The Layer 2 connectivity service can be provided by
            indicating a pointer to an L2VPN or by specifying a Layer 2
            tunnel service.";
         container l2-tunnel-service {
           description
             "Defines a Layer 2 tunnel termination.";
           uses ac-common:l2-tunnel-service;
         }
         case l2vpn {
           leaf l2vpn-id {
             type vpn-common:vpn-id;
             description
               "Indicates the L2VPN service associated with an
                Integrated Routing and Bridging (IRB) interface.";
           }
         }
       }
     }

Last up in this part is l2-connection-if-ref, which wraps the L2 stuff with interface references 🧚 It adds the termination point, a local bridge reference, an optional bearer reference, and a LAG container with its member links. Lots of little pieces, all tucked in neatly 🌸

     grouping l2-connection-if-ref {
       description
         "Specifies Layer 2 connection parameters with interface
          references.";
       uses l2-connection;
       leaf l2-termination-point {
         type string;
         description
           "Specifies a reference to a local Layer 2 termination point,
            such as a Layer 2 sub-interface.";
       }
       leaf local-bridge-reference {
         type string;
         description
           "Specifies a local bridge reference to accommodate, e.g.,
            implementations that require internal bridging.
            A reference may be a local bridge domain.";
       }
       leaf bearer-reference {
         if-feature "ac-common:server-assigned-reference";
         type string;
         description
           "This is an internal reference for the service provider to
            identify the bearer associated with this AC.";
       }
       container lag-interface {
         if-feature "vpn-common:lag-interface";
         description
           "Container for configuration of Link Aggregation Group (LAG)
            interface attributes.";
         leaf lag-interface-id {
           type string;
           description
             "LAG interface identifier.";
         }
         container member-link-list {
           description
             "Container for the member link list.";
           list member-link {
             key "name";
             description
               "Member link.";
             leaf name {
               type string;
               description
                 "Member link name.";
             }
           }
         }
       }
     }

     // IPv4 connection

okay bestie, the IPv4 and IPv6 groupings are literal twins 👯‍♀️ same vibe, just different address types ✨

     grouping ipv4-connection {
       description
         "IPv4-specific connection parameters.";
       leaf local-address {
         type inet:ipv4-address;
         description
           "The IPv4 address used at the provider's interface.";
       }
       uses ac-common:ipv4-allocation-type;
       choice allocation-type {
         description
           "Choice of the IPv4 address allocation.";
         case dynamic {
           description
             "When the addresses are allocated by DHCP or other
              dynamic means local to the infrastructure.";
           choice address-assign {
             description
               "A choice for how IPv4 addresses are assigned.";
             case number {
               leaf number-of-dynamic-address {
                 type uint16;
                 description
                   "Specifies the number of IP addresses to be
                    assigned to the customer on this access.";
               }
             }
             case explicit {
               container customer-addresses {
                 description
                   "Container for customer addresses to be allocated
                    using DHCP.";
                 list address-pool {
                   key "pool-id";
                   description
                     "Describes IP addresses to be dynamically
                      allocated.

                      When only 'start-address' is present, it
                      represents a single address.

                      When both 'start-address' and 'end-address' are
                      specified, it implies a range inclusive of both
                      addresses.";
                   leaf pool-id {
                     type string;
                     description
                       "A pool identifier for the address range from
                        'start-address' to 'end-address'.";
                   }
                   leaf start-address {
                     type inet:ipv4-address;
                     mandatory true;
                     description
                       "Indicates the first address in the pool.";
                   }
                   leaf end-address {
                     type inet:ipv4-address;
                     description
                       "Indicates the last address in the pool.";
                   }
                 }
               }
             }
           }
           choice provider-dhcp {
             description
               "Parameters related to DHCP-allocated addresses.
                IP addresses are allocated by DHCP, which is provided
                by the operator.";
             leaf dhcp-service-type {
               type enumeration {
                 enum server {
                   description
                     "Local DHCP server.";
                 }
                 enum relay {
                   description
                     "Local DHCP relay.  DHCP requests are relayed to a
                      provider's server.";
                 }
               }
               description
                 "Indicates the type of DHCP service to be enabled on
                  this access.";
             }
             choice service-type {
               description
                 "Choice based on the DHCP service type.";
               case relay {
                 description
                   "Container for a list of the provider's DHCP servers
                    (i.e., 'dhcp-service-type' is set to 'relay').";
                 leaf-list server-ip-address {
                   type inet:ipv4-address;
                   description
                     "IPv4 addresses of the provider's DHCP server, for
                      use by the local DHCP relay.";
                 }
               }
             }
           }
           choice dhcp-relay {
             description
               "The DHCP relay is provided by the operator.";
             container customer-dhcp-servers {
               description
                 "Container for a list of the customer's DHCP servers.";
               leaf-list server-ip-address {
                 type inet:ipv4-address;
                 description
                   "IPv4 addresses of the customer's DHCP server.";
               }
             }
           }
         }
         case static-addresses {
           description
             "Lists the static IPv4 addresses that are used.";
           list address {
             key "address-id";
             ordered-by user;
             description
               "Lists the IPv4 addresses that are used.  The first
                address of the list is the primary address of the
                connection.";
             leaf address-id {
               type string;
               description
                 "An identifier of the static IPv4 address.";
             }
             leaf customer-address {
               type inet:ipv4-address;
               description
                 "An IPv4 address of the customer side.";
             }
             uses failure-detection-profile-reference;
           }
         }
       }
     }

     grouping ipv6-connection {
       description
         "IPv6-specific connection parameters.";
       leaf local-address {
         type inet:ipv6-address;
         description
           "IPv6 address of the provider side.";
       }
       uses ac-common:ipv6-allocation-type;
       choice allocation-type {
         description
           "Choice of the IPv6 address allocation.";
         case dynamic {
           description
             "When the addresses are allocated by DHCP or other
              dynamic means local to the infrastructure.";
           choice address-assign {
             description
               "A choice for how IPv6 addresses are assigned.";
             case number {
               leaf number-of-dynamic-address {
                 type uint16;
                 description
                   "Specifies the number of IP addresses to be
                    assigned to the customer on this access.";
               }
             }
             case explicit {
               container customer-addresses {
                 description
                   "Container for customer addresses to be allocated
                    using DHCP.";
                 list address-pool {
                   key "pool-id";
                   description
                     "Describes IPv6 addresses to be dynamically
                      allocated.

                      When only 'start-address' is present, it
                      represents a single address.

                      When both 'start-address' and 'end-address' are
                      specified, it implies a range inclusive of both
                      addresses.";
                   leaf pool-id {
                     type string;
                     description
                       "A pool identifier for the address range from
                        'start-address' to 'end-address'.";
                   }
                   leaf start-address {
                     type inet:ipv6-address;
                     mandatory true;
                     description
                       "Indicates the first address in the pool.";
                   }
                   leaf end-address {
                     type inet:ipv6-address;
                     description
                       "Indicates the last address in the pool.";
                   }
                 }
               }
             }
           }
           choice provider-dhcp {
             description
               "Parameters related to DHCP-allocated addresses.
                IP addresses are allocated by DHCP, which is provided
                by the operator.";
             leaf dhcp-service-type {
               type enumeration {
                 enum server {
                   description
                     "Local DHCP server.";
                 }
                 enum relay {
                   description
                     "Local DHCP relay.  DHCP requests are relayed to
                      a provider's server.";
                 }
               }
               description
                 "Indicates the type of DHCP service to be enabled on
                  this access.";
             }
             choice service-type {
               description
                 "Choice based on the DHCP service type.";
               case relay {
                 description
                   "Container for a list of the provider's DHCP servers
                    (i.e., 'dhcp-service-type' is set to 'relay').";
                 leaf-list server-ip-address {
                   type inet:ipv6-address;
                   description
                     "IPv6 addresses of the provider's DHCP server, for
                      use by the local DHCP relay.";
                 }
               }
             }
           }
           choice dhcp-relay {
             description
               "The DHCP relay is provided by the operator.";
             container customer-dhcp-servers {
               description
                 "Container for a list of the customer's DHCP servers.";
               leaf-list server-ip-address {
                 type inet:ipv6-address;
                 description
                   "IPv6 addresses of the customer's DHCP servers.";
               }
             }
           }
         }
         case static-addresses {
           description
             "Lists the static IPv6 addresses that are used.";
           list address {
             key "address-id";
             ordered-by user;
             description
               "Lists the IPv6 addresses that are used.  The first
                address of the list is the primary address of
                the connection.";
             leaf address-id {
               type string;
               description
                 "An identifier of the static IPv6 address.";
             }
             leaf customer-address {
               type inet:ipv6-address;
               description
                 "An IPv6 address of the customer side.";
             }
             uses failure-detection-profile-reference;
           }
         }
       }
     }

     grouping ip-connection {
       description
         "Defines IP connection parameters.";
       leaf l3-termination-point {
         type string;
         description
           "Specifies a reference to a local Layer 3 termination point,
            such as a bridge domain interface.";
       }
       container ipv4 {
         if-feature "vpn-common:ipv4";
         description
           "IPv4-specific connection parameters.";
         uses ipv4-connection;
       }
       container ipv6 {
         if-feature "vpn-common:ipv6";
         description
           "IPv6-specific connection parameters.";
         uses ipv6-connection;
       }
     }

     /* Routing */
     //BGP base parameters

okay so we're still deep in the YANG module and it's giving BGP and RIP realness 🦋 this chunk is all about the knobs you can turn on a BGP session, how those knobs get bundled into peer groups, and the RIP timers 💅 the descriptions are doing the heavy lifting here so I'm keeping every single one word for word 🫶

bgp-base is the main bundle of BGP settings, like the session description, the ASNs, the role, the prefix limits, and the timers ⏱️ then bgp-base-peer-group and bgp-peer-group wrap those settings up so you can apply them to a named group of peers 🌸

     grouping bgp-base {
       description
         "Configuration specific to BGP.";
       leaf description {
         type string;
         description
           "Includes a description of the BGP session.  This description
            is meant to be used for diagnostic purposes.  The semantics
            of the description are local to an implementation.";
       }
       uses rt-pol:apply-policy-group;
       leaf local-as {
         type inet:as-number;
         description
           "Indicates a local Autonomous System Number (ASN), if an ASN
            distinct from the ASN configured at the AC level is
            needed.";
       }
       leaf peer-as {
         type inet:as-number;
         mandatory true;
         description
           "Indicates the customer's ASN when the customer requests BGP
            routing.";
       }
       leaf address-family {
         type identityref {
           base vpn-common:address-family;
         }
         description
           "This node contains the address families to be activated.
            'dual-stack' means that both IPv4 and IPv6 will be
            activated.";
       }
       leaf role {
         type identityref {
           base ac-common:bgp-role;
         }
         description
           "Specifies the BGP role (provider, customer, peer, etc.).";
       }
       leaf multihop {
         type uint8;
         description
           "Describes the number of IP hops allowed between a given BGP
            neighbor and the PE.";
       }
       leaf as-override {
         type boolean;
         description
           "Defines whether ASN override is enabled, i.e., replacing the
            ASN of the customer specified in the AS_PATH attribute with
            the local ASN.";
       }
       leaf allow-own-as {
         type uint8;
         description
           "If set, specifies the maximum number of occurrences of the
            provider's ASN that are permitted within the AS_PATH
            before it is rejected.";
       }
       leaf prepend-global-as {
         type boolean;
         description
           "In some situations, the ASN that is provided at the node
            level may be distinct from the ASN configured at the AC.
            When such ASNs are provided, they are both prepended to the
            BGP route updates for this AC.  To disable that behavior,
            'prepend-global-as' must be set to 'false'.  In such a
            case, the ASN that is provided at the node level is not
            prepended to the BGP route updates for this access.";
       }
       leaf send-default-route {
         type boolean;
         description
           "Defines whether default routes can be advertised to a peer.
            If set to 'true', the default routes are advertised to
            a peer.";
       }
       leaf site-of-origin {
         when "derived-from-or-self(../address-family, "
            + "'vpn-common:ipv4' or 'vpn-common:dual-stack')" {
           description
             "Only applies if IPv4 is activated.";
         }
         type rt-types:route-origin;
         description
           "The Site of Origin attribute is encoded as a Route Origin
            Extended Community.  It is meant to uniquely identify the
            set of routes learned from a site via a particular AC and
            is used to prevent routing loops.";
         reference
           "RFC 4364: BGP/MPLS IP Virtual Private Networks (VPNs),
                      Section 7";
       }
       leaf ipv6-site-of-origin {
         when "derived-from-or-self(../address-family, "
            + "'vpn-common:ipv6' or 'vpn-common:dual-stack')" {
           description
             "Only applies if IPv6 is activated.";
         }
         type rt-types:ipv6-route-origin;
         description
           "The IPv6 Site of Origin attribute is encoded as an IPv6
            Route Origin Extended Community.  It is meant to uniquely
            identify the set of routes learned from a site.";
         reference
           "RFC 5701: IPv6 Address Specific BGP Extended Community
                      Attribute";
       }
       list redistribute-connected {
         key "address-family";
         description
           "Indicates, per address family, the policy to follow for
            connected routes.";
         leaf address-family {
           type identityref {
             base vpn-common:address-family;
           }
           description
             "Indicates the address family.";
         }
         leaf enabled {
           type boolean;
           description
             "Enables, when set to 'true', the redistribution of
              connected routes.";
         }
       }
       container bgp-max-prefix {
         description
           "Controls the behavior when a prefix maximum is reached.";
         leaf max-prefix {
           type uint32;
           description
             "Indicates the maximum number of BGP prefixes allowed in
              the BGP session.

              It allows control of how many prefixes can be received
              from a neighbor.

              If the limit is exceeded, the action indicated in
              'violate-action' will be followed.";
           reference
             "RFC 4271: A Border Gateway Protocol 4 (BGP-4),
                        Section 8.2.2";
         }
         leaf warning-threshold {
           type decimal64 {
             fraction-digits 5;
             range "0..100";
           }
           units "percent";
           description
             "When this value is reached, a warning notification will be
              triggered.";
         }
         leaf violate-action {
           type enumeration {
             enum warning {
               description
                 "Only a warning message is sent to the peer when the
                  limit is exceeded.";
             }
             enum discard-extra-paths {
               description
                 "Discards extra paths when the limit is exceeded.";
             }
             enum restart {
               description
                 "The BGP session restarts after the indicated time
                  interval.";
             }
           }
           description
             "If the BGP neighbor 'max-prefix' limit is reached, the
              action indicated in 'violate-action' will be followed.";
         }
         leaf restart-timer {
           type uint32;
           units "seconds";
           description
             "Time interval after which the BGP session will be
              reestablished.";
         }
       }
       container bgp-timers {
         description
           "Includes two BGP timers.";
         leaf keepalive {
           type uint16 {
             range "0..21845";
           }
           units "seconds";
           description
             "This timer indicates the KEEPALIVE messages' frequency
              between a PE and a BGP peer.

              If set to '0', it indicates that KEEPALIVE messages are
              disabled.

              It is suggested that the maximum time between KEEPALIVE
              messages be one-third of the Hold Time interval.";
           reference
             "RFC 4271: A Border Gateway Protocol 4 (BGP-4),
                        Section 4.4";
         }
         leaf hold-time {
           type uint16 {
             range "0 | 3..65535";
           }
           units "seconds";
           description
             "Indicates the maximum number of seconds that may elapse
              between the receipt of successive KEEPALIVE and/or UPDATE
              messages from the peer.

              The Hold Time must be either zero or at least three
              seconds.";
           reference
             "RFC 4271: A Border Gateway Protocol 4 (BGP-4),
                        Section 4.2";
         }
       }
     }

     grouping bgp-base-peer-group {
       description
         "Grouping for a basic BGP peer group.";
       leaf name {
         type string;
         description
           "Name of the BGP peer group.";
       }
       uses bgp-base;
     }

     grouping bgp-base-peer-group-list {
       description
         "Grouping for a list of basic BGP peer groups.";
       list peer-group {
         key "name";
         description
           "List of BGP peer groups uniquely identified by a name.";
         uses bgp-base-peer-group;
       }
     }

     grouping bgp-peer-group {
       description
         "Grouping for BGP peer group.";
       leaf name {
         type string;
         description
           "Name of the BGP peer group";
       }
       leaf local-address {
         type union {
           type inet:ip-address;
           type if:interface-ref;
         }
         description
           "Sets the local IP address to use for the BGP transport
            session.  This may be expressed as either an IP
            address or a reference to an interface.";
       }
       uses bgp-base;
       uses ac-common:bgp-authentication;
     }

     grouping bgp-peer-group-list {
       description
         "Grouping for a list of BGP peer groups.";
       list peer-group {
         key "name";
         description
           "List of BGP peer groups uniquely identified by a name.";
         uses bgp-peer-group;
       }
     }

     // RIP base parameters

     grouping rip-base {
       description
         "Configuration specific to RIP routing.";
       leaf address-family {
         type identityref {
           base vpn-common:address-family;
         }
         description
           "Indicates whether IPv4, IPv6, or both address families are
            to be activated.";
       }
       container timers {
         description
           "Indicates the RIP timers.";
         reference
           "RFC 2080: RIPng for IPv6
            RFC 2453: RIP Version 2";
         leaf update-interval {
           type uint16 {
             range "1..32767";
           }
           units "seconds";
           description
             "Indicates the RIP update time, i.e., the amount of time
              for which RIP updates are sent.";
         }
         leaf invalid-interval {
           type uint16 {
             range "1..32767";
           }
           units "seconds";
           description
             "The interval before a route is declared invalid after no
              updates are received.  This value is at least three times
              the value for the 'update-interval' argument.";
         }
         leaf holddown-interval {
           type uint16 {
             range "1..32767";
           }
           units "seconds";
           description
             "Specifies the interval before better routes are
              released.";
         }
         leaf flush-interval {
           type uint16 {
             range "1..32767";
           }
           units "seconds";
           description
             "Indicates the RIP flush timer, i.e., the amount of time
              that must elapse before a route is removed from the
              routing table.";
         }
       }
       leaf default-metric {
         type uint8 {
           range "0..16";
         }
         description
           "Sets the default metric.";
       }
     }

     // Routing profile

and that's where this part ends, right at // Routing profile 🥺 the next bit is where the routing profile gets built up, so stay tuned bestie 🎀✨

okay bestie, this part is all YANG 💅 The routing-profile grouping is basically a menu of routing protocols. Each one gets its own container (BGP, OSPF, IS-IS, RIP, and VRRP 🦋), and each container only applies when the type matches, plus it's gated by its own feature. ✨

     grouping routing-profile {
       description
         "Defines profiles for routing protocols.";
       list routing-protocol {
         key "id";
         description
           "List of routing protocols used on the AC.";
         leaf id {
           type string;
           description
             "Unique identifier for the routing protocol.";
         }
         leaf type {
           type identityref {
             base vpn-common:routing-protocol-type;
           }
           description
             "Type of routing protocol.";
         }
         container bgp {
           when "derived-from-or-self(../type, "
              + "'vpn-common:bgp-routing')" {
             description
               "Only applies when the protocol is BGP.";
           }
           if-feature "vpn-common:rtg-bgp";
           description
             "Configuration specific to BGP.";
           container peer-groups {
             description
               "Lists a set of BGP peer groups.";
             uses bgp-base-peer-group-list;
           }
         }
         container ospf {
           when "derived-from-or-self(../type, "
              + "'vpn-common:ospf-routing')" {
             description
               "Only applies when the protocol is OSPF.";
           }
           if-feature "vpn-common:rtg-ospf";
           description
             "Configuration specific to OSPF.";
           uses ac-common:ospf-basic;
           leaf max-lsa {
             type uint32 {
               range "1..4294967294";
             }
             description
               "Maximum number of allowed Link State Advertisements
                (LSAs) that the OSPF instance will accept.";
           }
           leaf passive {
             type boolean;
             description
               "When set to 'true', enables a passive interface.  It is
                active when set to 'false'.  A passive interface's
                prefix will be advertised, but no neighbor adjacencies
                will be formed on the interface.";
           }
         }
         container isis {
           when "derived-from-or-self(../type, "
              + "'vpn-common:isis-routing')" {
             description
               "Only applies when the protocol is IS-IS.";
           }
           if-feature "vpn-common:rtg-isis";
           description
             "Configuration specific to IS-IS.";
           uses ac-common:isis-basic;
           leaf level {
             type identityref {
               base vpn-common:isis-level;
             }
             description
               "Can be 'level-1', 'level-2', or 'level-1-2'.";
             reference
               "RFC 9181: A Common YANG Data Model for Layer 2
                          and Layer 3 VPNs";
           }
           leaf metric {
             type uint32 {
               range "0 .. 16777215";
             }
             description
               "Metric of the AC.  It is used in the routing state
                calculation and path selection.";
           }
           leaf passive {
             type boolean;
             description
               "When set to 'false', the interface is active.  In such
                mode, the interface sends or receives IS-IS protocol
                control packets.

                When set to 'true', the interface is passive.  That
                is, it suppresses the sending of IS-IS updates through
                the specified interface.";
           }
         }
         container rip {
           when "derived-from-or-self(../type, "
              + "'vpn-common:rip-routing')" {
             description
               "Only applies when the protocol is RIP.";
           }
           if-feature "vpn-common:rtg-rip";
           description
             "Configuration specific to RIP routing.";
           uses rip-base;
         }
         container vrrp {
           when "derived-from-or-self(../type, "
              + "'vpn-common:vrrp-routing')" {
             description
               "Only applies when the protocol is the Virtual Router
                Redundancy Protocol (VRRP).";
           }
           if-feature "vpn-common:rtg-vrrp";
           description
             "Configuration specific to VRRP.";
           reference
             "RFC 9568: Virtual Router Redundancy Protocol (VRRP)
                        Version 3 for IPv4 and IPv6";
           leaf address-family {
             type identityref {
               base vpn-common:address-family;
             }
             description
               "Indicates whether IPv4, IPv6, or both address families
                are to be enabled.";
           }
           leaf ping-reply {
             type boolean;
             description
               "Controls whether the VRRP speaker should reply to ping
                requests.  Such behavior is enabled, if set to 'true'.";
           }
         }
       }
     }

grouping routing { description "Defines routing protocols."; list routing-protocol { key "id"; description "List of routing protocols used on the AC."; leaf id { type string; description "Unique identifier for the routing protocol."; } leaf type { type identityref { base vpn-common:routing-protocol-type; } description "Type of routing protocol."; } list routing-profile { key "routing-profile-ref"; description "Routing profiles."; uses routing-profile-reference; leaf type { type identityref { base vpn-common:ie-type; } description "Import, export, or both."; } } container static { when "derived-from-or-self(../type, "

  • "'vpn-common:static-routing')" { description "Only applies when the protocol is static routing."; } description "Configuration specific to static routing."; container cascaded-lan-prefixes { description "LAN prefixes from the customer."; list ipv4-lan-prefix { if-feature "vpn-common:ipv4"; key "lan next-hop"; description "List of LAN prefixes for the site."; uses ac-common:ipv4-static-rtg-entry; uses bfd-routing; leaf preference { type uint32; description "Indicates the preference associated with the static route."; } uses ac-common:service-status; } list ipv6-lan-prefix { if-feature "vpn-common:ipv6"; key "lan next-hop"; description "List of LAN prefixes for the site."; uses ac-common:ipv6-static-rtg-entry; uses bfd-routing; leaf preference { type uint32; description "Indicates the preference associated with the static route."; } uses ac-common:service-status; } } } container bgp { when "derived-from-or-self(../type, "
  • "'vpn-common:bgp-routing')" { description "Only applies when the protocol is BGP."; } if-feature "vpn-common:rtg-bgp"; description "Configuration specific to BGP."; container peer-groups { description "Configuration for BGP peer groups"; uses bgp-peer-group-list; } list neighbor { key "remote-address"; description "List of BGP neighbors."; leaf remote-address { type inet:ip-address; description "The remote IP address of this entry's BGP peer."; } leaf local-address { type union { type inet:ip-address; type if:interface-ref; } description "Sets the local IP address to use for the BGP transport session. This may be expressed as either an IP address or a reference to an interface."; } leaf peer-group { type leafref { path "../../peer-groups/peer-group/name"; } description "The peer group with which this neighbor is associated."; } uses bgp-base; uses bfd-routing; uses ac-common:bgp-authentication; uses ac-common:service-status; } } container ospf { when "derived-from-or-self(../type, "
  • "'vpn-common:ospf-routing')" { description "Only applies when the protocol is OSPF."; } if-feature "vpn-common:rtg-ospf"; description "Configuration specific to OSPF."; uses ac-common:ospf-basic; container sham-links { if-feature "vpn-common:rtg-ospf-sham-link"; description "List of sham links."; reference "RFC 4577: OSPF as the Provider/Customer Edge Protocol for BGP/MPLS IP Virtual Private Networks (VPNs), Section 4.2.7 RFC 6565: OSPFv3 as a Provider Edge to Customer Edge (PE-CE) Routing Protocol, Section 5"; list sham-link { key "target-site"; description "Creates a sham link with another site."; leaf target-site { type string; description "Target site for the sham link connection. The site is referred to by its identifier."; } leaf metric { type uint16; description "Metric of the sham link. It is used in the routing state calculation and path selection."; reference "RFC 4577: OSPF as the Provider/Customer Edge Protocol for BGP/MPLS IP Virtual Private Networks (VPNs), Section 4.2.7.3 RFC 6565: OSPFv3 as a Provider Edge to Customer Edge (PE-CE) Routing Protocol, Section 5.2"; } } } leaf max-lsa { type uint32 { range "1..4294967294"; } description "Maximum number of allowed Link State Advertisements (LSAs) that the OSPF instance will accept."; } leaf passive { type boolean; description "When set to 'true', enables a passive interface. It is active when set to 'false'. A passive interface's prefix will be advertised, but no neighbor adjacencies will be formed on the interface."; } uses ac-common:ospf-authentication; uses ac-common:service-status; } container isis { when "derived-from-or-self(../type, "
  • "'vpn-common:isis-routing')" { description "Only applies when the protocol is IS-IS."; } if-feature "vpn-common:rtg-isis"; description "Configuration specific to IS-IS."; uses ac-common:isis-basic; leaf level { type identityref { base vpn-common:isis-level; } description "Can be 'level-1', 'level-2', or 'level-1-2'."; reference "RFC 9181: A Common YANG Data Model for Layer 2 and Layer 3 VPNs"; } leaf metric { type uint32 { range "0 .. 16777215"; } description "Metric of the AC. It is used in the routing state calculation and path selection."; } leaf passive { type boolean; description "When set to 'false', the interface is active. In such mode, the interface sends or receives IS-IS protocol control packets.

When set to 'true', the interface is passive. That is, it suppresses the sending of IS-IS updates through the specified interface."; } uses ac-common:isis-authentication; uses ac-common:service-status; } container rip { when "derived-from-or-self(../type, "

  • "'vpn-common:rip-routing')" { description "Only applies when the protocol is RIP. For IPv4, the model assumes that RIP version 2 is used."; } if-feature "vpn-common:rtg-rip"; description "Configuration specific to RIP routing."; uses rip-base; uses ac-common:rip-authentication; uses ac-common:service-status; } container vrrp { when "derived-from-or-self(../type, "
  • "'vpn-common:vrrp-routing')" { description "Only applies when the protocol is VRRP."; } if-feature "vpn-common:rtg-vrrp"; description "Configuration specific to VRRP."; reference "RFC 9568: Virtual Router Redundancy Protocol (VRRP) Version 3 for IPv4 and IPv6"; leaf address-family { type identityref { base vpn-common:address-family; } description "Indicates whether IPv4, IPv6, or both address families are to be enabled."; } leaf vrrp-group { type uint8 { range "1..255"; } description "Includes the VRRP group identifier."; } leaf backup-peer { type inet:ip-address; description "Indicates the IP address of the peer."; } leaf-list virtual-ip-address { type inet:ip-address; description "Virtual IP addresses for a single VRRP group."; reference "RFC 9568: Virtual Router Redundancy Protocol (VRRP) Version 3 for IPv4 and IPv6, Sections 1.2 and 1.3"; } leaf priority { type uint8 { range "1..254"; } description "Sets the local priority of the VRRP speaker."; } leaf ping-reply { type boolean; description "Controls whether the VRRP speaker should reply to ping requests."; } uses ac-common:service-status; } } }

// OAM

grouping bfd { description "Grouping for BFD."; leaf session-type { type identityref { base vpn-common:bfd-session-type; } description "Specifies the BFD session type."; } leaf desired-min-tx-interval { type uint32; units "microseconds"; description "The minimum interval between transmissions of BFD Control packets, as desired by the operator."; reference "RFC 5880: Bidirectional Forwarding Detection (BFD), Section 6.8.7"; } leaf required-min-rx-interval { type uint32; units "microseconds"; description "The minimum interval between received BFD Control packets that the PE should support."; reference "RFC 5880: Bidirectional Forwarding Detection (BFD), Section 6.8.7"; } leaf local-multiplier { type uint8 { range "1..255"; } description "Specifies the detection multiplier that is transmitted to a

okay bestie, the BFD stuff keeps going and it is so detailed 🫶 here's the next chunk of the YANG module 💅✨

            The detection interval for the receiving BFD peer is
            calculated by multiplying the value of the negotiated
            transmission interval by the received detection multiplier
            value.";
         reference
           "RFC 5880: Bidirectional Forwarding Detection (BFD),
                      Section 6.8.7";
       }
       leaf holdtime {
         type uint32;
         units "milliseconds";
         description
           "Expected BFD holdtime.

            The customer may impose some fixed values for the holdtime
            period if the provider allows the customer to use this
            function.";
         reference
           "RFC 5880: Bidirectional Forwarding Detection (BFD),
                      Section 6.8.18";
       }
     }

     grouping bfd-routing {
       description
         "Defines a basic BFD grouping for routing configuration.";
       container bfd {
         if-feature "vpn-common:bfd";
         description
           "BFD control for this neighbor.";
         leaf enabled {
           type boolean;
           description
             "Enables BFD if set to 'true'. BFD is disabled if set to
              'false'.";
         }
         uses failure-detection-profile-reference;
       }
     }

     grouping oam {
       description
         "Defines the Operations, Administration, and Maintenance
          (OAM) mechanisms used.";
       container bfd {
         if-feature "vpn-common:bfd";
         description
           "Container for BFD.";
         list session {
           key "dest-addr";
           description
             "List of IP sessions.";
           leaf dest-addr {
             type inet:ip-address;
             description
               "IP address of the peer.";
           }
           leaf source-address {
             type union {
               type inet:ip-address;
               type if:interface-ref;
             }
             description
               "Sets the local IP address to use for the BFD session.
                This may be expressed as either an IP address or
                a reference to an interface.";
           }
           uses failure-detection-profile-reference;
           uses bfd;
           container authentication {
             presence "Enables BFD authentication";
             description
               "Parameters for BFD authentication.";
             leaf key-chain {
               type key-chain:key-chain-ref;
               description
                 "Name of the key chain.";
             }
             leaf meticulous {
               type boolean;
               description
                 "Enables meticulous mode, if set to 'true'.";
               reference
                 "RFC 5880: Bidirectional Forwarding Detection (BFD),
                            Section 6.7";
             }
           }
           uses ac-common:service-status;
         }
       }
     }

     // Security

     grouping security {
       description
         "Security parameters for an AC.";
       container encryption {
         if-feature "vpn-common:encryption";
         description
           "Container for AC encryption.";
         leaf enabled {
           type boolean;
           description
             "If set to 'true', traffic encryption on the connection is
              required.  Otherwise, it is disabled.";
         }
         leaf layer {
           when "../enabled = 'true'" {
             description
               "Included only when encryption is enabled.";
           }
           type enumeration {
             enum layer2 {
               description
                 "Encryption occurs at Layer 2.";
             }
             enum layer3 {
               description
                 "Encryption occurs at Layer 3.  For example, IPsec
                  may be used when a customer requests Layer 3
                  encryption.";
             }
           }
           description
             "Indicates the layer on which encryption is applied.";
         }
       }
       container encryption-profile {
         when "../encryption/enabled = 'true'" {
           description
             "Indicates the layer on which encryption is enabled.";
         }
         description
           "Container for the encryption profile.";
         choice profile {
           description
             "Choice for the encryption profile.";
           case provider-profile {
             uses encryption-profile-reference;
           }
           case customer-profile {
             leaf customer-key-chain {
               type key-chain:key-chain-ref;
               description
                 "Customer-supplied key chain.";
             }
           }
         }
       }
     }

     // AC profile

     grouping ac-profile {
       description
         "Grouping for AC profiles.";
       container routing-protocols {
         description
           "Defines routing protocols.";
         uses routing-profile;
       }
       container oam {
         description
           "Defines the OAM mechanisms used for the AC profile.";
         container bfd {
           if-feature "vpn-common:bfd";
           description
             "Container for BFD.";
           uses bfd;
         }
       }
     }

     // Parent and Child ACs

     grouping ac-hierarchy {
       description
         "Container for Parent and Child AC references.";
       container parent-ref {
         description
           "Specifies the Parent AC that is inherited by an AC.
            Parent ACs are used, e.g., in contexts where multiple
            CEs are terminating the same AC, but some specific
            information is required for each peer SAP.";
         uses ac-ntw:attachment-circuit-reference;
       }
       container child-ref {
         config false;
         description
           "Specifies a Child AC that relies upon a Parent AC.";
         uses ac-ntw:attachment-circuit-references;
       }
     }

     // AC network provisioning

     grouping ac {
       description
         "Grouping for ACs.";
       leaf description {
         type string;
         description
           "Associates a description with an AC.";
       }
       container l2-connection {
         if-feature "ac-common:layer2-ac";
         description
           "Defines Layer 2 protocols and parameters that are required
            to enable AC connectivity.";
         uses l2-connection-if-ref;
       }
       container ip-connection {
         if-feature "ac-common:layer3-ac";
         description
           "Defines IP connection parameters.";
         uses ip-connection;
       }
       container routing-protocols {
         description
           "Defines routing protocols.";
         uses routing;
       }
       container oam {
         description
           "Defines the OAM mechanisms used for the AC.";
         uses oam;
       }
       container security {
         description
           "AC-specific security parameters.";
         uses security;
       }
       container service {
         description
           "AC-specific bandwidth parameters.";
         leaf mtu {
           type uint32;
           units "bytes";
           description
             "Layer 2 MTU.";
         }
         uses ac-svc:bandwidth;
         container qos {
           if-feature "vpn-common:qos";
           description
             "QoS configuration.";
           container qos-profiles {
             description
               "QoS profile configuration.";
             list qos-profile {
               key "qos-profile-ref";
               description
                 "Points to a QoS profile.";
               uses qos-profile-reference;
               leaf direction {
                 type identityref {
                   base vpn-common:qos-profile-direction;
                 }
                 description
                   "The direction to which the QoS profile is applied.";
               }
             }
           }
         }
         container access-control-list {
           description
             "Container for the Access Control List (ACL).";
           container acl-profiles {
             description
               "ACL profile configuration.";
             list acl-profile {
               key "forwarding-profile-ref";
               description
                 "Points to an ACL profile.";
               uses forwarding-profile-reference;
             }
           }
         }
       }
     }

     augment "/nw:networks/nw:network" {
       description
         "Add a list of profiles.";
       container specific-provisioning-profiles {
         description
           "Contains a set of valid profiles to reference in the AC
            activation.";
         uses ac-common:ac-profile-cfg;
       }
       list ac-profile {
         key "name";
         description
           "Specifies a list of AC profiles.";
         leaf name {
           type string;
           description
             "Name of the AC.";
         }
         uses ac-ntw:ac-profile;
       }
     }

     augment "/nw:networks/nw:network/nw:node" {
       when '../nw:network-types/sap:sap-network' {
         description
           "Augmentation parameters apply only for SAP networks.";
       }
       description
         "Augments nodes with AC provisioning details.";
       list ac {
         key "name";
         description
           "List of ACs.";
         leaf name {
           type string;
           description
             "A name that identifies the AC locally.";
         }
         leaf svc-ref {
           type ac-svc:attachment-circuit-reference;
           description
             "A reference to the AC as exposed at the service level.";
         }
         list profile {
           key "ac-profile-ref";
           description
             "List of AC profiles.";
           uses ac-profile-reference;
         }
         uses ac-hierarchy;
         leaf-list peer-sap-id {
           type string;
           description
             "One or more peer SAPs can be indicated.";
         }
         uses ac-common:redundancy-group;
         uses ac-common:service-status;
         uses ac-ntw:ac;
       }
     }

     augment "/nw:networks/nw:network/nw:node"
           + "/sap:service/sap:sap" {
       when '../../../nw:network-types/sap:sap-network' {
         description
           "Augmentation parameters apply only for SAP networks.";
       }
       description
         "Augments SAPs with AC provisioning details.";
       list ac {
         key "ac-ref";
         description
           "Specifies the ACs that are terminated by the SAP.";
         uses ac-ntw:attachment-circuit-reference;
       }
     }
   }
   <CODE ENDS>
the vibe check: this chunk is all about BFD timers, encryption at Layer 2 vs Layer 3 (IPsec shows up for the Layer 3 kind 🔐), and how the AC gets its profiles, QoS and ACLs stacked on top ✨

7. Security Considerations 🔐

Okay bestie, this section is modeled after the template in Section 3.7.1 of [YANG-GUIDELINES], so we're not reinventing the wheel here 💅

The ietf-ac-ntw YANG module is a data model meant to be accessed through YANG-based management protocols, like NETCONF [RFC6241] and RESTCONF [RFC8040]. These protocols have to use a secure transport layer (for example SSH [RFC4252], TLS [RFC8446], and QUIC [RFC9000]) and have to use mutual authentication. Not optional, not negotiable, periodt 🔒

The Network Configuration Access Control Model (NACM) [RFC8341] lets you restrict access for particular NETCONF or RESTCONF users to a preset subset of all the available protocol operations and content. It's giving bouncer at the door 🚪

Now, there are a bunch of data nodes in this module that are writable, creatable, and deletable (that's config true, which is the default). Every writable data node is likely to be pretty sensitive in some network environments 😬 Write operations (like edit-config) and delete operations on these nodes, done without proper protection or authentication, can have a negative effect on network operations. The ones with the most drama are:

  • 'specific-provisioning-profiles': This container holds sensitive data that shapes how an AC gets delivered. For example, an attacker with access to these data nodes might be able to mess with routing policies, QoS policies, or encryption properties. These data nodes are tagged with nacm:default-deny-write [RFC9833], which is the protective move 🛡️
  • 'ac': An attacker who can reach network nodes can do all kinds of chaos, like modifying an AC's attributes (QoS, bandwidth, routing protocols, keying material), which can make the services delivered over that AC malfunction and lead to Service Level Agreement (SLA) violations. An attacker could also try to add a brand-new AC 😭 Using NACM to prevent unauthorized access helps here too, because such activity can be detected by adequately monitoring and tracking network configuration changes.

Some of the readable data nodes in this module may also be sensitive or vulnerable in some network environments, so controlling read access (for example via get, get-config, or notification) to them matters a lot 👀 Specifically:

  • 'ac': Unauthorized access to this subtree can disclose the identity of a customer 'peer-sap-id'.
  • 'l2-connection' and 'ip-connection': An attacker can retrieve privacy-related information, which can be used to track a customer. Disclosing that kind of info may be considered a violation of the customer-provider trust relationship 🫣
  • 'keying-material' and 'customer-key-chain': An attacker can retrieve the cryptographic keys protecting an AC (routing, in particular). Those keys could be used to inject spoofed routing advertisements. Major red flag 🚩

There are no particularly sensitive RPC or action operations, so that's one less thing to stress about ✨

Several data nodes (bgp, ospf, isis, rip, and customer-key-chain) rely on the key chains described in [RFC8177] for authentication purposes. Because of that, the AC network module inherits the security considerations discussed in Section 5 of [RFC8177]. Also, these data nodes support supplying explicit keys as strings in ASCII format. Using keys in hexadecimal string format would give greater key entropy with the same number of key-string octets 🧠 However, that format isn't included in this version of the AC network model, because the underlying device modules don't support it (see [RFC8695]).

Section 5.8 specifies the encryption to be applied to traffic for a given AC 🔐🌸

8. IANA Considerations 🦋

IANA has registered the following URI in the "ns" subregistry within the "IETF XML Registry" [RFC3688]:

URI:  urn:ietf:params:xml:ns:yang:ietf-ac-ntw
Registrant Contact:  The IESG.
XML:  N/A; the requested URI is an XML namespace.

IANA has also registered the following YANG module in the "YANG Module Names" registry [RFC6020] within the "YANG Parameters" registry group:

Name:  ietf-ac-ntw
Maintained by IANA?  N
Namespace:  urn:ietf:params:xml:ns:yang:ietf-ac-ntw
Prefix:  ac-ntw
Reference:  RFC 9835

9. References 📚

9.1. Normative References ✨

okay bestie, this is the list of docs the spec leans on the hardest 🫶 every entry is here with its full details, so you can go find the originals whenever you want 🔥

9.2. Informative References ✨

okay bestie, these are the informative references 📚. They aren't normative, but they're giving background and I'm obsessed 💅


Appendix A. Examples 🎀

A.1. VPLS 🌸

okay so picture this 🦋 we've got two customer terminating points, CE1 and CE2, and we're going to assume the bearers that hook these CEs up to the provider network are already set up. The bearers are labelled right in the figure, so no guessing needed 🫶

                 .-----.   .--------------.   .-----.
      .---.      | PE1 +===+              +===+ PE2 |       .---.
     | CE1+------+"450"|   |     MPLS     |   |"451"+------+ CE2|
     '---'    ^  '-----'   |              |   '-----'   ^  '---'
              |            |     Core     |             |
         Bearer:1234       '--------------'         Bearer:5678

                      Figure 21: Topology Example

The AC service model [RFC9834] is what the provider can use to manage and expose the ACs over those existing bearers, as shown in Figure 22. Slay 💅

{
  "ietf-ac-svc:attachment-circuits": {
    "ac-group-profile": [
      {
        "name": "an-ac-profile",
        "l2-connection": {
          "encapsulation": {
            "type": "ietf-vpn-common:dot1q",
            "dot1q": {
              "tag-type": "ietf-vpn-common:c-vlan",
              "cvlan-id": 550
            }
          }
        },
        "service": {
          "mtu": 1550,
          "svc-pe-to-ce-bandwidth": {
            "bandwidth": [
              {
                "bw-type": "ietf-vpn-common:bw-per-port",
                "cir": "20480000"
              }
            ]
          },
          "svc-ce-to-pe-bandwidth": {
            "bandwidth": [
              {
                "bw-type": "ietf-vpn-common:bw-per-port",
                "cir": "20480000"
              }
            ]
          },
          "qos": {
            "qos-profiles": {
              "qos-profile": [
                {
                  "profile": "QoS_Profile_A",
                  "direction": "ietf-vpn-common:both"
                }
              ]
            }
          }
        }
      }
    ],
    "ac": [
      {
        "name": "ac-1",
        "description": "First attachment",
        "ac-group-profile": [
          "an-ac-profile"
        ],
        "l2-connection": {
          "bearer-reference": "1234"
        }
      },
      {
        "name": "ac-2",
        "description": "Second attachment",
        "ac-group-profile": [
          "an-ac-profile"
        ],
        "l2-connection": {
          "bearer-reference": "5678"
        }
      }
    ]
  }
}

                  Figure 22: ACs Created Using ACaaS

Next up 🧚 the provisioned AC at PE1 can be retrieved with the AC network model, as depicted in Figure 23. A similar query works for the AC at PE2, so you've got this 🌈

{
   "ietf-ac-ntw:ac":[
      {
         "name":"ac-11",
         "svc-ref":"ac-1",
         "peer-sap-id":[
            "ce-1"
         ],
         "status":{
            "admin-status":{
               "status":"ietf-vpn-common:admin-up"
            },
            "oper-status":{
               "status":"ietf-vpn-common:op-up"
            }
         },
         "l2-connection":{
            "encapsulation":{
               "encap-type":"ietf-vpn-common:dot1q",
               "dot1q":{
                  "tag-type":"ietf-vpn-common:c-vlan",
                  "cvlan-id":550
               }
            },
            "bearer-reference":"1234"
         },
         "service":{
            "mtu":1550,
            "svc-pe-to-ce-bandwidth":{
               "bandwidth":[
                  {
                     "bw-type": "ietf-vpn-common:bw-per-port",
                     "cir":"20480000"
                  }
               ]
            },
            "svc-ce-to-pe-bandwidth":{
               "bandwidth":[
                  {
                     "bw-type": "ietf-vpn-common:bw-per-port",
                     "cir":"20480000"
                  }
               ]
            },
            "qos":{
               "qos-profiles":{
                  "qos-profile":[
                     {
                        "qos-profile-ref":"QoS_Profile_A",
                        "network-ref":"example:an-id",
                        "direction":"ietf-vpn-common:both"
                     }
                  ]
               }
            }
         }
      }
   ]
}

      Figure 23: Example of AC Network Response (Message Body)

Also, the AC network model can be used to pull up the list of SAPs that the ACs are bound to, as shown in Figure 23. The response looks like this 👑

{
   "ietf-sap-ntw:service":[
      {
         "service-type":"ietf-vpn-common:vpls",
         "sap":[
            {
               "sap-id":"sap#1",
               "peer-sap-id":[
                  "ce-1"
               ],
               "description":"A parent SAP",
               "attachment-interface":"GE0/6/1",
               "interface-type":"ietf-sap-ntw:phy",
               "role":"ietf-sap-ntw:uni",
               "allows-child-saps":true,
               "sap-status":{
                  "status":"ietf-vpn-common:op-up"
               }
            },
            {
               "sap-id":"sap#11",
               "description":"A child SAP",
               "parent-termination-point":"GE0/6/4",
               "attachment-interface":"GE0/6/4.2",
               "interface-type":"ietf-sap-ntw:logical",
               "encapsulation-type":"ietf-vpn-common:vlan-type",
               "sap-status":{
                  "status":"ietf-vpn-common:op-up"
               },
               "ietf-ac-ntw:ac":[
                  {
                     "ac-ref":"ac-1",
                     "node-ref":"example:pe2",
                     "network-ref":"example:an-id"
                  }
               ]
            }
         ]
      }
   ]
}

       Figure 24: Example of AC Network Response to Retrieve the SAP
                               (Message Body)

A.2. Parent AC 💖

okay so, in the topology from Figure 1, PE2 has a SAP that terminates an AC with two peer SAPs (CE2 and CE5) 👀. To control the data for each of those peer SAPs over that same AC, you can instantiate Child ACs, as shown in Figure 25. it's giving organized 🗂️✨

{
   "ietf-ac-ntw:ac":[
      {
         "name":"ac-1",
         "peer-sap-id":[
            "CE2",
            "CE5"
         ],
         "status":{
            "admin-status":{
               "status":"ietf-vpn-common:admin-up"
            },
            "oper-status":{
               "status":"ietf-vpn-common:op-up"
            }
         },
         "l2-connection":{
            "encapsulation":{
               "encap-type":"ietf-vpn-common:dot1q",
               "dot1q":{
                  "tag-type":"ietf-vpn-common:c-vlan",
                  "cvlan-id":550
               }
            },
            "bearer-reference":"1234"
         }
      },
      {
         "name":"ac-1-to-ce2",
         "parent-ref":{
            "ac-ref":"ac-1",
            "node-ref":"example:pe2",
            "network-ref":"example:an-id"
         },
         "peer-sap-id":[
            "CE2"
         ]
      },
      {
         "name":"ac-1-to-ce5",
         "parent-ref":{
            "ac-ref":"ac-1",
            "node-ref":"example:pe2",
            "network-ref":"example:an-id"
         },
         "peer-sap-id":[
            "CE5"
         ]
      }
   ]
}

Figure 25: Example of Child ACs

Child ACs are the little sisters that keep each peer's data separate 🎀

Figure 26 shows how to bind the Parent AC to a SAP. bestie, this is the glue moment 🫶

{
   "ietf-sap-ntw:service":[
      {
         "service-type":"ietf-vpn-common:l3vpn",
         "sap":[
            {
               "sap-id":"sap#14587",
               "description":"A SAP",
               "parent-termination-point":"GE0/6/4",
               "attachment-interface":"GE0/6/4.2",
               "interface-type":"ietf-sap-ntw:logical",
               "encapsulation-type":"ietf-vpn-common:vlan-type",
               "sap-status":{
                  "status":"ietf-vpn-common:op-up"
               },
               "ietf-ac-ntw:ac":[
                  {
                     "ac-ref":"ac-1",
                     "node-ref":"example:pe2",
                     "network-ref":"example:an-id"
                  }
               ]
            }
         ]
      }
   ]
}

Figure 26: Example of Binding Parent ACs to SAPs


Appendix B. Full Tree 🌳✨

okay the full tree is literally the whole family portrait of the module 📸💅 it starts right here with the module name:

module: ietf-ac-ntw

more of the tree is coming up, so keep your eyes peeled 🧚💜

Okay bestie, the tree keeps going, and it's giving main character energy 🦋✨

     augment /nw:networks/nw:network:
       +--rw specific-provisioning-profiles
       |  +--rw valid-provider-identifiers
       |     +--rw encryption-profile-identifier* [id]
       |     |  +--rw id    string
       |     +--rw qos-profile-identifier* [id]
       |     |  +--rw id    string
       |     +--rw failure-detection-profile-identifier* [id]
       |     |  +--rw id    string
       |     +--rw forwarding-profile-identifier* [id]
       |     |  +--rw id    string
       |     +--rw routing-profile-identifier* [id]
       |        +--rw id    string
       +--rw ac-profile* [name]
          +--rw name                 string
          +--rw routing-protocols
          |  +--rw routing-protocol* [id]
          |     +--rw id      string
          |     +--rw type?   identityref
          |     +--rw bgp {vpn-common:rtg-bgp}?
          |     |  +--rw peer-groups
          |     |     +--rw peer-group* [name]
          |     |        +--rw name                      string
          |     |        +--rw description?              string
          |     |        +--rw apply-policy
          |     |        |  +--rw import-policy*           leafref
          |     |        |  +--rw default-import-policy?
          |     |        |  |       default-policy-type
          |     |        |  +--rw export-policy*           leafref
          |     |        |  +--rw default-export-policy?
          |     |        |          default-policy-type
          |     |        +--rw local-as?                 inet:as-number
          |     |        +--rw peer-as                   inet:as-number
          |     |        +--rw address-family?           identityref
          |     |        +--rw role?                     identityref
          |     |        +--rw multihop?                 uint8
          |     |        +--rw as-override?              boolean
          |     |        +--rw allow-own-as?             uint8
          |     |        +--rw prepend-global-as?        boolean
          |     |        +--rw send-default-route?       boolean
          |     |        +--rw site-of-origin?
          |     |        |       rt-types:route-origin
          |     |        +--rw ipv6-site-of-origin?
          |     |        |       rt-types:ipv6-route-origin
          |     |        +--rw redistribute-connected* [address-family]
          |     |        |  +--rw address-family    identityref
          |     |        |  +--rw enabled?          boolean
          |     |        +--rw bgp-max-prefix
          |     |        |  +--rw max-prefix?          uint32
          |     |        |  +--rw warning-threshold?   decimal64
          |     |        |  +--rw violate-action?      enumeration
          |     |        |  +--rw restart-timer?       uint32
          |     |        +--rw bgp-timers
          |     |           +--rw keepalive?   uint16
          |     |           +--rw hold-time?   uint16
          |     +--rw ospf {vpn-common:rtg-ospf}?
          |     |  +--rw address-family?   identityref
          |     |  +--rw area-id           yang:dotted-quad
          |     |  +--rw metric?           uint16
          |     |  +--rw max-lsa?          uint32
          |     |  +--rw passive?          boolean
          |     +--rw isis {vpn-common:rtg-isis}?
          |     |  +--rw address-family?   identityref
          |     |  +--rw area-address      area-address
          |     |  +--rw level?            identityref
          |     |  +--rw metric?           uint32
          |     |  +--rw passive?          boolean
          |     +--rw rip {vpn-common:rtg-rip}?
          |     |  +--rw address-family?   identityref
          |     |  +--rw timers
          |     |  |  +--rw update-interval?     uint16
          |     |  |  +--rw invalid-interval?    uint16
          |     |  |  +--rw holddown-interval?   uint16
          |     |  |  +--rw flush-interval?      uint16
          |     |  +--rw default-metric?   uint8
          |     +--rw vrrp {vpn-common:rtg-vrrp}?
          |        +--rw address-family?   identityref
          |        +--rw ping-reply?       boolean
          +--rw oam
             +--rw bfd {vpn-common:bfd}?
                +--rw session-type?               identityref
                +--rw desired-min-tx-interval?    uint32
                +--rw required-min-rx-interval?   uint32
                +--rw local-multiplier?           uint8
                +--rw holdtime?                   uint32
     augment /nw:networks/nw:network/nw:node:
       +--rw ac* [name]
          +--rw name                 string
          +--rw svc-ref?             ac-svc:attachment-circuit-reference
          +--rw profile* [ac-profile-ref]
          |  +--rw ac-profile-ref    leafref
          |  +--rw network-ref?      -> /nw:networks/network/network-id
          +--rw parent-ref
          |  +--rw ac-ref?        leafref
          |  +--rw node-ref?      leafref
          |  +--rw network-ref?   -> /nw:networks/network/network-id
          +--ro child-ref
          |  +--ro ac-ref*        leafref
          |  +--ro node-ref?      leafref
          |  +--ro network-ref?   -> /nw:networks/network/network-id
          +--rw peer-sap-id*         string
          +--rw group* [group-id]
          |  +--rw group-id      string
          |  +--rw precedence?   identityref
          +--rw status
          |  +--rw admin-status
          |  |  +--rw status?        identityref
          |  |  +--ro last-change?   yang:date-and-time
          |  +--ro oper-status
          |     +--ro status?        identityref
          |     +--ro last-change?   yang:date-and-time
          +--rw description?         string
          +--rw l2-connection {ac-common:layer2-ac}?
          |  +--rw encapsulation
          |  |  +--rw encap-type?        identityref
          |  |  +--rw dot1q
          |  |  |  +--rw tag-type?         identityref
          |  |  |  +--rw cvlan-id?         uint16
          |  |  |  +--rw tag-operations
          |  |  |     +--rw (op-choice)?
          |  |  |     |  +--:(pop)
          |  |  |     |  |  +--rw pop?         empty
          |  |  |     |  +--:(push)
          |  |  |     |  |  +--rw push?        empty
          |  |  |     |  +--:(translate)
          |  |  |     |     +--rw translate?   empty
          |  |  |     +--rw tag-1?          dot1q-types:vlanid
          |  |  |     +--rw tag-1-type?     dot1q-types:dot1q-tag-type
          |  |  |     +--rw tag-2?          dot1q-types:vlanid
          |  |  |     +--rw tag-2-type?     dot1q-types:dot1q-tag-type
          |  |  +--rw priority-tagged
          |  |  |  +--rw tag-type?   identityref
          |  |  +--rw qinq
          |  |     +--rw tag-type?         identityref
          |  |     +--rw svlan-id?         uint16
          |  |     +--rw cvlan-id?         uint16
          |  |     +--rw tag-operations
          |  |        +--rw (op-choice)?
          |  |        |  +--:(pop)
          |  |        |  |  +--rw pop?         uint8
          |  |        |  +--:(push)
          |  |        |  |  +--rw push?        empty
          |  |        |  +--:(translate)
          |  |        |     +--rw translate?   uint8
          |  |        +--rw tag-1?          dot1q-types:vlanid
          |  |        +--rw tag-1-type?     dot1q-types:dot1q-tag-type
          |  |        +--rw tag-2?          dot1q-types:vlanid
          |  |        +--rw tag-2-type?     dot1q-types:dot1q-tag-type
          |  +--rw (l2-service)?
          |  |  +--:(l2-tunnel-service)
          |  |  |  +--rw l2-tunnel-service
          |  |  |     +--rw type?         identityref
          |  |  |     +--rw pseudowire
          |  |  |     |  +--rw vcid?      uint32
          |  |  |     |  +--rw far-end?   union
          |  |  |     +--rw vpls
          |  |  |     |  +--rw vcid?      uint32
          |  |  |     |  +--rw far-end*   union
          |  |  |     +--rw vxlan
          |  |  |        +--rw vni-id?            uint32
          |  |  |        +--rw peer-mode?         identityref
          |  |  |        +--rw peer-ip-address*   inet:ip-address
          |  |  +--:(l2vpn)
          |  |     +--rw l2vpn-id?            vpn-common:vpn-id
          |  +--rw l2-termination-point?      string
          |  +--rw local-bridge-reference?    string
          |  +--rw bearer-reference?          string
          |  |       {ac-common:server-assigned-reference}?
          |  +--rw lag-interface {vpn-common:lag-interface}?
          |     +--rw lag-interface-id?   string
          |     +--rw member-link-list
          |        +--rw member-link* [name]
          |           +--rw name    string
          +--rw ip-connection {ac-common:layer3-ac}?
          |  +--rw l3-termination-point?   string
          |  +--rw ipv4 {vpn-common:ipv4}?
          |  |  +--rw local-address?
          |  |  |       inet:ipv4-address
          |  |  +--rw prefix-length?                           uint8
          |  |  +--rw address-allocation-type?
          |  |  |       identityref
          |  |  +--rw (allocation-type)?
          |  |     +--:(dynamic)
          |  |     |  +--rw (address-assign)?
          |  |     |  |  +--:(number)
          |  |     |  |  |  +--rw number-of-dynamic-address?   uint16
          |  |     |  |  +--:(explicit)
          |  |     |  |     +--rw customer-addresses
          |  |     |  |        +--rw address-pool* [pool-id]
          |  |     |  |           +--rw pool-id          string
          |  |     |  |           +--rw start-address
          |  |     |  |           |       inet:ipv4-address
          |  |     |  |           +--rw end-address?
          |  |     |  |                   inet:ipv4-address
          |  |     |  +--rw (provider-dhcp)?
          |  |     |  |  +--:(dhcp-service-type)
          |  |     |  |  |  +--rw dhcp-service-type?
          |  |     |  |  |          enumeration
          |  |     |  |  +--:(service-type)
          |  |     |  |     +--rw (service-type)?
          |  |     |  |        +--:(relay)
          |  |     |  |           +--rw server-ip-address*
          |  |     |  |                   inet:ipv4-address
          |  |     |  +--rw (dhcp-relay)?
          |  |     |     +--:(customer-dhcp-servers)
          |  |     |        +--rw customer-dhcp-servers
          |  |     |           +--rw server-ip-address*
          |  |     |                   inet:ipv4-address
          |  |     +--:(static-addresses)
          |  |        +--rw address* [address-id]
          |  |           +--rw address-id                       string
          |  |           +--rw customer-address?
          |  |           |       inet:ipv4-address
          |  |           +--rw failure-detection-profile-ref?   leafref
          |  |           +--rw network-ref?
          |  |                   -> /nw:networks/network/network-id
          |  +--rw ipv6 {vpn-common:ipv6}?
          |     +--rw local-address?
          |     |       inet:ipv6-address
          |     +--rw prefix-length?                           uint8
          |     +--rw address-allocation-type?
          |     |       identityref
          |     +--rw (allocation-type)?
          |        +--:(dynamic)
          |        |  +--rw (address-assign)?
          |        |  |  +--:(number)
          |        |  |  |  +--rw number-of-dynamic-address?   uint16
          |        |  |  +--:(explicit)
          |        |  |     +--rw customer-addresses
          |        |  |        +--rw address-pool* [pool-id]
          |        |  |           +--rw pool-id          string
          |        |  |           +--rw start-address
          |        |  |           |       inet:ipv6-address
          |        |  |           +--rw end-address?
          |        |  |                   inet:ipv6-address
          |        |  +--rw (provider-dhcp)?
          |        |  |  +--:(dhcp-service-type)
          |        |  |  |  +--rw dhcp-service-type?
enumeration
+--:(service-type)
+--rw (service-type)?
+--:(relay)
+--rw server-ip-address*
inet:ipv6-address
+--rw (dhcp-relay)?
+--:(customer-dhcp-servers)
+--rw customer-dhcp-servers
+--rw server-ip-address*
inet:ipv6-address
+--:(static-addresses)
+--rw address* [address-id]
+--rw address-id string
+--rw customer-address?
inet:ipv6-address
+--rw failure-detection-profile-ref? leafref
+--rw network-ref?
-> /nw:networks/network/network-id

+--rw routing-protocols

+--rw routing-protocol* [id]
+--rw id string
+--rw type? identityref
+--rw routing-profile* [routing-profile-ref]
+--rw routing-profile-ref leafref
+--rw network-ref?
-> /nw:networks/network/network-id
+--rw type? identityref
+--rw static
+--rw cascaded-lan-prefixes
+--rw ipv4-lan-prefix* [lan next-hop]
{vpn-common:ipv4}?
+--rw lan inet:ipv4-prefix
+--rw lan-tag? string
+--rw next-hop union
+--rw metric? uint32
+--rw bfd {vpn-common:bfd}?
+--rw enabled?
boolean
+--rw failure-detection-profile-ref?
leafref
+--rw network-ref?
-> /nw:networks/network/network-id
+--rw preference? uint32
+--rw status
+--rw admin-status
+--rw status? identityref
+--ro last-change? yang:date-and-time
+--ro oper-status
+--ro status? identityref
+--ro last-change? yang:date-and-time
+--rw ipv6-lan-prefix* [lan next-hop]
{vpn-common:ipv6}?
+--rw lan inet:ipv6-prefix
+--rw lan-tag? string
+--rw next-hop union
+--rw metric? uint32
+--rw bfd {vpn-common:bfd}?
+--rw enabled?
boolean
+--rw failure-detection-profile-ref?
leafref
+--rw network-ref?
-> /nw:networks/network/network-id
+--rw preference? uint32
+--rw status
+--rw admin-status
+--rw status? identityref
+--ro last-change? yang:date-and-time
+--ro oper-status
+--ro status? identityref
+--ro last-change? yang:date-and-time
+--rw bgp {vpn-common:rtg-bgp}?
+--rw peer-groups
+--rw peer-group* [name]
+--rw name string
+--rw local-address? union
+--rw description? string
+--rw apply-policy
+--rw import-policy* leafref
+--rw default-import-policy?
default-policy-type
+--rw export-policy* leafref
+--rw default-export-policy?
default-policy-type
+--rw local-as? inet:as-number
+--rw peer-as inet:as-number
+--rw address-family? identityref
+--rw role? identityref
+--rw multihop? uint8
+--rw as-override? boolean
+--rw allow-own-as? uint8
+--rw prepend-global-as? boolean
+--rw send-default-route? boolean
+--rw site-of-origin?
rt-types:route-origin
+--rw ipv6-site-of-origin?
rt-types:ipv6-route-origin
+--rw redistribute-connected* [address-family]
+--rw address-family identityref
+--rw enabled? boolean
+--rw bgp-max-prefix
+--rw max-prefix? uint32
+--rw warning-threshold? decimal64
+--rw violate-action? enumeration
+--rw restart-timer? uint32
+--rw bgp-timers
+--rw keepalive? uint16
+--rw hold-time? uint16
+--rw authentication
+--rw enabled? boolean
+--rw keying-material
+--rw (option)?
+--:(ao)
+--rw enable-ao? boolean
+--rw ao-keychain?
key-chain:key-chain-ref
+--:(md5)
+--rw md5-keychain?
key-chain:key-chain-ref
+--:(explicit)
+--rw key-id? uint32
+--rw key? string
+--rw crypto-algorithm?
identityref
+--rw neighbor* [remote-address]
+--rw remote-address inet:ip-address
+--rw local-address? union
+--rw peer-group?
-> ../../peer-groups/peer-group/name
+--rw description? string
+--rw apply-policy
+--rw import-policy* leafref
+--rw default-import-policy?
default-policy-type
+--rw export-policy* leafref
+--rw default-export-policy?
default-policy-type
+--rw local-as? inet:as-number
+--rw peer-as inet:as-number
+--rw address-family? identityref
+--rw role? identityref
+--rw multihop? uint8
+--rw as-override? boolean
+--rw allow-own-as? uint8
+--rw prepend-global-as? boolean
+--rw send-default-route? boolean
+--rw site-of-origin?
rt-types:route-origin
+--rw ipv6-site-of-origin?
rt-types:ipv6-route-origin
+--rw redistribute-connected* [address-family]
+--rw address-family identityref
+--rw enabled? boolean
+--rw bgp-max-prefix
+--rw max-prefix? uint32
+--rw warning-threshold? decimal64
+--rw violate-action? enumeration
+--rw restart-timer? uint32
+--rw bgp-timers
+--rw keepalive? uint16
+--rw hold-time? uint16
+--rw bfd {vpn-common:bfd}?
+--rw enabled? boolean
+--rw failure-detection-profile-ref? leafref
+--rw network-ref?
-> /nw:networks/network/network-id
+--rw authentication
+--rw enabled? boolean
+--rw keying-material
+--rw (option)?
+--:(ao)
+--rw enable-ao? boolean
+--rw ao-keychain?
key-chain:key-chain-ref
+--:(md5)
+--rw md5-keychain?
key-chain:key-chain-ref
+--:(explicit)
+--rw key-id? uint32
+--rw key? string
+--rw crypto-algorithm? identityref
+--rw status
+--rw admin-status
+--rw status? identityref
+--ro last-change? yang:date-and-time
+--ro oper-status
+--ro status? identityref
+--ro last-change? yang:date-and-time
+--rw ospf {vpn-common:rtg-ospf}?
+--rw address-family? identityref
+--rw area-id yang:dotted-quad
+--rw metric? uint16
+--rw sham-links {vpn-common:rtg-ospf-sham-link}?
+--rw sham-link* [target-site]
+--rw target-site string
+--rw metric? uint16
+--rw max-lsa? uint32
+--rw passive? boolean
+--rw authentication
+--rw enabled? boolean
+--rw keying-material
+--rw (option)?
+--:(auth-key-chain)
+--rw key-chain?
key-chain:key-chain-ref
+--:(auth-key-explicit)
+--rw key-id? uint32
+--rw key? string
+--rw crypto-algorithm? identityref
+--rw status
+--rw admin-status
+--rw status? identityref
+--ro last-change? yang:date-and-time
+--ro oper-status
+--ro status? identityref
+--ro last-change? yang:date-and-time
+--rw isis {vpn-common:rtg-isis}?
+--rw address-family? identityref
+--rw area-address area-address
+--rw level? identityref
+--rw metric? uint32
+--rw passive? boolean
+--rw authentication
+--rw enabled? boolean
+--rw keying-material
+--rw (option)?
+--:(auth-key-chain)
+--rw key-chain?
key-chain:key-chain-ref
+--:(auth-key-explicit)
+--rw key-id? uint32
+--rw key? string
+--rw crypto-algorithm? identityref
+--rw status
+--rw admin-status
+--rw status? identityref
+--ro last-change? yang:date-and-time
+--ro oper-status
+--ro status? identityref
+--ro last-change? yang:date-and-time
+--rw rip {vpn-common:rtg-rip}?
+--rw address-family? identityref
+--rw timers
+--rw update-interval? uint16
+--rw invalid-interval? uint16
+--rw holddown-interval? uint16
+--rw flush-interval? uint16
+--rw default-metric? uint8
+--rw authentication
+--rw enabled? boolean
+--rw keying-material
+--rw (option)?
+--:(auth-key-chain)
+--rw key-chain?
key-chain:key-chain-ref
+--:(auth-key-explicit)
+--rw key? string
+--rw crypto-algorithm? identityref
+--rw status
+--rw admin-status
+--rw status? identityref
+--ro last-change? yang:date-and-time
+--ro oper-status
+--ro status? identityref
+--ro last-change? yang:date-and-time
+--rw vrrp {vpn-common:rtg-vrrp}?
+--rw address-family? identityref
+--rw vrrp-group? uint8
+--rw backup-peer? inet:ip-address
+--rw virtual-ip-address* inet:ip-address
+--rw priority? uint8
+--rw ping-reply? boolean
+--rw status
+--rw admin-status
+--rw status? identityref
+--ro last-change? yang:date-and-time
+--ro oper-status
+--ro status? identityref
+--ro last-change? yang:date-and-time

+--rw oam

+--rw bfd {vpn-common:bfd}?
+--rw session* [dest-addr]
+--rw dest-addr inet:ip-address
+--rw source-address? union
+--rw failure-detection-profile-ref? leafref
+--rw network-ref?
-> /nw:networks/network/network-id
+--rw session-type? identityref
+--rw desired-min-tx-interval? uint32
+--rw required-min-rx-interval? uint32
+--rw local-multiplier? uint8
+--rw holdtime? uint32
+--rw authentication!
+--rw key-chain? key-chain:key-chain-ref
+--rw meticulous? boolean
+--rw status
+--rw admin-status
+--rw status? identityref
+--ro last-change? yang:date-and-time
+--ro oper-status
+--ro status? identityref
+--ro last-change? yang:date-and-time

+--rw security

+--rw encryption {vpn-common:encryption}?
+--rw enabled? boolean
+--rw layer? enumeration
+--rw encryption-profile
+--rw (profile)?
+--:(provider-profile)
+--rw encryption-profile-ref? leafref
+--rw network-ref?
-> /nw:networks/network/network-id
+--:(customer-profile)
+--rw customer-key-chain?
key-chain:key-chain-ref

+--rw service +--rw mtu? uint32 +--rw svc-pe-to-ce-bandwidth {vpn-common:inbound-bw}?

+--rw bandwidth* [bw-type]
+--rw bw-type identityref
+--rw (type)?
+--:(per-cos)
+--rw cos* [cos-id]
+--rw cos-id uint8
+--rw cir? uint64
+--rw cbs? uint64
+--rw eir? uint64
+--rw ebs? uint64
+--rw pir? uint64
+--rw pbs? uint64
+--:(other)
+--rw cir? uint64
+--rw cbs? uint64
+--rw eir? uint64
+--rw ebs? uint64
+--rw pir? uint64
+--rw pbs? uint64

+--rw svc-ce-to-pe-bandwidth {vpn-common:outbound-bw}?

+--rw bandwidth* [bw-type]
+--rw bw-type identityref
+--rw (type)?
+--:(per-cos)
+--rw cos* [cos-id]
+--rw cos-id uint8
+--rw cir? uint64
+--rw cbs? uint64
+--rw eir? uint64
+--rw ebs? uint64
+--rw pir? uint64
+--rw pbs? uint64
+--:(other)
+--rw cir? uint64
+--rw cbs? uint64
+--rw eir? uint64
+--rw ebs? uint64
+--rw pir? uint64
+--rw pbs? uint64

+--rw qos {vpn-common:qos}?

+--rw qos-profiles
+--rw qos-profile* [qos-profile-ref]
+--rw qos-profile-ref leafref
+--rw network-ref?
-> /nw:networks/network/network-id
+--rw direction? identityref

+--rw access-control-list +--rw acl-profiles +--rw acl-profile* [forwarding-profile-ref] +--rw forwarding-profile-ref leafref +--rw network-ref? -> /nw:networks/network/network-id augment /nw:networks/nw:network/nw:node/sap:service/sap:sap: +--rw ac* [ac-ref] +--rw ac-ref leafref +--rw node-ref? leafref +--rw network-ref? -> /nw:networks/network/network-id


---

# Acknowledgments 🫶

This doc builds on [RFC9182] and [RFC9291], so big thanks to everyone who made those possible! 💜

Huge thanks to Moti Morgenstern for the review and comments. 🌸

Massive shoutout to Martin Björklund for the YANG Doctors review, Gyan Mishra for an early RTGDIR review, Joel Halpern for the RTGDIR review, Giuseppe Fioccola for the OPSDIR review, and Russ Housley for the SECDIR review. You all are literally the reason this is so solid 😭✨

Thanks to Krzysztof Szarkowicz for the shepherd review. 🎀

And thanks to Mahesh Jethanandani for the AD review. 👑

# Contributors 💖

**Victor Lopez** 🌈
Nokia
Email: victor.lopez@nokia.com

**Ivan Bykov** 🦋
Ribbon Communications
Email: Ivan.Bykov@rbbn.com

**Qin Wu** 🧚
Huawei
Email: bill.wu@huawei.com

**Ogaki Kenichi** 🍓
KDDI
Email: ke-oogaki@kddi.com

**Luis Angel Munoz** ⭐
Vodafone
Email: luis-angel.munoz@vodafone.com

# Authors' Addresses 🦋

**Mohamed Boucadair** (editor) 👑
Orange
Email: mohamed.boucadair@orange.com

**Richard Roberts** 💅
Juniper
Email: rroberts@juniper.net

**Oscar Gonzalez de Dios** 🫶
Telefonica
Email: oscar.gonzalezdedios@telefonica.com

**Samier Barguil** 🔥
Nokia
Email: samier.barguil_giraldo@nokia.com

**Bo Wu** 💜
Huawei Technologies
Email: lana.wubo@huawei.com
📦 where this page comes from