diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/bgp.json b/src/sonic-yang-models/tests/yang_model_tests/tests/bgp.json index d98ca3796d6..6280322926c 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/bgp.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/bgp.json @@ -242,6 +242,53 @@ "BGP_SENTINEL_INVALID_RANGE_IPV6": { "desc": "does not satisfy.", "eStr": "Invalid value \"fc00:f0::/129\" in \"ip_range\" element." + }, + "BGP_GLOBALS_RR_CLUSTER_ID_DOTTED_VALID": { + "desc": "rr_cluster_id accepts dotted-quad notation." + }, + "BGP_GLOBALS_RR_CLUSTER_ID_INTEGER_VALID": { + "desc": "rr_cluster_id accepts a 32-bit integer (top of range, unambiguously not dotted-quad)." + }, + "BGP_GLOBALS_RR_CLUSTER_ID_INVALID": { + "desc": "rr_cluster_id must reject a value that is neither an IPv4 address nor a 32-bit integer.", + "eStrKey": "InvalidValue", + "eStr": ["rr_cluster_id"] + }, + "BGP_GLOBALS_AF_SRPOLICY_INVALID": { + "desc": "BGP_GLOBALS_AF has no global AFI-SAFI configuration for SR-Policy SAFI; afi_safi=ipv4_srpolicy must be rejected outright by the restricted key type.", + "eStrKey": "InvalidValue", + "eStr": ["afi_safi"] + }, + "BGP_GLOBALS_AF_AFI_SAFI_HYPHENATED_INVALID": { + "desc": "BGP_GLOBALS_AF with a hyphenated afi_safi spelling (ipv4-unicast) must be rejected; the canonical form is underscore-separated.", + "eStrKey": "InvalidValue", + "eStr": ["afi_safi"] + }, + "BGP_GLOBALS_AF_AGGREGATE_ADDR_SRPOLICY_INVALID": { + "desc": "BGP_GLOBALS_AF_AGGREGATE_ADDR with an SR-Policy afi_safi must be rejected by the restricted key type.", + "eStrKey": "InvalidValue", + "eStr": ["afi_safi"] + }, + "BGP_GLOBALS_AF_NETWORK_SRPOLICY_INVALID": { + "desc": "BGP_GLOBALS_AF_NETWORK with an SR-Policy afi_safi must be rejected by the restricted key type.", + "eStrKey": "InvalidValue", + "eStr": ["afi_safi"] + }, + "BGP_NEIGHBOR_AF_L2VPN_EVPN_VALID": { + "desc": "BGP_NEIGHBOR_AF accepts l2vpn_evpn, which is required to activate a neighbor for EVPN." + }, + "BGP_NEIGHBOR_AF_AFI_SAFI_HYPHENATED_INVALID": { + "desc": "BGP_NEIGHBOR_AF with a hyphenated afi_safi spelling (ipv4-unicast) must be rejected; the canonical form is underscore-separated.", + "eStrKey": "InvalidValue", + "eStr": ["afi_safi"] + }, + "BGP_PEER_GROUP_AF_SRPOLICY_VALID": { + "desc": "BGP_PEER_GROUP_AF (with BGP_NEIGHBOR_AF) is one of only two tables carrying the full bgp_afi_safi vocabulary; both SR-Policy families must remain admissible keys." + }, + "BGP_PEER_GROUP_AF_AFI_SAFI_HYPHENATED_INVALID": { + "desc": "BGP_PEER_GROUP_AF with a hyphenated afi_safi spelling (ipv4-unicast) must be rejected; the canonical form is underscore-separated.", + "eStrKey": "InvalidValue", + "eStr": ["afi_safi"] } } diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/bgp_device_global.json b/src/sonic-yang-models/tests/yang_model_tests/tests/bgp_device_global.json index e2ef3992f26..039359fec0d 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/bgp_device_global.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/bgp_device_global.json @@ -77,6 +77,19 @@ "BGP_DEVICE_GLOBAL_CONFED" : { "desc": "Load bgp device global table with confederation asn and peers" }, + "BGP_DEVICE_GLOBAL_CONFED_PEERS_SINGLE_VALID" : { + "desc": "Load bgp device global table with a single confederation sub-ASN and no separator" + }, + "BGP_DEVICE_GLOBAL_CONFED_PEERS_TRAILING_SEPARATOR_INVALID" : { + "desc": "A trailing semi-colon in the confederation peers list must be rejected", + "eStrKey": "Pattern", + "eStr": ["peers"] + }, + "BGP_DEVICE_GLOBAL_CONFED_PEERS_NON_NUMERIC_INVALID" : { + "desc": "A non-numeric sub-ASN in the confederation peers list must be rejected", + "eStrKey": "Pattern", + "eStr": ["peers"] + }, "BGP_DEVICE_GLOBAL_CONFED_INVALID_ASN" : { "desc": "Load bgp device global table with confederation invalid asn", "eStrKey": "InvalidValue", diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests_config/bgp.json b/src/sonic-yang-models/tests/yang_model_tests/tests_config/bgp.json index 99ea273c12f..301465248f9 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests_config/bgp.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests_config/bgp.json @@ -2160,6 +2160,268 @@ ] } } + }, + + "BGP_GLOBALS_AF_SRPOLICY_INVALID": { + "sonic-bgp-global:sonic-bgp-global": { + "sonic-bgp-global:BGP_GLOBALS": { + "BGP_GLOBALS_LIST": [ + { + "vrf_name": "default", + "local_asn": 65001 + } + ] + }, + "sonic-bgp-global:BGP_GLOBALS_AF": { + "BGP_GLOBALS_AF_LIST": [ + { + "vrf_name": "default", + "afi_safi": "ipv4_srpolicy" + } + ] + } + } + }, + "BGP_GLOBALS_AF_AFI_SAFI_HYPHENATED_INVALID": { + "sonic-bgp-global:sonic-bgp-global": { + "sonic-bgp-global:BGP_GLOBALS": { + "BGP_GLOBALS_LIST": [ + { + "vrf_name": "default", + "local_asn": 65001 + } + ] + }, + "sonic-bgp-global:BGP_GLOBALS_AF": { + "BGP_GLOBALS_AF_LIST": [ + { + "vrf_name": "default", + "afi_safi": "ipv4-unicast" + } + ] + } + } + }, + "BGP_GLOBALS_AF_AGGREGATE_ADDR_SRPOLICY_INVALID": { + "sonic-bgp-global:sonic-bgp-global": { + "sonic-bgp-global:BGP_GLOBALS": { + "BGP_GLOBALS_LIST": [ + { + "vrf_name": "default", + "local_asn": 65001 + } + ] + }, + "sonic-bgp-global:BGP_GLOBALS_AF_AGGREGATE_ADDR": { + "BGP_GLOBALS_AF_AGGREGATE_ADDR_LIST": [ + { + "vrf_name": "default", + "afi_safi": "ipv4_srpolicy", + "ip_prefix": "192.168.0.0/24" + } + ] + } + } + }, + "BGP_GLOBALS_AF_NETWORK_SRPOLICY_INVALID": { + "sonic-bgp-global:sonic-bgp-global": { + "sonic-bgp-global:BGP_GLOBALS": { + "BGP_GLOBALS_LIST": [ + { + "vrf_name": "default", + "local_asn": 65001 + } + ] + }, + "sonic-bgp-global:BGP_GLOBALS_AF_NETWORK": { + "BGP_GLOBALS_AF_NETWORK_LIST": [ + { + "vrf_name": "default", + "afi_safi": "ipv4_srpolicy", + "ip_prefix": "192.168.0.0/24" + } + ] + } + } + }, + "BGP_NEIGHBOR_AF_L2VPN_EVPN_VALID": { + "sonic-bgp-global:sonic-bgp-global": { + "sonic-bgp-global:BGP_GLOBALS": { + "BGP_GLOBALS_LIST": [ + { + "vrf_name": "default", + "local_asn": 65001 + } + ] + } + }, + "sonic-bgp-neighbor:sonic-bgp-neighbor": { + "sonic-bgp-neighbor:BGP_NEIGHBOR": { + "BGP_NEIGHBOR_LIST": [ + { + "vrf_name": "default", + "neighbor": "20.0.0.1", + "local_asn": 1, + "name": "BGP nbr 1", + "asn": 65003 + } + ] + }, + "sonic-bgp-neighbor:BGP_NEIGHBOR_AF": { + "BGP_NEIGHBOR_AF_LIST": [ + { + "vrf_name": "default", + "neighbor": "20.0.0.1", + "afi_safi": "l2vpn_evpn", + "admin_status": "up" + } + ] + } + } + }, + "BGP_NEIGHBOR_AF_AFI_SAFI_HYPHENATED_INVALID": { + "sonic-bgp-global:sonic-bgp-global": { + "sonic-bgp-global:BGP_GLOBALS": { + "BGP_GLOBALS_LIST": [ + { + "vrf_name": "default", + "local_asn": 65001 + } + ] + } + }, + "sonic-bgp-neighbor:sonic-bgp-neighbor": { + "sonic-bgp-neighbor:BGP_NEIGHBOR": { + "BGP_NEIGHBOR_LIST": [ + { + "vrf_name": "default", + "neighbor": "20.0.0.1", + "local_asn": 1, + "name": "BGP nbr 1", + "asn": 65003 + } + ] + }, + "sonic-bgp-neighbor:BGP_NEIGHBOR_AF": { + "BGP_NEIGHBOR_AF_LIST": [ + { + "vrf_name": "default", + "neighbor": "20.0.0.1", + "afi_safi": "ipv4-unicast", + "admin_status": "up" + } + ] + } + } + }, + "BGP_PEER_GROUP_AF_AFI_SAFI_HYPHENATED_INVALID": { + "sonic-bgp-global:sonic-bgp-global": { + "sonic-bgp-global:BGP_GLOBALS": { + "BGP_GLOBALS_LIST": [ + { + "vrf_name": "default", + "local_asn": 65001 + } + ] + } + }, + "sonic-bgp-peergroup:sonic-bgp-peergroup": { + "sonic-bgp-peergroup:BGP_PEER_GROUP": { + "BGP_PEER_GROUP_LIST": [ + { + "vrf_name": "default", + "peer_group_name": "PG1" + } + ] + }, + "sonic-bgp-peergroup:BGP_PEER_GROUP_AF": { + "BGP_PEER_GROUP_AF_LIST": [ + { + "vrf_name": "default", + "peer_group_name": "PG1", + "afi_safi": "ipv4-unicast", + "admin_status": "up" + } + ] + } + } + }, + "BGP_PEER_GROUP_AF_SRPOLICY_VALID": { + "sonic-bgp-global:sonic-bgp-global": { + "sonic-bgp-global:BGP_GLOBALS": { + "BGP_GLOBALS_LIST": [ + { + "vrf_name": "default", + "local_asn": 65001 + } + ] + } + }, + "sonic-bgp-peergroup:sonic-bgp-peergroup": { + "sonic-bgp-peergroup:BGP_PEER_GROUP": { + "BGP_PEER_GROUP_LIST": [ + { + "vrf_name": "default", + "peer_group_name": "PG1" + } + ] + }, + "sonic-bgp-peergroup:BGP_PEER_GROUP_AF": { + "BGP_PEER_GROUP_AF_LIST": [ + { + "vrf_name": "default", + "peer_group_name": "PG1", + "afi_safi": "ipv4_srpolicy", + "admin_status": "up" + }, + { + "vrf_name": "default", + "peer_group_name": "PG1", + "afi_safi": "ipv6_srpolicy", + "admin_status": "up" + } + ] + } + } + }, + "BGP_GLOBALS_RR_CLUSTER_ID_DOTTED_VALID": { + "sonic-bgp-global:sonic-bgp-global": { + "sonic-bgp-global:BGP_GLOBALS": { + "BGP_GLOBALS_LIST": [ + { + "vrf_name": "default", + "local_asn": 65001, + "rr_cluster_id": "1.1.1.1" + } + ] + } + } + }, + "BGP_GLOBALS_RR_CLUSTER_ID_INTEGER_VALID": { + "sonic-bgp-global:sonic-bgp-global": { + "sonic-bgp-global:BGP_GLOBALS": { + "BGP_GLOBALS_LIST": [ + { + "vrf_name": "default", + "local_asn": 65001, + "rr_cluster_id": "4294967295" + } + ] + } + } + }, + "BGP_GLOBALS_RR_CLUSTER_ID_INVALID": { + "sonic-bgp-global:sonic-bgp-global": { + "sonic-bgp-global:BGP_GLOBALS": { + "BGP_GLOBALS_LIST": [ + { + "vrf_name": "default", + "local_asn": 65001, + "rr_cluster_id": "cluster-one" + } + ] + } + } } } diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests_config/bgp_device_global.json b/src/sonic-yang-models/tests/yang_model_tests/tests_config/bgp_device_global.json index 23f46d9cd6d..9ffd847fdda 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests_config/bgp_device_global.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests_config/bgp_device_global.json @@ -123,6 +123,36 @@ } } }, + "BGP_DEVICE_GLOBAL_CONFED_PEERS_SINGLE_VALID": { + "sonic-bgp-device-global:sonic-bgp-device-global": { + "sonic-bgp-device-global:BGP_DEVICE_GLOBAL": { + "CONFED": { + "asn": 65100, + "peers": "66000" + } + } + } + }, + "BGP_DEVICE_GLOBAL_CONFED_PEERS_TRAILING_SEPARATOR_INVALID": { + "sonic-bgp-device-global:sonic-bgp-device-global": { + "sonic-bgp-device-global:BGP_DEVICE_GLOBAL": { + "CONFED": { + "asn": 65100, + "peers": "66000;63000;" + } + } + } + }, + "BGP_DEVICE_GLOBAL_CONFED_PEERS_NON_NUMERIC_INVALID": { + "sonic-bgp-device-global:sonic-bgp-device-global": { + "sonic-bgp-device-global:BGP_DEVICE_GLOBAL": { + "CONFED": { + "asn": 65100, + "peers": "66000;abc" + } + } + } + }, "BGP_DEVICE_GLOBAL_CONFED_INVALID_ASN": { "sonic-bgp-device-global:sonic-bgp-device-global": { "sonic-bgp-device-global:BGP_DEVICE_GLOBAL": { diff --git a/src/sonic-yang-models/yang-models/sonic-bgp-common.yang b/src/sonic-yang-models/yang-models/sonic-bgp-common.yang index 74595e3fde6..4f75001b14c 100644 --- a/src/sonic-yang-models/yang-models/sonic-bgp-common.yang +++ b/src/sonic-yang-models/yang-models/sonic-bgp-common.yang @@ -49,11 +49,56 @@ module sonic-bgp-common { description "SONIC BGP common YANG attributes for Neighbors and Peer group"; + revision 2026-07-22 { + description + "Add bgp_afi_safi typedef (and the bgp_afi_safi_global restriction) and use it for + the afi_safi list keys, which were previously an unconstrained 'type string'. + Constraining the key rejects non-canonical spellings such as 'ipv4-unicast' at + validation time and lets YANG-derived CLIs offer the valid values as completion + candidates."; + } + revision 2021-02-26 { description "Initial revision."; } + typedef bgp_afi_safi { + type enumeration { + enum ipv4_unicast { + description "IPv4 unicast address family"; + } + enum ipv6_unicast { + description "IPv6 unicast address family"; + } + enum l2vpn_evpn { + description "L2VPN EVPN address family"; + } + enum ipv4_srpolicy { + description "IPv4 SR-Policy address family"; + } + enum ipv6_srpolicy { + description "IPv6 SR-Policy address family"; + } + } + description + "Address family identifier and subsequent address family identifier, as stored + in CONFIG_DB. The underscore-separated form is canonical; hyphenated spellings + such as 'ipv4-unicast' are not valid."; + } + + typedef bgp_afi_safi_global { + type bgp_afi_safi { + enum ipv4_unicast; + enum ipv6_unicast; + enum l2vpn_evpn; + } + description + "bgp_afi_safi restricted to the address families valid in a BGP global + address-family context. The SR-Policy families are excluded; SR-Policy is + configured per-neighbor on BGP_NEIGHBOR_AF / BGP_PEER_GROUP_AF."; + } + typedef bgp_peer_type { type enumeration { enum internal { @@ -337,7 +382,7 @@ module sonic-bgp-common { grouping sonic-bgp-cmn-af { leaf afi_safi { - type string; + type bgp_afi_safi; description "Address family"; } diff --git a/src/sonic-yang-models/yang-models/sonic-bgp-device-global.yang b/src/sonic-yang-models/yang-models/sonic-bgp-device-global.yang index d2b675e6082..d3b9d5b3ee1 100644 --- a/src/sonic-yang-models/yang-models/sonic-bgp-device-global.yang +++ b/src/sonic-yang-models/yang-models/sonic-bgp-device-global.yang @@ -12,6 +12,11 @@ module sonic-bgp-device-global { description "SONIC Device-specific BGP global data"; + revision 2026-07-22 { + description "Add a pattern to the BGP confederation peers leaf, previously an + unconstrained string, enforcing its semi-colon-separated sub-ASN shape."; + } + revision 2026-04-28 { description "Add chassis_tsa_supported to select CHASSIS_APP_DB vs per-linecard TSA orchestration"; } @@ -88,8 +93,12 @@ module sonic-bgp-device-global { /* List of peer ASN part of the confederation */ leaf peers { - type string; - description "List of sub-ASNs in the confederation separated by semi-colon"; + type string { + pattern "[1-9][0-9]*(;[1-9][0-9]*)*"; + } + description "List of sub-ASNs in the confederation separated by semi-colon. + The pattern enforces the semi-colon-separated shape; it does not + range-check each sub-ASN against the 32-bit AS number maximum."; } } /* end of CONFED container */ diff --git a/src/sonic-yang-models/yang-models/sonic-bgp-global.yang b/src/sonic-yang-models/yang-models/sonic-bgp-global.yang index 6fc54b00ccb..d9f88211590 100644 --- a/src/sonic-yang-models/yang-models/sonic-bgp-global.yang +++ b/src/sonic-yang-models/yang-models/sonic-bgp-global.yang @@ -19,6 +19,10 @@ module sonic-bgp-global { prefix ext; } + import sonic-bgp-common { + prefix bgpcmn; + } + organization "SONiC"; @@ -28,6 +32,15 @@ module sonic-bgp-global { description "SONIC BGP Global YANG"; + revision 2026-07-22 { + description + "Constrain the afi_safi keys of BGP_GLOBALS_AF_LIST, BGP_GLOBALS_AF_AGGREGATE_ADDR_LIST + and BGP_GLOBALS_AF_NETWORK_LIST to bgp_afi_safi_global instead of an unconstrained + string, so the SR-Policy families are rejected at validation time. + Also constrain rr_cluster_id, previously an unconstrained string, to a union of an + IPv4 address and a 32-bit integer."; + } + revision 2021-02-26 { description "Initial revision."; @@ -113,8 +126,15 @@ module sonic-bgp-global { } leaf rr_cluster_id { - type string; - description "Route reflector cluster ID used to identify the reflector cluster."; + type union { + type inet:ipv4-address; + type uint32 { + range "1..4294967295"; + } + } + description "Route reflector cluster ID used to identify the reflector cluster. + Expressed either in dotted-quad notation or as a non-zero 32-bit + integer (1..4294967295)."; } leaf rr_allow_out_policy { @@ -333,7 +353,7 @@ module sonic-bgp-global { } leaf afi_safi { - type string; + type bgpcmn:bgp_afi_safi_global; description "Address family name and subsequent address family name"; } @@ -478,7 +498,7 @@ module sonic-bgp-global { } leaf afi_safi { - type string; + type bgpcmn:bgp_afi_safi_global; description "Address family name and subsequent address family name"; } @@ -518,7 +538,7 @@ module sonic-bgp-global { } leaf afi_safi { - type string; + type bgpcmn:bgp_afi_safi_global; description "Address family name and subsequent address family name"; }