diff --git a/src/sonic-yang-models/doc/Configuration.md b/src/sonic-yang-models/doc/Configuration.md index a7726d8b5695..bfc97850bbfa 100644 --- a/src/sonic-yang-models/doc/Configuration.md +++ b/src/sonic-yang-models/doc/Configuration.md @@ -26,6 +26,9 @@ Table of Contents * [Device Metadata](#device-metadata) * [Device neighbor metada](#device-neighbor-metada) * [DSCP_TO_TC_MAP](#dscp_to_tc_map) + * [FG_NHG](#fg_nhg) + * [FG_NHG_MEMBER](#fg_nhg_member) + * [FG_NHG_PREFIX](#fg_nhg_prefix) * [FLEX_COUNTER_TABLE](#flex_counter_table) * [Hash](#hash) * [KDUMP](#kdump) @@ -892,6 +895,57 @@ instance is supported in SONiC. ``` +### FG_NHG + +The FG_NHG table provides information on Next Hop Groups, including a specified Hash Bucket Size (bucket_size) and match mode for each group. + +``` +"FG_NHG": { + "fgnhg_v4": { + "bucket_size": "120", + "match_mode": "nexthop-based" + }, + "fgnhg_v6": { + "bucket_size": "120", + "match_mode": "nexthop-based" + } +} +``` + +### FG_NHG_MEMBER + +The FG_NHG_MEMBER table provides information about the members of a next hop group, including the group name (FG_NHG), the index at which redistribution is performed (bank), and the link associated with the next-hop-ip (link). + +``` +"FG_NHG_MEMBER": { + "200.200.200.4": { + "FG_NHG": "fgnhg_v4", + "bank": "0", + "link": "Ethernet8" + }, + "200.200.200.5": { + "FG_NHG": "fgnhg_v4", + "bank": "1", + "link": "Ethernet12" + } +} +``` + +### FG_NHG_PREFIX + +The FG_NHG_PREFIX table provides the FG_NHG_PREFIX for which FG behavior is desired, and Fine Grained next-hop group name. + +``` +"FG_NHG_PREFIX": { + "100.50.25.12/32": { + "FG_NHG": "fgnhg_v4" + }, + "fc:05::/128": { + "FG_NHG": "fgnhg_v6" + } +} +``` + ### MPLS_TC_TO_TC_MAP ``` diff --git a/src/sonic-yang-models/setup.py b/src/sonic-yang-models/setup.py index 2736465ead3e..26582723f132 100644 --- a/src/sonic-yang-models/setup.py +++ b/src/sonic-yang-models/setup.py @@ -116,6 +116,7 @@ def run(self): './yang-models/sonic-events-syncd.yang', './yang-models/sonic-extension.yang', './yang-models/sonic-flex_counter.yang', + './yang-models/sonic-fine-grained-ecmp.yang', './yang-models/sonic-feature.yang', './yang-models/sonic-hash.yang', './yang-models/sonic-system-defaults.yang', @@ -203,6 +204,7 @@ def run(self): './cvlyang-models/sonic-extension.yang', './cvlyang-models/sonic-flex_counter.yang', './cvlyang-models/sonic-feature.yang', + './cvlyang-models/sonic-fine-grained-ecmp.yang', './cvlyang-models/sonic-hash.yang', './cvlyang-models/sonic-system-defaults.yang', './cvlyang-models/sonic-interface.yang', diff --git a/src/sonic-yang-models/tests/files/sample_config_db.json b/src/sonic-yang-models/tests/files/sample_config_db.json index 8b80631f4fb4..e326ee07852b 100644 --- a/src/sonic-yang-models/tests/files/sample_config_db.json +++ b/src/sonic-yang-models/tests/files/sample_config_db.json @@ -2273,6 +2273,46 @@ "vni": "10", "guid":"guid-vnet1" } + }, + "FG_NHG": { + "nhg1": { + "bucket_size": "16", + "match_mode": "nexthop-based" + }, + "nhg2": { + "bucket_size": "32", + "match_mode": "route-based" + } + }, + "FG_NHG_PREFIX": { + "10.0.0.0/24": { + "FG_NHG": "nhg1" + }, + "192.168.0.0/16": { + "FG_NHG": "nhg2" + } + }, + "FG_NHG_MEMBER": { + "192.168.1.1": { + "FG_NHG": "nhg1", + "bank": "0", + "link": "Ethernet1" + }, + "192.168.1.2": { + "FG_NHG": "nhg1", + "bank": "0", + "link": "Ethernet2" + }, + "10.0.0.1": { + "FG_NHG": "nhg2", + "bank": "1", + "link": "PortChannel42" + }, + "10.0.0.2": { + "FG_NHG": "nhg2", + "bank": "1", + "link": "PortChannel2" + } } }, "SAMPLE_CONFIG_DB_UNKNOWN": { diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/fine-grained-ecmp.json b/src/sonic-yang-models/tests/yang_model_tests/tests/fine-grained-ecmp.json new file mode 100644 index 000000000000..2eed9fb8f34f --- /dev/null +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/fine-grained-ecmp.json @@ -0,0 +1,59 @@ +{ + "FG_NHG_TEST": { + "desc": "Fine-grained ECMP next-hop group configuration in FG_NHG_LIST table." + }, + "FG_NHG_PREFIX_TEST": { + "desc": "Fine-grained ECMP prefix configuration in FG_NHG_PREFIX_LIST table." + }, + "FG_NHG_MEMBER_TEST": { + "desc": "Fine-grained ECMP next-hop member configuration in FG_NHG_MEMBER_LIST table." + }, + "FG_NHG_MEMBER_MULTI_LINK_TEST": { + "desc": "Fine-grained ECMP next-hop member configuration with multiple links in FG_NHG_MEMBER_LIST table." + }, + "FG_NHG_TEST_DUPLICATE_NAME": { + "desc": "Fine-grained ECMP next-hop group configuration with duplicate name in FG_NHG_LIST table.", + "eStr": "Duplicated instance of \"FG_NHG_LIST\" list." + }, + "FG_NHG_MEMBER_TEST_INVALID_IP": { + "desc": "Fine-grained ECMP next-hop member configuration with invalid IP value in FG_NHG_MEMBER_LIST table.", + "eStrKey": "InvalidValue", + "eStr": [ + "next_hop_ip" + ] + }, + "FG_NHG_PREFIX_TEST_INVALID_PREFIX": { + "desc": "Fine-grained ECMP prefix configuration with invalid prefix value in FG_NHG_PREFIX_LIST table.", + "eStrKey": "InvalidValue", + "eStr": [ + "ip_prefix" + ] + }, + "FG_NHG_MEMBER_TEST_INVALID_LINK": { + "desc": "Fine-grained ECMP next-hop member configuration with invalid link value in FG_NHG_MEMBER_LIST table.", + "eStrKey": "InvalidValue", + "eStr": [ + "link" + ] + }, + "FG_NHG_MEMBER_TEST_MISSING_FG_NHG_REF": { + "desc": "Fine-grained ECMP next-hop member configuration with missing FG_NHG reference in FG_NHG_MEMBER_LIST table.", + "eStr": "Missing required element \"FG_NHG\" in \"FG_NHG_MEMBER_LIST\". " + }, + "FG_NHG_PREFIX_TEST_MISSING_FG_NHG_REF": { + "desc": "Fine-grained ECMP prefix configuration with missing FG_NHG reference in FG_NHG_PREFIX_LIST table.", + "eStr": "Missing required element \"FG_NHG\" in \"FG_NHG_PREFIX_LIST\". " + }, + "FG_NHG_MEMBER_TEST_MISSING_BANK": { + "desc": "Fine-grained ECMP next-hop member configuration with missing bank in FG_NHG_MEMBER_LIST table.", + "eStr": "Missing required element \"bank\"" + }, + "FG_NHG_PREFIX_TEST_DUPLICATE_ENTRY": { + "desc": "Fine-grained ECMP prefix configuration with duplicate entry in FG_NHG_PREFIX_LIST table.", + "eStr": "Duplicated instance of \"FG_NHG_PREFIX_LIST\" list." + }, + "FG_NHG_MEMBER_TEST_DUPLICATE_MEMBER": { + "desc": "Fine-grained ECMP next-hop member configuration with duplicate member in FG_NHG_MEMBER_LIST table.", + "eStr": "Duplicated instance of \"FG_NHG_MEMBER_LIST\" list." + } +} \ No newline at end of file diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests_config/fine_grained_ecmp.json b/src/sonic-yang-models/tests/yang_model_tests/tests_config/fine_grained_ecmp.json new file mode 100644 index 000000000000..2bfbbb6239c0 --- /dev/null +++ b/src/sonic-yang-models/tests/yang_model_tests/tests_config/fine_grained_ecmp.json @@ -0,0 +1,395 @@ +{ + "FG_NHG_TEST": { + "sonic-fine-grained-ecmp:sonic-fine-grained-ecmp": { + "sonic-fine-grained-ecmp:FG_NHG": { + "FG_NHG_LIST": [ + { + "name": "group1", + "bucket_size": 10, + "match_mode": "nexthop-based" + }, + { + "name": "group2", + "bucket_size": 20, + "match_mode": "route-based" + } + ] + } + } + }, + "FG_NHG_PREFIX_TEST": { + "sonic-fine-grained-ecmp:sonic-fine-grained-ecmp": { + "sonic-fine-grained-ecmp:FG_NHG": { + "FG_NHG_LIST": [ + { + "name": "group1", + "bucket_size": 10, + "match_mode": "nexthop-based" + }, + { + "name": "group2", + "bucket_size": 20, + "match_mode": "route-based" + } + ] + }, + "sonic-fine-grained-ecmp:FG_NHG_PREFIX": { + "FG_NHG_PREFIX_LIST": [ + { + "ip_prefix": "10.0.0.0/24", + "FG_NHG": "group1" + }, + { + "ip_prefix": "10.1.0.0/24", + "FG_NHG": "group2" + }, + { + "ip_prefix": "fe80::/64", + "FG_NHG": "group1" + }, + { + "ip_prefix": "::/0", + "FG_NHG": "group2" + } + ] + } + } + }, + "FG_NHG_MEMBER_TEST": { + "sonic-port:sonic-port": { + "sonic-port:PORT": { + "PORT_LIST": [ + { + "admin_status": "up", + "alias": "eth0", + "description": "Ethernet0", + "lanes": "65", + "mtu": "9000", + "name": "Ethernet1", + "tpid": "0x8100", + "speed": "25000" + } + ] + } + }, + "sonic-fine-grained-ecmp:sonic-fine-grained-ecmp": { + "sonic-fine-grained-ecmp:FG_NHG": { + "FG_NHG_LIST": [ + { + "name": "group1", + "bucket_size": 10, + "match_mode": "nexthop-based" + }, + { + "name": "group2", + "bucket_size": 20, + "match_mode": "route-based" + } + ] + }, + "sonic-fine-grained-ecmp:FG_NHG_MEMBER": { + "FG_NHG_MEMBER_LIST": [ + { + "next_hop_ip": "10.0.0.1", + "FG_NHG": "group1", + "bank": 1, + "link": "Ethernet1" + }, + { + "next_hop_ip": "10.0.0.2", + "FG_NHG": "group1", + "bank": 2, + "link": "Ethernet1" + }, + { + "next_hop_ip": "10.1.0.1", + "FG_NHG": "group2", + "bank": 3, + "link": "Ethernet1" + }, + { + "next_hop_ip": "2001:0db8:85a3:0000:0000:8a2e:0370:7334", + "FG_NHG": "group1", + "bank": 4, + "link": "Ethernet1" + }, + { + "next_hop_ip": "2001:db8::1", + "FG_NHG": "group2", + "bank": 5, + "link": "Ethernet1" + } + ] + } + } + }, + "FG_NHG_MEMBER_MULTI_LINK_TEST": { + "sonic-port:sonic-port": { + "sonic-port:PORT": { + "PORT_LIST": [ + { + "admin_status": "up", + "alias": "eth0", + "description": "Ethernet0", + "lanes": "65", + "mtu": "9000", + "name": "Ethernet1", + "tpid": "0x8100", + "speed": "25000" + }, + { + "admin_status": "up", + "alias": "eth1", + "description": "Ethernet1", + "lanes": "65", + "mtu": "9000", + "name": "Ethernet2", + "tpid": "0x8100", + "speed": "25000" + } + ] + } + }, + "sonic-fine-grained-ecmp:sonic-fine-grained-ecmp": { + "sonic-fine-grained-ecmp:FG_NHG": { + "FG_NHG_LIST": [ + { + "name": "group1", + "bucket_size": 10, + "match_mode": "nexthop-based" + }, + { + "name": "group2", + "bucket_size": 20, + "match_mode": "route-based" + } + ] + }, + "sonic-fine-grained-ecmp:FG_NHG_MEMBER": { + "FG_NHG_MEMBER_LIST": [ + { + "next_hop_ip": "10.0.0.1", + "FG_NHG": "group1", + "bank": 1, + "link": "Ethernet1" + }, + { + "next_hop_ip": "10.0.0.2", + "FG_NHG": "group1", + "bank": 2, + "link": "Ethernet2" + }, + { + "next_hop_ip": "10.1.0.1", + "FG_NHG": "group2", + "bank": 3, + "link": "Ethernet1" + } + ] + } + } + }, + "FG_NHG_TEST_DUPLICATE_NAME": { + "sonic-fine-grained-ecmp:sonic-fine-grained-ecmp": { + "sonic-fine-grained-ecmp:FG_NHG": { + "FG_NHG_LIST": [ + { + "name": "group1", + "bucket_size": 10, + "match_mode": "nexthop-based" + }, + { + "name": "group1", + "bucket_size": 20, + "match_mode": "route-based" + } + ] + } + } + }, + "FG_NHG_MEMBER_TEST_INVALID_IP": { + "sonic-fine-grained-ecmp:sonic-fine-grained-ecmp": { + "sonic-fine-grained-ecmp:FG_NHG_MEMBER": { + "FG_NHG_MEMBER_LIST": [ + { + "next_hop_ip": "invalid_ip", + "FG_NHG": "group1", + "bank": 1, + "link": "Ethernet1" + } + ] + } + } + }, + "FG_NHG_PREFIX_TEST_INVALID_PREFIX": { + "sonic-fine-grained-ecmp:sonic-fine-grained-ecmp": { + "sonic-fine-grained-ecmp:FG_NHG_PREFIX": { + "FG_NHG_PREFIX_LIST": [ + { + "ip_prefix": "invalid_prefix", + "FG_NHG": "group1" + } + ] + } + } + }, + "FG_NHG_MEMBER_TEST_INVALID_LINK": { + "sonic-port:sonic-port": { + "sonic-port:PORT": { + "PORT_LIST": [ + { + "admin_status": "up", + "alias": "eth0", + "description": "Ethernet0", + "lanes": "65", + "mtu": "9000", + "name": "Ethernet1", + "tpid": "0x8100", + "speed": "25000" + } + ] + } + }, + "sonic-fine-grained-ecmp:sonic-fine-grained-ecmp": { + "sonic-fine-grained-ecmp:FG_NHG": { + "FG_NHG_LIST": [ + { + "name": "group1", + "bucket_size": 10, + "match_mode": "nexthop-based" + } + ] + }, + "sonic-fine-grained-ecmp:FG_NHG_MEMBER": { + "FG_NHG_MEMBER_LIST": [ + { + "next_hop_ip": "10.0.0.1", + "FG_NHG": "group1", + "bank": 1, + "link": "invalidLink" + } + ] + } + } + }, + "FG_NHG_MEMBER_TEST_MISSING_FG_NHG_REF": { + "sonic-port:sonic-port": { + "sonic-port:PORT": { + "PORT_LIST": [ + { + "admin_status": "up", + "alias": "eth0", + "description": "Ethernet0", + "lanes": "65", + "mtu": "9000", + "name": "Ethernet1", + "tpid": "0x8100", + "speed": "25000" + } + ] + } + }, + "sonic-fine-grained-ecmp:sonic-fine-grained-ecmp": { + "sonic-fine-grained-ecmp:FG_NHG_MEMBER": { + "FG_NHG_MEMBER_LIST": [ + { + "next_hop_ip": "10.0.0.1", + "bank": 1, + "link": "Ethernet1" + } + ] + } + } + }, + "FG_NHG_PREFIX_TEST_MISSING_FG_NHG_REF": { + "sonic-fine-grained-ecmp:sonic-fine-grained-ecmp": { + "sonic-fine-grained-ecmp:FG_NHG_PREFIX": { + "FG_NHG_PREFIX_LIST": [ + { + "ip_prefix": "10.0.0.0/24" + } + ] + } + } + }, + "FG_NHG_MEMBER_TEST_MISSING_BANK": { + "sonic-port:sonic-port": { + "sonic-port:PORT": { + "PORT_LIST": [ + { + "admin_status": "up", + "alias": "eth0", + "description": "Ethernet0", + "lanes": "65", + "mtu": "9000", + "name": "Ethernet1", + "tpid": "0x8100", + "speed": "25000" + } + ] + } + }, + "sonic-fine-grained-ecmp:sonic-fine-grained-ecmp": { + "sonic-fine-grained-ecmp:FG_NHG": { + "FG_NHG_LIST": [ + { + "name": "group1", + "bucket_size": 10, + "match_mode": "nexthop-based" + } + ] + }, + "sonic-fine-grained-ecmp:FG_NHG_MEMBER": { + "FG_NHG_MEMBER_LIST": [ + { + "next_hop_ip": "10.0.0.1", + "FG_NHG": "group1", + "link": "Ethernet1" + } + ] + } + } + }, + "FG_NHG_PREFIX_TEST_DUPLICATE_ENTRY": { + "sonic-fine-grained-ecmp:sonic-fine-grained-ecmp": { + "sonic-fine-grained-ecmp:FG_NHG_PREFIX": { + "FG_NHG_PREFIX_LIST": [ + { + "ip_prefix": "10.0.0.0/24", + "FG_NHG": "group1" + }, + { + "ip_prefix": "10.0.0.0/24", + "FG_NHG": "group2" + } + ] + } + } + }, + "FG_NHG_MEMBER_TEST_DUPLICATE_MEMBER": { + "sonic-fine-grained-ecmp:sonic-fine-grained-ecmp": { + "sonic-fine-grained-ecmp:FG_NHG_MEMBER": { + "FG_NHG_MEMBER_LIST": [ + { + "next_hop_ip": "10.0.0.1", + "FG_NHG": "group1", + "bank": 1, + "link": "Ethernet1" + }, + { + "next_hop_ip": "10.0.0.2", + "FG_NHG": "group1", + "bank": 2, + "link": "Ethernet1" + }, + { + "next_hop_ip": "10.0.0.1", + "FG_NHG": "group1", + "bank": 3, + "link": "Ethernet1" + } + ] + } + } + } +} \ No newline at end of file diff --git a/src/sonic-yang-models/yang-models/sonic-fine-grained-ecmp.yang b/src/sonic-yang-models/yang-models/sonic-fine-grained-ecmp.yang new file mode 100644 index 000000000000..b5811f06f0c3 --- /dev/null +++ b/src/sonic-yang-models/yang-models/sonic-fine-grained-ecmp.yang @@ -0,0 +1,171 @@ +module sonic-fine-grained-ecmp { + + yang-version 1.1; + + namespace "http://github.com/sonic-net/sonic-fine-grained-ecmp"; + prefix sfgecmp; + + import ietf-inet-types { + prefix inet; + } + + import sonic-portchannel { + prefix lag; + } + + import sonic-port { + prefix port; + } + + import sonic-types { + prefix stypes; + } + + organization + "SONiC"; + + contact + "SONiC"; + + description + "SONIC Fine Grained ECMP"; + + revision 2023-01-19 { + description "Initial revision."; + } + + typedef match-mode-name { + + type enumeration { + + enum route-based { + description + "Fine grained ecmp is used when the route prefix matches the FG_NHG_PREFIX prefix"; + } + + enum nexthop-based { + description + "Fine grained ecmp is used when the nexthop IPs match the FG_NHG_MEMBER IPs"; + } + + } + + description + "This enumeration type defines the method used to determine whether fine grained ecmp should be applied."; + } + + container sonic-fine-grained-ecmp { + + container FG_NHG { + + description "FG_NHG part of config_db.json"; + + list FG_NHG_LIST{ + + key "name"; + + leaf name{ + type string; + description "FG_NHG group name"; + } + + leaf bucket_size{ + type uint16; + mandatory true; + description "total hash bucket size desired, + recommended value of Lowest Common Multiple + of 1..{max # of next-hops}"; + } + + leaf match_mode{ + type match-mode-name; + mandatory true; + description " The filtering method used to identify + when to use Fine Grained vs regular route handling. + nexthop-based looks to next-hop IP to filter routes + and uses fine grained ecmp when nexthop IPs matches + FG_NHG_MEMBER IPs. route-based looks to prefix to + filter routes, and uses fine grained ecmp when the + route prefix matches the FG_NHG_PREFIX prefix."; + } + } + /* end of list FG_NHG_LIST */ + } + /* end of container FG_NHG */ + + container FG_NHG_PREFIX{ + + description "FG_NHG_PREFIX part of config_db.json"; + + list FG_NHG_PREFIX_LIST{ + + key "ip_prefix"; + + leaf ip_prefix{ + type stypes:sonic-ip-prefix; + description "FG_NHG_PREFIX for which FG behavior is + desired"; + } + + leaf FG_NHG{ + type leafref { + path "/sfgecmp:sonic-fine-grained-ecmp/sfgecmp:FG_NHG/sfgecmp:FG_NHG_LIST/sfgecmp:name"; + } + mandatory true; + description "Fine Grained next-hop group name"; + } + } + /* end of list FG_NHG_PREFIX_LIST */ + } + /* end of container FG_NHG_PREFIX */ + + container FG_NHG_MEMBER{ + + description "FG_NHG_MEMBER part of config_db.json"; + + list FG_NHG_MEMBER_LIST{ + + key "next_hop_ip"; + + leaf next_hop_ip{ + type inet:ip-address; + description "FG_NHG next-hop-ip member associated + with prefix"; + } + + leaf FG_NHG{ + type leafref { + path "/sfgecmp:sonic-fine-grained-ecmp/sfgecmp:FG_NHG/sfgecmp:FG_NHG_LIST/sfgecmp:name"; + } + mandatory true; + description "Fine Grained next-hop group name"; + } + + leaf bank{ + type uint16; + mandatory true; + description "An index which specifies a bank/group + in which the redistribution is performed"; + } + + leaf link{ + type union { + type leafref { + path "/port:sonic-port/port:PORT/port:PORT_LIST/port:name"; + } + type leafref { + path "/lag:sonic-portchannel/lag:PORTCHANNEL/lag:PORTCHANNEL_LIST/lag:name"; + } + } + description "Link associated with next-hop-ip, if + configured, enables next-hop withdrawal/addition + per link's operational state changes"; + } + } + /* end of list FG_NHG_MEMBER_LIST */ + } + /* end of container FG_NHG_MEMBER */ + } + /* end of container sonic-fine-grained-ecmp */ +} +/* end of module sonic-fine-grained-ecmp */ \ No newline at end of file