module ietf-flexible-encapsulation {
  yang-version 1.1;

  namespace
    "urn:ietf:params:xml:ns:yang:ietf-flexible-encapsulation";

  prefix flex;

  import ietf-interfaces {
    prefix if;
  }

  import iana-if-type {
    prefix ianaift;
  }

  import ietf-interfaces-common {
    prefix if-cmn;
  }

  import ieee802-dot1q-types {
    prefix dot1q-types;
  }

  organization
    "IETF NETMOD (NETCONF Data Modeling Language) Working Group";

  contact
    "WG Web:   <http://tools.ietf.org/wg/netmod/>
     WG List:  <mailto:netmod@ietf.org>

     WG Chair: Lou Berger
               <mailto:lberger@labn.net>

     WG Chair: Kent Watsen
               <mailto:kwatsen@juniper.net>

     Editor:   Robert Wilton
               <mailto:rwilton@cisco.com>";

  description
    "This YANG module describes interface configuration for flexible
     VLAN matches and rewrites.";

  revision 2017-07-04 {
    description "Fix for c-vlan and s-vlan missing namespace prefixes.";

    reference
      "https://www.ietf.org/mail-archive/web/netmod/current/msg18367.html";
  }

  revision 2017-07-03 {
    description "Latest draft revision";

    reference
      "Internet-Draft draft-ietf-netmod-sub-intf-vlan-model-02";
  }

  feature flexible-rewrites {
    description
      "This feature indicates whether the network element supports
        specifying flexible rewrite operations";
  }

  feature asymmetric-rewrites {
    description
      "This feature indicates whether the network element supports
       specifying different rewrite operations for the ingress
       rewrite operation and egress rewrite operation.";
  }

  feature dot1q-tag-rewrites {
    description
      "This feature indicates whether the network element supports
       the flexible rewrite functionality specifying flexible 802.1Q
       tag rewrites";
  }

  /*
   * flexible-match grouping.
   *
   * This grouping represents a flexible match.
   *
   * The rules for a flexible match are:
   *     1. default, untagged, priority tag, or a stack of tags.
   *   - Each tag in the stack of tags matches:
   *      1. tag type (802.1Q or 802.1ad) +
   *      2. tag value:
   *        i. single tag
   *        ii. set of tag ranges/values.
   *        iii. "any" keyword
   */
  grouping flexible-match {
    description "Flexible match";
    choice match-type {
      mandatory true;
      description "Provides a choice of how the frames may be
                   matched";

      case default {
        description "Default match";
        leaf default {
          type empty;
          description
            "Default match.  Matches all traffic not matched to any
             other peer sub-interface by a more specific
             encapsulation.";
        } // leaf default
      } // case default

      case untagged {
        description "Match untagged Ethernet frames only";
        leaf untagged {
          type empty;
          description
            "Untagged match.  Matches all untagged traffic.";
        } // leaf untagged
      } // case untagged

      case dot1q-priority-tagged {
        description
          "Match 802.1Q priority tagged Ethernet frames only";

        container dot1q-priority-tagged {
          description "802.1Q priority tag match";
          leaf tag-type {
            type dot1q-types:dot1q-tag-type;
            description "The 802.1Q tag type of matched priority
                         tagged packets";
          }
        }
      }

      case dot1q-vlan-tagged {
        container dot1q-vlan-tagged {
          description "Matches VLAN tagged frames";

          container outer-tag {
            presence "The outermost VLAN tag exists";

            description
              "Classifies traffic using the outermost VLAN tag on the
               frame.";

            uses
              'dot1q-types:'+
              'dot1q-tag-ranges-or-any-classifier-grouping';
          }

          container second-tag {
            must
              '../outer-tag/dot1q-tag/tag-type = "dot1q-types:s-vlan" and ' +
              'dot1q-tag/tag-type = "dot1q-types:c-vlan"' {

              error-message
                "When matching two tags, the outermost tag must be
                 specified and of S-VLAN type and the second
                 outermost tag must be of C-VLAN tag type";

              description
                "For IEEE 802.1Q interoperability, when matching two
                 tags, it is required that the outermost tag exists
                 and is an S-VLAN, and the second outermost tag is a
                 C-VLAN";
            }

            presence "The second outermost VLAN tag exists";

            description
              "Classifies traffic using the second outermost VLAN tag
               on the frame.";

            uses
              'dot1q-types:'+
              'dot1q-tag-ranges-or-any-classifier-grouping';
          }

          leaf match-exact-tags {
            type empty;
            description
              "If set, indicates that all 802.1Q VLAN tags in the
               Ethernet frame header must be explicitly matched, i.e.
               the EtherType following the matched tags must not be a
               802.1Q tag EtherType.  If unset then extra 802.1Q VLAN
               tags are allowed.";
          }
        }
      }
    } // encaps-type
  }

  /*
   * Grouping for tag-rewrite that can be expressed either
   * symmetrically, or in the ingress and/or egress directions
   * independently.
   */
  grouping dot1q-tag-rewrite {
    description "Flexible rewrite";
    leaf pop-tags {
      type uint8 {
        range 1..2;
      }
      description "The number of tags to pop (or translate if used in
                   conjunction with push-tags)";
    }

    container push-tags {
      description "The 802.1Q tags to push (or translate if used in
                   conjunction with pop-tags)";

