module snabb-softwire-v2 {
  yang-version 1.1;
  namespace snabb:softwire-v2;
  prefix softwire;

  import ietf-inet-types { prefix inet; }
  import ietf-yang-types { prefix yang; }

  organization "Igalia, S.L.";
  contact "Jessica Tallon <tsyesika@igalia.com>";
  description
   "Configuration for the Snabb Switch lwAFTR.";

  revision 2019-09-17 {
    description
      "Add discontinuity time to softwire-state.";
  }

  revision 2018-10-13 {
    description
      "Add flow-label setting.";
  }

  revision 2017-04-17 {
    description
      "Removal of br-address leaf-list and  br leaf. It adds the
       addition of br-address binding_table.softwire. This is to
       make the schema more yang-like. One now only need to specify
       the br-address on the softwire rather than managing the index's
       to a leaf-list of them.

       This also removes the psid-map list and adds a new port-set
       container on the softwire container instead. This will help
       adding the softwires as well as bring it more inline with the
       ietf-softwire schema.

       The addition of /softwire-config/instance allows for configuring
       multiple instances of the lwAFTR with a shared binding table and
       other common configuration properties.";
  }

  revision 2016-11-04 {
    description
     "Initial revision.";
  }

  grouping state-counters {
    container softwire-state {

      description "State data about interface.";
      config false;

      leaf discontinuity-time {
        type yang:date-and-time;
        mandatory true;
        description
          "The time of the most recent occasion on which the lwaftr instance
           suffered a discontinuity. This is set to the current time whenever
           the lwaftr instance is started or configured.";
      }

      leaf drop-all-ipv4-iface-bytes {
        type yang:zero-based-counter64;
        description
          "All dropped packets and bytes that came in over IPv4 interfaces,
          whether or not they actually IPv4 (they only include data about
          packets that go in/out over the wires, excluding internally generated
          ICMP packets).";
      }
      leaf drop-all-ipv4-iface-packets {
        type yang:zero-based-counter64;
        description
          "All dropped packets and bytes that came in over IPv4 interfaces,
          whether or not they actually IPv4 (they only include data about
          packets that go in/out over the wires, excluding internally generated
          ICMP packets).";
      }
      leaf drop-all-ipv6-iface-bytes {
        type yang:zero-based-counter64;
        description
          "All dropped packets and bytes that came in over IPv6 interfaces,
          whether or not they actually IPv6 (they only include data about packets
          that go in/out over the wires, excluding internally generated ICMP
          packets).";
      }
      leaf drop-all-ipv6-iface-packets {
        type yang:zero-based-counter64;
        description
          "All dropped packets and bytes that came in over IPv6 interfaces,
          whether or not they actually IPv6 (they only include data about packets
          that go in/out over the wires, excluding internally generated ICMP
          packets).";
      }
      leaf drop-bad-checksum-icmpv4-bytes {
        type yang:zero-based-counter64;
        description "ICMPv4 packets dropped because of a bad checksum.";
      }
      leaf drop-bad-checksum-icmpv4-packets {
        type yang:zero-based-counter64;
        description "ICMPv4 packets dropped because of a bad checksum.";
      }
      leaf drop-in-by-policy-icmpv4-bytes {
        type yang:zero-based-counter64;
        description "Incoming ICMPv4 packets dropped because of current policy.";
      }
      leaf drop-in-by-policy-icmpv4-packets {
        type yang:zero-based-counter64;
        description "Incoming ICMPv4 packets dropped because of current policy.";
      }
      leaf drop-in-by-policy-icmpv6-bytes {
        type yang:zero-based-counter64;
        description "Incoming ICMPv6 packets dropped because of current policy.";
      }
      leaf drop-in-by-policy-icmpv6-packets {
        type yang:zero-based-counter64;
        description "Incoming ICMPv6 packets dropped because of current policy.";
      }
      leaf drop-in-by-rfc7596-icmpv4-bytes {
        type yang:zero-based-counter64;
        description
          "Incoming ICMPv4 packets with no destination (RFC 7596 section 8.1).";
      }
      leaf drop-in-by-rfc7596-icmpv4-packets {
        type yang:zero-based-counter64;
        description
          "Incoming ICMPv4 packets with no destination (RFC 7596 section 8.1).";
      }
      leaf drop-ipv4-frag-disabled {
        type yang:zero-based-counter64;
        description
          "If fragmentation is disabled, the only potentially non-zero IPv4
          fragmentation counter is drop-ipv4-frag-disabled. If fragmentation is
          enabled, it will always be zero.";
      }
      leaf drop-ipv4-frag-invalid-reassembly {
        type yang:zero-based-counter64;
        description
          "Two or more IPv4 fragments were received, and reassembly was started,
          but was invalid and dropped. Causes include multiple fragments claiming
          they are the last fragment, overlapping fragment offsets, or the packet
          was being reassembled from too many fragments (the setting is
          max_fragments_per_reassembly_packet, and the default is that no packet
          should be reassembled from more than 40).";
      }
      leaf drop-ipv4-frag-random-evicted {
        type yang:zero-based-counter64;
        description
          "Reassembling an IPv4 packet from fragments was in progress, but the
          configured amount of packets to reassemble at once was exceeded, so one
          was dropped at random. Consider increasing the setting
          max_ipv4_reassembly_packets.";
      }
      leaf drop-ipv6-frag-disabled {
        type yang:zero-based-counter64;
        description
          "If fragmentation is disabled, the only potentially non-zero IPv6
          fragmentation counter is drop-ipv6-frag-disabled. If fragmentation is
          enabled, it will always be zero.";
      }
      leaf drop-ipv6-frag-invalid-reassembly {
        type yang:zero-based-counter64;
        description
          "Two or more IPv6 fragments were received, and reassembly was started,
          but was invalid and dropped. Causes include multiple fragments claiming
          they are the last fragment, overlapping fragment offsets, or the packet
          was being reassembled from too many fragments (the setting is
          max_fragments_per_reassembly_packet, and the default is that no packet
          should be reassembled from more than 40).";
      }
      leaf drop-ipv6-frag-random-evicted {
        type yang:zero-based-counter64;
        description
          "Reassembling an IPv6 packet from fragments was in progress, but the
          configured amount of packets to reassemble at once was exceeded, so one
          was dropped at random. Consider increasing the setting
          max_ipv6_reassembly_packets.";
      }
      leaf drop-misplaced-not-ipv4-bytes {
        type yang:zero-based-counter64;
        description "Non-IPv4 packets incoming on the IPv4 link.";
      }
      leaf drop-misplaced-not-ipv4-packets {
        type yang:zero-based-counter64;
        description "Non-IPv4 packets incoming on the IPv4 link.";
      }
      leaf drop-misplaced-not-ipv6-bytes {
        type yang:zero-based-counter64;
        description "Non-IPv6 packets incoming on IPv6 link.";
      }
      leaf drop-misplaced-not-ipv6-packets {
        type yang:zero-based-counter64;
        description "Non-IPv6 packets incoming on IPv6 link.";
      }
      leaf drop-no-dest-softwire-ipv4-bytes {
        type yang:zero-based-counter64;
        description
          "No matching destination softwire in the binding table; incremented
          whether or not the reason was RFC7596.";
      }
      leaf drop-no-dest-softwire-ipv4-packets {
        type yang:zero-based-counter64;
        description
          "No matching destination softwire in the binding table; incremented
          whether or not the reason was RFC7596.";
      }
      leaf drop-no-source-softwire-ipv6-bytes {
        type yang:zero-based-counter64;
        description
          "No matching source softwire in the binding table; incremented whether
          or not the reason was RFC7596.";
      }
      leaf drop-no-source-softwire-ipv6-packets {
        type yang:zero-based-counter64;
        description
          "No matching source softwire in the binding table; incremented whether
          or not the reason was RFC7596.";
      }
      leaf drop-out-by-policy-icmpv4-packets {
        type yang:zero-based-counter64;
        description
          "Internally generated ICMPv4 error packets dropped because of current
          policy.";
      }
      leaf drop-out-by-policy-icmpv6-packets {
        type yang:zero-based-counter64;
        description
          "Internally generated ICMPv6 packets dropped because of current
          policy.";
      }
      leaf drop-over-mtu-but-dont-fragment-ipv4-bytes {
        type yang:zero-based-counter64;
        description
          "IPv4 packets whose size exceeded the MTU, but the DF (Don't Fragment)
          flag was set.";
      }
      leaf drop-over-mtu-but-dont-fragment-ipv4-packets {
        type yang:zero-based-counter64;
        description
          "IPv4 packets whose size exceeded the MTU, but the DF (Don't Fragment)
          flag was set.";
      }
      leaf drop-over-rate-limit-icmpv6-bytes {
        type yang:zero-based-counter64;
        description
          "Packets dropped because the outgoing ICMPv6 rate limit was reached.";
      }
      leaf drop-over-rate-limit-icmpv6-packets {
        type yang:zero-based-counter64;
        description
          "Packets dropped because the outgoing ICMPv6 rate limit was reached.";
      }
      leaf drop-over-time-but-not-hop-limit-icmpv6-bytes {
        type yang:zero-based-counter64;
        description
          "Packet's time limit was exceeded, but the hop limit was not.";
      }
      leaf drop-over-time-but-not-hop-limit-icmpv6-packets {
        type yang:zero-based-counter64;
        description
          "Packet's time limit was exceeded, but the hop limit was not.";
      }
      leaf drop-too-big-type-but-not-code-icmpv6-bytes {
        type yang:zero-based-counter64;
        description
          "Packet's ICMP type was 'Packet too big' but its ICMP code was not an
          acceptable one for this type.";
      }
      leaf drop-too-big-type-but-not-code-icmpv6-packets {
        type yang:zero-based-counter64;
        description
          "Packet's ICMP type was 'Packet too big' but its ICMP code was not an
          acceptable one for this type.";
      }
      leaf drop-ttl-zero-ipv4-bytes {
        type yang:zero-based-counter64;
        description "IPv4 packets dropped because their TTL was zero.";
      }
      leaf drop-ttl-zero-ipv4-packets {
        type yang:zero-based-counter64;
        description "IPv4 packets dropped because their TTL was zero.";
      }
      leaf drop-unknown-protocol-icmpv6-bytes {
        type yang:zero-based-counter64;
        description "Packets with an unknown ICMPv6 protocol.";
      }
      leaf drop-unknown-protocol-icmpv6-packets {
        type yang:zero-based-counter64;
        description "Packets with an unknown ICMPv6 protocol.";
      }
      leaf drop-unknown-protocol-ipv6-bytes {
        type yang:zero-based-counter64;
        description "Packets with an unknown IPv6 protocol.";
      }
      leaf drop-unknown-protocol-ipv6-packets {
        type yang:zero-based-counter64;
        description "Packets with an unknown IPv6 protocol.";
      }
      leaf hairpin-ipv4-bytes {
        type yang:zero-based-counter64;
        description "IPv4 packets going to a known b4 (hairpinned).";
      }
      leaf hairpin-ipv4-packets {
        type yang:zero-based-counter64;
        description "IPv4 packets going to a known b4 (hairpinned).";
      }
      leaf in-ipv4-bytes {
        type yang:zero-based-counter64;
        description "All valid outgoing IPv4 packets.";
      }
      leaf in-ipv4-frag-needs-reassembly {
        type yang:zero-based-counter64;
        description "An IPv4 fragment was received.";
      }
      leaf in-ipv4-frag-reassembled {
        type yang:zero-based-counter64;
        description "A packet was successfully reassembled from IPv4 fragments.";
      }
      leaf in-ipv4-frag-reassembly-unneeded {
        type yang:zero-based-counter64;
        description
          "An IPv4 packet which was not a fragment was received - consequently,
          it did not need to be reassembled. This should be the usual case.";
      }
      leaf in-ipv4-packets {
        type yang:zero-based-counter64;
        description "All valid outgoing IPv4 packets.";
      }
      leaf in-ipv6-bytes {
        type yang:zero-based-counter64;
        description "All valid outgoing IPv4 packets.";
      }
      leaf in-ipv6-frag-needs-reassembly {
        type yang:zero-based-counter64;
        description "An IPv6 fragment was received.";
      }
      leaf in-ipv6-frag-reassembled {
        type yang:zero-based-counter64;
        description "A packet was successfully reassembled from IPv6 fragments.";
      }
      leaf in-ipv6-frag-reassembly-unneeded {
        type yang:zero-based-counter64;
        description
          "An IPv6 packet which was not a fragment was received - consequently, it
          did not need to be reassembled. This should be the usual case.";
      }
      leaf in-ipv6-packets {
        type yang:zero-based-counter64;
        description "All valid outgoing IPv4 packets.";
      }
      leaf ingress-packet-drops {
        type yang:zero-based-counter64;
        description "Packets dropped due to ingress filters.";
      }
      leaf memuse-ipv4-frag-reassembly-buffer {
        type yang:zero-based-counter64;
        description
          "The amount of memory being used by the statically sized data structure
          for reassembling IPv4 fragments. This is directly proportional to the
          setting max_ipv4_reassembly_packets.";
      }
      leaf memuse-ipv6-frag-reassembly-buffer {
        type yang:zero-based-counter64;
        description
          "The amount of memory being used by the statically sized data structure
          for reassembling IPv6 fragments. This is directly proportional to the
          setting max_ipv6_reassembly_packets.";
      }
      leaf out-icmpv4-bytes {
        type yang:zero-based-counter64;
        description "Internally generated ICMPv4 packets.";
      }
      leaf out-icmpv4-packets {
        type yang:zero-based-counter64;
        description "Internally generated ICMPv4 packets.";
      }
      leaf out-icmpv6-bytes {
        type yang:zero-based-counter64;
        description "Internally generted ICMPv6 error packets.";
      }
      leaf out-icmpv6-packets {
        type yang:zero-based-counter64;
        description "Internally generted ICMPv6 error packets.";
      }
      leaf out-ipv4-bytes {
        type yang:zero-based-counter64;
        description "Valid outgoing IPv4 packets.";
      }
      leaf out-ipv4-frag {
        type yang:zero-based-counter64;
        description
          "An outgoing packet exceeded the configured IPv4 MTU, so needed to be
          fragmented. This may happen, but should be unusual.";
      }
      leaf out-ipv4-frag-not {
        type yang:zero-based-counter64;
        description
          "An outgoing packet was small enough to pass through unfragmented - this
          should be the usual case.";
      }
      leaf out-ipv4-packets {
        type yang:zero-based-counter64;
        description "Valid outgoing IPv4 packets.";
      }
      leaf out-ipv6-bytes {
        type yang:zero-based-counter64;
        description "All valid outgoing IPv6 packets.";
      }
      leaf out-ipv6-frag {
        type yang:zero-based-counter64;
        description
          "An outgoing packet exceeded the configured IPv6 MTU, so needed to be
          fragmented. This may happen, but should be unusual.";
      }
      leaf out-ipv6-frag-not {
        type yang:zero-based-counter64;
        description
          "An outgoing packet was small enough to pass through unfragmented - this
          should be the usual case.";
      }
      leaf out-ipv6-packets {
        type yang:zero-based-counter64;
        description "All valid outgoing IPv6 packets.";
      }
    }
  }

