module bgp-multiprotocol {

     yang-version "1";

     // namespace
     // TODO: change to an ietf or other more generic namespace
     namespace "http://google.com/yang/google-bgp-multiprotocol-cfg";

     prefix "bgp-mp";

     // import some basic inet types
     import ietf-inet-types { prefix inet; }
     import bgp-policy { prefix bgp-pol; }
     import bgp-operational { prefix bgp-op; }

     // meta
     organization
       "Google, AT&T, BT, Microsoft";

     contact
       "Google, Inc.
       1600 Amphitheatre Way
       Mountain View, CA  94043

       AT&T Labs
       200 S. Laurel Avenue
       Middletown, NJ  07748

       BT
       pp. C3L, BT Centre
       81, Newgate Street
       London  EC1A 7AJ
       UK

       Microsoft
       205 108th Ave. NE, Suite 400
       Bellevue, WA 98004";

     description
       "This module is part of a YANG model for BGP protocol
       configuration, focusing on configuration of multiprotocol
       BGP, in particular various relevant address families (AFI) and
       sub-address families (SAFI).
       Identities (rather than enumerated types) are used to identify
       each AFI / SAFI type to make it easier for users to extend to
       pre-standard or custom AFI/SAFI types.  This module is only
       intended to capture the most";

     revision "2014-10-13" {
       description
         "Initial revision";
       reference "TBD";
     }

     // extension statements

     // feature statements

     // identity statements

     identity afi-type {
       description
         "base identity type for BGP address family identifiers (AFI)";
       reference "RFC 4760 - Multiprotocol Extensions for BGP-4";
     }

     identity safi-type {
       description
         "base identity type for BGP subsequent address family
         identifiers (SAFI)";
       reference "RFC 4760 - Multiprotocol Extensions for BGP-4";
     }

     identity ipv4-afi {
       base bgp-mp:afi-type;
       description
         "IPv4 AF identifier (AFI = 1)";
     }

     identity ipv6-afi {
       base bgp-mp:afi-type;
       description
         "IPv6 AF identifier (AFI = 2)";
     }

     identity unicast-safi {
       base bgp-mp:safi-type;
       description
         "unicast SAFI identifier (SAFI = 1)";
     }
     identity l3vpn-unicast-safi {
       base safi-type;
       description
         "L3 / MPLS virtual private networks SAFI (SAFI = 128/129)";
       reference "RFC 4364 - BGP/MPLS IP Virtual Private Networks
       (VPNs)";
     }

     identity labeled-unicast-safi {
       base safi-type;
       description
         "labeled unicast SAFI identifier (SAFI = 4)";
       reference "RFC 3107 - Carrying Label Information in BGP-4";
     }

     identity l2vpn-vpls-afi {
       base afi-type;
       description
         "AFI for BGP L2 VPN / VPLS (AFI = 25)";
       reference "RFC 4761 - Virtual Private LAN Service (VPLS)
       Using BGP for Auto-Discovery and Signaling";
     }

     identity l2vpn-vpls-safi {
       base safi-type;
       description
         "BGP L2 VPN / VPLS service SAFI (SAFI = 65)";
     }

     identity multicast-safi {
       base safi-type;
       description
         "multicast SAFI (SAFI = 2)";
       reference "RFC 4760 - Multiprotocol Extensions for BGP-4";
     }

     identity multicast-vpn-safi {
       base safi-type;
       description
         "Multicast VPN SAFI (SAFI = 5)";
       reference "RFC 6514 - BGP Encodings and Procedures for Multicast
       in MPLS/BGP IP VPNs";
     }

     // typedef statements

     // TODO: move this and other commonly types to a common bgp-types
     // module
     typedef percentage {
       type uint8 {
         range "0..100";
       }
       description
         "Integer indicating a percentage value";
     }

     // grouping statements

     grouping address-family-common {
       description
         "Configuration that is for the address family level,
         but applies across AFI/SAFI";

       container prefix-limit {
         description
         "Configure the maximum number of prefixes that will be
         accepted from a peer.";

         leaf max-prefixes {
           type uint32;
           description
             "Maximum number of prefixes that will be accepted from
             the neighbor.";
         }

         leaf shutdown-threshold-pct {
           type percentage;
           description
             "Threshold on number of prefixes that can be received
             from a neighbor before generation of warning messages
             or log entries.  Expressed as a percentage of
             max-prefixes.";
         }

         leaf restart-timer {
           type decimal64 {
             fraction-digits 2;
           }
           units "seconds";
           description
             "Time interval in seconds after which the BGP session
             is reestablished after being torn down due to exceeding
             the max-prefixes limit.";
         }
       }
       // policies can be applied at a specific AF level
       uses bgp-pol:apply-policy-group;

     }