      container outer-tag {
        presence
          "Indicates existence of the outermost VLAN tag to
           push/rewrite";

        description
          "The outermost VLAN tag to push onto the frame.";

        uses dot1q-types:dot1q-tag-classifier-grouping;
      }

      container second-tag {
        must
          '../outer-tag/dot1q-tag/tag-type = "dot1q-types:s-vlan" and ' +
          'dot1q-tag/tag-type = "dot1q-types:c-vlan"' {

          error-message
          "When pushing/rewriting two tags, the outermost tag must be
           specified and of S-VLAN type and the second outermost tag
           must be of C-VLAN tag type";

          description
          "For IEEE 802.1Q interoperability, when pushing two tags,
           it is required that the outermost tag exists and is an
           S-VLAN, and the second outermost tag is a C-VLAN";
        }

        presence
          "Indicates existence of a second outermost VLAN tag to
           push/rewrite.";

        description
          "The second outermost VLAN tag to push onto the frame.";

        uses dot1q-types:dot1q-tag-classifier-grouping;
      }
    }
  }

  /*
   * Grouping for all flexible rewrites of fields in the L2 header.
   *
   * This currently only includes flexible tag rewrites, but is
   * designed to be extensible to cover rewrites of other fields in
   * the L2 header if required.
   */
  grouping flexible-rewrite {
    description "Flexible rewrite";

    /*
     * Tag rewrite.
     *
     * All tag rewrites are formed using a combination of pop-tags
     * and push-tags operations.
     */
    container dot1q-tag-rewrite {
      if-feature dot1q-tag-rewrites;
      description "Tag rewrite.  Translate operations are expressed
                   as a combination of tag push and pop operations.";
      uses dot1q-tag-rewrite;
    }
  }
  augment "/if:interfaces/if:interface/if-cmn:encapsulation/" +
          "if-cmn:encaps-type" {
    when
        "derived-from-or-self(../if:type,
                              'ianaift:ethernetCsmacd') or
         derived-from-or-self(../if:type,
                              'ianaift:ieee8023adLag') or
         derived-from-or-self(../if:type,
                              'if-cmn:ethSubInterface')" {
      description
        "Applies only to Ethernet-like interfaces and
         sub-interfaces";
    }
    description
      "Add flexible match and rewrite for VLAN sub-interfaces";

    /*
     * A flexible encapsulation allows for the matching of ranges and
     * sets of VLAN Ids.  The structure is also designed to be
     * extended to allow for matching/rewriting other fields within
     * the L2 frame header if required.
     */
    case flexible {
      description "Flexible encapsulation and rewrite";
      container flexible {
          must
            'count(../../if-cmn:forwarding-mode) = 0 or ' +
            'derived-from-or-self(../../if-cmn:forwarding-mode,' +
                                 '"if-cmn:layer-2-forwarding")' {
            error-message
              "If the interface forwarding-mode leaf is set then it
               must be set to an identity that derives from
               layer-2-forwarding";

            description
              "The forwarding-mode leaf on an interface can
               optionally be used to enforce consistency of
               configuration";
          }

        description "Flexible encapsulation and rewrite";

        container match {
          description
            "The match used to classify frames to this interface";
          uses flexible-match;
        }

        container rewrite {
          if-feature flexible-rewrites;
          description "L2 frame rewrite operations";
          choice direction {
            description
              "Whether the rewrite policy is symmetrical or
               asymmetrical";
            case symmetrical {
              container symmetrical {
                uses flexible-rewrite;
                description
                  "Symmetrical rewrite.  Expressed in the ingress
                   direction, but the reverse operation is applied to
                   egress traffic";
              }
            }

            /*
             * Allow asymmetrical rewrites to be specified.
             */
            case asymmetrical {
              if-feature asymmetric-rewrites;
              description "Asymmetrical rewrite";
              container ingress {
                uses flexible-rewrite;
                description "Ingress rewrite";
              }
              container egress {
                uses flexible-rewrite;
                description "Egress rewrite";
              }
            }
          }
        }

        /*
         * For encapsulations that match a range of VLANs (or Any),
         * allow configuration to specify the default 802.1Q VLAN tag
         * values to use for any traffic that is locally sourced from
         * an interface on the device.
         */
        container local-traffic-default-encaps {
          presence
            "A local traffic default encapsulation has been
             specified";
          description
            "The 802.1Q VLAN tags to use by default for locally
             sourced traffic";

          container outer-tag {
            presence
              "Indicates existence of the outermost VLAN tag";

            description
              "The outermost VLAN tag for locally sourced traffic";

            uses dot1q-types:dot1q-tag-classifier-grouping;
          }

          container second-tag {
            must
              '../outer-tag/dot1q-tag/tag-type = "dot1q-types:s-vlan" and ' +
               'dot1q-tag/tag-type = "dot1q-types:c-vlan"' {

            error-message
              "When specifying two tags, the outermost tag must be
               specified and of S-VLAN type and the second outermost
               tag must be of C-VLAN tag type";

            description
              "For IEEE 802.1Q interoperability, when specifying two
               tags, it is required that the outermost tag exists and
               is an S-VLAN, and the second outermost tag is a
               C-VLAN";
            }

            presence
              "Indicates existence of a second outermost VLAN tag.";

            description
              "The second outermost VLAN tag for locally sourced
               traffic";

            uses dot1q-types:dot1q-tag-classifier-grouping;
          }
        }
      }
    }
  }
}