  container softwire-config {
    description
     "Configuration for Snabb lwaftr.";

    leaf name {
      type string;
      description
        "Name of lwAFTR instance. This must be unique amongst the Snabb
        processes on the system. This may be specified either here, in the
        YANG configuration or via the command line when the lwAFTR is started.

        The order of presidence for this leaf is as followers:
        1. The name set on an already running lwAFTR instance via snabb set.
        2. A command line option to specify the name upon starting the lwAFTR
            instance (i.e. overriding this value).
        3. The value here in the configuration when starting a lwaftr instance.

        If no name is specified the lwaftr can be referred to using the PID of
        the lwAFTR process on the system.";
    }

    grouping traffic-filters {
      description
       "Ingress and egress filters describing the set of packets
        that should be allowed to pass, as pflang filters.  pflang
        is the language of tcpdump, libpcap and other tools.  Note
        that if VLAN tagging is enabled, the filters run on packets
        after VLAN tags have been stripped off.";
      leaf ingress-filter {
        type string;
        description
         "Filter for incoming traffic.  Packets that do not match
          the filter will be silently dropped.";
      }
      leaf egress-filter {
        type string;
        description
         "Filter for outgoing traffic.  Packets that do not match
          the filter will be silently dropped.";
      }
    }

    grouping icmp-policy {
      description
       "The lwAFTR can be configured to allow or drop incoming ICMP
        messages, and to generate outgoing ICMP error messages or
        not.";

      leaf allow-incoming-icmp {
        type boolean;
        default true;
        description
         "Whether to allow incoming ICMP packets.";
      }

      leaf generate-icmp-errors {
        type boolean;
        default true;
        description
         "Whether to generate outgoing ICMP error messages.";
      }
    }

    grouping vlan-tagging {
      description
       "802.1Q Ethernet tagging.";

      leaf vlan-tag {
        type uint16 {
          range 0..4095;
        }
        description
         "802.1Q Ethernet VLAN tag for this interface.";
      }
    }

    grouping error-rate-limiting {
      description
       "These settings limit the rate of ICMP error message
        transmission.";

      container error-rate-limiting {
        leaf packets {
          type uint32;
          description
           "The number of ICMP error messages which can be sent within
            the specified time period.";
        }

        leaf period {
          type uint32 { range 1..max; }
          default 2;
          description
           "The time period given in seconds.";
        }
      }
    }

    grouping reassembly {
      description
       "These settings limit the resources devoted to reassembling
        fragmented packets.";

      container reassembly {
        leaf max-fragments-per-packet {
          type uint32 { range 1..max; }
          default 20;
          description
           "The maximum number of fragments per reassembled packet.
            Attempts to reassemble a packet using more fragments than
            this threshold will fail and the reassembly data will be
            discarded.";
        }

        leaf max-packets {
          type uint32;
          default 20000;
          description
           "The maximum number of concurrent reassembly attempts.  If
            this limit is reached, an additional reassembly will cause
            random eviction of an ongoing reassembly. Note that this
            setting directly affects memory usage; the memory buffer
            allocated to reassembly is this maximum number of
            reassemblies times 25 kilobytes each.";
        }
      }
    }


    list instance {
      description
       "Provides configuration for specific instances of the lwAFTR.
        These configuration options will only affect the specific lwaftr
        with the given name specified in the name leaf. The other options
        not present in this list are shared amongst all instances.";

      key "device";

      leaf device {
        type string;
        description
          "The PCI device the instance should use during lwAFTR operation. If
           device is configured in on-a-stick mode, the 'external-interface'
           device should not be configured. If the 'external-interface is
           specified this option should specify the PCI device of the
           'internal-interface' (IPv6 traffic only).";
      }

      list queue {
        description "List of Receive-Side Scaling (RSS) queues.";
        key "id";

        leaf id {
          type uint8 { range 0..1; }
          description
          "RSS queue on which to attach.  Traffic will be partitioned
           evenly between instances servicing queues on the same
           interface.  The queue to which an incoming packet is assigned
           is a function of the TCP or UDP source and destination ports
           (if any) and the source and destination IPv4 or IPv6
           addresses.  Fragmented packets will be delivered to the
           lowest-numbered queue.

           Note that currently the lwAFTR is restricted to running at
           most 2 RSS workers per device.  This limitation may be lifted
           to 4 soon.  Raising it farther is possible but needs changes
           to how the lwAFTR uses its PCI devices.";
        }

        container external-interface {
          leaf ip {
            type inet:ipv4-address;
            mandatory true;
            description
            "L3 Address of the internet-facing network interface.  Used
              when generating error messages and responding to ICMP echo
              requests.";
          }
          leaf device {
            description
             "PCI device of the instance uses for external IPv6 traffic. If this
              is left unspecified the lwAFTR configures itself in on-a-stick
              mode.";
            type string;
          }
          leaf mac {
            type yang:mac-address;
            mandatory true;
            description
              "MAC address of the internet-facing NIC.";
          }

          uses vlan-tagging;

          container next-hop {
            choice address {
              mandatory true;
              case ip {
                leaf ip {
                  type inet:ipv4-address;
                  description
                  "IPv4 address of the next hop for the internet-facing NIC.
                    The lwAFTR will resolve this to a MAC address using ARP.";
                }
                leaf resolved-mac {
                  config false;
                  description "Resolved next-hop mac address found by ARP.";
                  type yang:mac-address;
                }
              }
              case mac {
                leaf mac {
                  type yang:mac-address;
                  description
                  "Statically configured MAC address of the next hop for the
                    internet-facing NIC.";
                }
              }
            }
          }
        }

        container internal-interface {
          leaf ip {
            type inet:ipv6-address;
            mandatory true;
            description
            "L3 Address of the internal-facing network interface.  Used
              when generating error messages and responding to ICMP echo
              requests.";
          }
          leaf mac {
            type yang:mac-address;
            mandatory true;
            description
              "MAC address of the internal-facing NIC.";
          }

          uses vlan-tagging;


          container next-hop {
            choice address {
              mandatory true;
              case ip {
                leaf ip {
                  type inet:ipv6-address;
                  description
                  "IPv4 address of the next hop for the internet-facing NIC.
                    The lwAFTR will resolve this to a MAC address using ARP.";
                }
                leaf resolved-mac {
                  config false;
                  description "Resolved next-hop mac address found by ARP.";
                  type yang:mac-address;
                }
              }
              case mac {
                leaf mac {
                  type yang:mac-address;
                  description
                  "Statically configured MAC address of the next hop for the
                    internet-facing NIC.";
                }
              }
            }
          }
        }
      }

      uses state-counters;
    }

    container external-interface {
      description
       "Configuration for the external, internet-facing IPv4
        interface.";

      leaf mtu {
        type uint16;
        default 1460;
        description
         "Maximum packet size to send on the IPv4 interface.";
      }

      leaf mru {
        type uint16;
        default 1460;
        description
         "Maximum packet size to receive on the IPv4 interface.";
      }

      uses traffic-filters;
      uses icmp-policy;
      uses error-rate-limiting;
      uses reassembly;


    }

    container internal-interface {
      description
       "Configuration for the internal IPv6 interface.";

      leaf mtu {
        type uint16;
        default 1500;
        description
         "Maximum packet size to sent on the IPv6 interface.";
      }

      leaf mru {
        type uint16;
        default 1460;
        description
         "Maximum packet size to recieve on the IPv6 interface.";
      }

      leaf flow-label {
        type uint32;
        default 0;
        description
          "IPv6 flow label";
      }

      uses traffic-filters;
      uses icmp-policy;
      uses vlan-tagging;
      uses error-rate-limiting;
      uses reassembly;

      leaf hairpinning {
        type boolean;
        default true;
        description
         "Indicates whether to support hairpinning of traffic between
          two B4s.";
      }
    }

    container binding-table {
      description
       "A collection of softwires (tunnels), along with a description
        of the IPv4 and IPv6 addresses handled by the lwAFTR.";

      list softwire {
        key "ipv4 psid";

        leaf ipv4 {
          type inet:ipv4-address;
          mandatory true;
          description
           "Public IPv4 address of the softwire.";
        }

        leaf padding {
          type uint16;
          default 0;
        }

        leaf br-address {
          type inet:ipv6-address;
          mandatory true;
          description
           "The B4-facing address of the lwAFTR for this softwire.";
        }

        leaf b4-ipv6 {
          type inet:ipv6-address;
          mandatory true;
          description
           "B4 address.";
        }

        leaf psid {
          type uint16;
          mandatory true;
          description "Port set ID.";
        }

        container port-set {
          description
          "The set of IPv4 addresses managed by the lwAFTR, along with
            the way in which those IPv4 addresses share ports.  A PSID map
            entry associates a PSID length and reserved-ports-bit-count
            with each IPv4 address served by the lwAFTR.

            The lightweight 4-over-6 architecture supports sharing of
            IPv4 addresses by partitioning the space of TCP/UDP/ICMP
            ports into disjoint \"port sets\".  Each softwire associated
            with an IPv4 address corresponds to a different set of ports
            on that address.  The way that the ports are partitioned is
            specified in RFC 7597:  each address has an associated set
            of parameters that specifies how to compute a \"port set
            identifier\" (PSID) from a given port.

                                0                   1
                                0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
                                +-----------+-----------+-------+
                  Ports in      |     A     |    PSID   |   j   |
              the CE port set   |    > 0    |           |       |
                                +-----------+-----------+-------+
                                |  a bits   |  k bits   |m bits |

                Figure 2: Structure of a Port-Restricted Port Field

              Source: http://tools.ietf.org/html/rfc7597#section-5.1

            We find the specification's names to be a bit obtuse, so we
            refer to them using the following names:

              a bits = reserved-ports-bit-count.
              k bits = psid-length.
              m bits = shift.

            The shift parameter is calculated from psid-length and
            reserved-ports-bit-count. The calculation performed to
            get the value of shift is:

              shift = 16 - psid-length - reserved-ports-bit-count";

          leaf psid-length {
            type uint8 { range 0..16; }
            mandatory true;
            description
            "The number of bits devoted to the PSID in the port map.
              If the psid-length is N, then the IPv4 address will be
              shared 2^N ways.  Note that psid-length, shift, and
              reserved-ports-bit-count must add up to 16.";
          }

          leaf reserved-ports-bit-count {
            type uint8 { range 0..16; }
            default 0;
            description
            "Reserve the lowest 2^N ports so that they map to no
              softwire.  This can be useful to prevent the low 1024
              ports (for example) from being mapped to customers.  Note
              that psid-length and shift must add up to less than or
              equal to 16.";
          }
        }
      }

      container version {
        description
         "Optional versioning for binding table. The vesioning information
          will change on every update or change to the binding table.";

        leaf number {
          type uint64;
          description "Incremental version number.";
        }
        leaf date {
          type yang:date-and-time;
          description "Timestamp of last change.";
        }
      }
    }
  }

  uses state-counters;
}