     grouping ipv4-ipv6-unicast-common {
       description
         "common configuration for base ipv4 and ipv6 unicast; may
         need to be split into separate containers for each of ipv4
         and ipv6";

       container ipv4-ipv6-unicast {
         // YANG uses XPath 1.0 expression syntax
         when "(../../afi-name = 'ipv4-afi' or " +
           "../../afi-name = 'ipv6-afi') " +
           "and ../safi-name = 'unicast-safi'" {
             description
               "Include this container for unicast ipv4 or ipv6
               AFI-specific configuration";
         }
         description "ipv4 unicast config items";

         leaf send-default-route {
           // TODO: consider moving this to policy
           type boolean;
           default "false";
           description "if set to true, send the default route, i.e.,
           0.0.0.0/0 to the neighbor(s)";
         }
       }
     }

     grouping ipv4-l3vpn-unicast-group {
       description
         "configuration group for L3 VPN VRFs for IPv4";

       container ipv4-l3vpn-unicast {
         when "../../afi-name = 'bgp-mp:ipv4-afi' and " +
         "../safi-name = 'l3vpn-unicast-safi'" {
           description
             "Include this container when AFI = ipv4 and
             SAFI = l3vpn-unicast";
         }
         description "ipv4 l3vpn config items";
         list vrfs {
           key name;
           description "list of configured VRFs";

           leaf name {
             type string;
             description "name / identifier of the VRF";
           }

           leaf route-distinguisher {
             // TODO: consider expanding to a union type to make it more
             // convenient to express as AS:addr or other common formats
             type uint64;
             description
               "route distinguisher value assigned to this VRF";
           }

           uses bgp-pol:apply-policy-group;

           /* additional leafs to consider --- should these be in BGP?
           interface-name
           retain-local-label-size
           advertise-best-external
           no-synchronization
           */

         }
       }
     }

     grouping ipv6-l3vpn-unicast-group {
       description
         "configuration group for L3 VPN VRFs for IPv6";

       container ipv6-l3vpn-unicast {
         when "../../afi-name = 'bgp-mp:ipv6-afi' and " +
         "../safi-name = 'l3vpn-unicast-safi'" {
           description
             "Include this container only when AFI = ipv6 and
             SAFI = l3vpn-unicast";
         }
         description "ipv6 l3vpn config items";
       }
     }

     grouping ipv4-labeled-unicast-group {
       description
         "configuration group for IPv4 labeled unicast";
       container ipv4-labeled-unicast {
         when "../../afi-name = 'ipv4-afi' and " +
         "../safi-name = 'labeled-unicast-safi'" {
           description
             "Include this container when AFI = ipv4 and
             SAFI = labeled-unicast";
         }
         description "ipv4 labeled unicast config items";
       }
     }

     grouping l2vpn-group {
       description
         "configuration group for L2 VPN";

       container l2vpn {
         // TODO: confirm that both AFI/SAFI values are set
         // for L2 VPNs
         when "../../afi-name = 'l2vpn-vpls-afi' and " +
         "../safi-name = 'l2vpn-vpls-safi'" {
           description
             "Include this container when AFI = l2vpn-vpls and
             SAFI = l2vpn-vpls";
         }
         description "l2vpn config items";
       }
     }

     grouping ipv4-multicast-vpn-group {
       description
         "configuration group for IPv4 multicast VPNs";

       container ipv4-multicast-vpn {
         when "../../afi-name = 'ipv4-afi' and " +
         "../safi-name = 'multicast-vpn-safi'" {
           description
             "Include this container when AFI = ipv4 and
             SAFI = multicast-vpn";
         }
         description "ipv4 multicast vpn config items";
       }
     }

     grouping ipv6-multicast-vpn-group {
       description
         "configuration group for IPv6 multicast VPNs";

       container ipv6-multicast-vpn {
         when "../../afi-name = 'ipv6-afi' and " +
         "../safi-name = 'multicast-vpn-safi'" {
           description
             "Include this container when AFI = ipv6 and
             SAFI = multicast-vpn";
         }
         description "ipv6 multicast vpn config items";
       }
     }

     grouping address-family-configuration {
       description "Configuration options that are applied at the
       address family level.";

       list afi {

         key "afi-name";
         description
           "Per address-family configuration, uniquely identified by AF
           name.";
         leaf afi-name {
           type identityref {
             base "afi-type";
           }
           description
             "Address family names are drawn from the afi-type base
             identity, which has specific address family types as
             derived identities.";
         }

         list safi {
           key "safi-name";
           description
             "Per subsequent address family configuration, under a
             specific address family.";

           leaf safi-name {
             type identityref {
               base "safi-type";
             }
             description
               "Within each address family, subsequent address family
               names are drawn from the subsequent-address-family base
               identity.";
           }

           // these grouping references conditionally add config nodes
           // that are specific to each AFI / SAFI combination
           uses ipv4-ipv6-unicast-common;
           uses ipv4-l3vpn-unicast-group;
           uses ipv6-l3vpn-unicast-group;
           uses ipv4-labeled-unicast-group;
           uses l2vpn-group;
           uses ipv4-multicast-vpn-group;
           uses ipv6-multicast-vpn-group;

           // this grouping pulls in the config items common across
           // AF/SAFI combinations
           uses address-family-common;

          }
         // operational state common acrossr address families
         uses bgp-op:bgp-op-af-group;
       }
     }

     // data definition statements

     // augment statements

     // rpc statements

     // notification statements

   }