Skip to content

Commit a5210d8

Browse files
zebra: Add ECMP count filtering for sh ip route nhg summary cmd
Add support for filtering routes by ECMP count in the nexthop-group summary command. The new syntax allows filtering routes based on ECMP count: - show ip route nexthop-group summary ecmp-count gt N (greater than) - show ip route nexthop-group summary ecmp-count lt N (less than) - show ip route nexthop-group summary ecmp-count eq N (equal to) and their corresponding json Example: r1# sh ip route sharp nexthop-group summary ecmp-count eq 2 D> 2.2.2.1/32 [150/0] Rcv/Ins NHG ID: 90/90 ECMP/FIB count: 2/2 Status: Installed Flags: Valid, Installed D>* 2.2.2.2/32 [150/0] Rcv/Ins NHG ID: 109/109 ECMP/FIB count: 2/2 Status: Installed Flags: Valid, Installed D> 3.3.3.2/32 [150/0] Rcv/Ins NHG ID: 118/118 ECMP/FIB count: 2/1 Status: Installed Flags: Valid, Installed D> 5.5.5.1/32 [150/0] Rcv/Ins NHG ID: 152/152 ECMP/FIB count: 2/8 Status: Installed Flags: Valid, Installed r1# sh ip route sharp nexthop-group summary ecmp-count lt 2 D> 3.3.3.1/32 [150/0] Rcv/Ins NHG ID: 111/112 ECMP/FIB count: 1/2 Status: Installed Flags: Valid, Recursive r1# sh ip route sharp nexthop-group summary ecmp-count eq 1 json {"3.3.3.1/32":[{"prefix":"3.3.3.1/32","prefixLen":32,"protocol":"sharp", "vrfId":0,"vrfName":"default","selected":true,"destSelected":true, "distance":150,"metric":0,"installed":true,"table":254, "nexthopGroupId":113,"ecmpCount":1,"fibInstalledCount":2, "installedNexthopGroupId":114,"receivedNexthopGroupId":113, "nexthopGroupFlags":9,"nexthopGroupValid":"true"}] } Signed-off-by: Rajasekar Raja <[email protected]>
1 parent 98896ab commit a5210d8

File tree

1 file changed

+73
-34
lines changed

1 file changed

+73
-34
lines changed

zebra/zebra_vty.c

Lines changed: 73 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,12 @@ struct route_show_ctx {
6060
bool header_done; /* common header already displayed */
6161
};
6262

63-
static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
64-
safi_t safi, bool use_fib, bool use_json,
65-
route_tag_t tag,
66-
const struct prefix *longer_prefix_p,
67-
bool supernets_only, int type,
68-
unsigned short ospf_instance_id, uint32_t tableid,
69-
bool show_ng, struct route_show_ctx *ctx);
63+
static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, safi_t safi,
64+
bool use_fib, bool use_json, route_tag_t tag,
65+
const struct prefix *longer_prefix_p, bool supernets_only, int type,
66+
unsigned short ospf_instance_id, uint32_t tableid, bool show_ng,
67+
bool show_nhg_summary, bool ecmp_gt, bool ecmp_lt, bool ecmp_eq,
68+
uint16_t ecmp_count, struct route_show_ctx *ctx);
7069
static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
7170
int mcast, bool use_fib, bool show_ng);
7271
static void vty_show_ip_route_summary(struct vty *vty, struct route_table *table,
@@ -507,7 +506,8 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
507506
}
508507

509508
static void vty_show_ip_route(struct vty *vty, struct route_node *rn, struct route_entry *re,
510-
json_object *json, bool is_fib, bool show_ng, bool show_nhg_summary)
509+
json_object *json, bool is_fib, bool show_ng, bool show_nhg_summary,
510+
bool ecmp_gt, bool ecmp_lt, bool ecmp_eq, uint16_t ecmp_count)
511511
{
512512
const struct nexthop *nexthop;
513513
int len = 0;
@@ -531,6 +531,18 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, struct rou
531531
else
532532
nhg = &(re->nhe->nhg);
533533

534+
/* Apply ECMP count filter if specified */
535+
if (show_nhg_summary && (ecmp_gt || ecmp_lt || ecmp_eq)) {
536+
uint16_t nh_count = nexthop_group_nexthop_num_no_recurse(nhg);
537+
538+
if (ecmp_gt && nh_count <= ecmp_count)
539+
return;
540+
if (ecmp_lt && nh_count >= ecmp_count)
541+
return;
542+
if (ecmp_eq && nh_count != ecmp_count)
543+
return;
544+
}
545+
534546
if (json) {
535547
json_route = json_object_new_object();
536548

@@ -570,7 +582,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, struct rou
570582

571583
/* NHG Summary JSON output */
572584
if (show_nhg_summary) {
573-
uint16_t ecmp_count = nexthop_group_nexthop_num_no_recurse(nhg);
585+
uint16_t nh_ecmp_count = nexthop_group_nexthop_num_no_recurse(nhg);
574586
uint16_t fib_nh_count = nexthop_group_fib_nexthop_num(nhg);
575587

576588
if (re->tag)
@@ -579,8 +591,8 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, struct rou
579591
if (re->table)
580592
json_object_int_add(json_route, "table", re->table);
581593

582-
json_object_int_add(json_route, "nextHopGroupId", re->nhe_id);
583-
json_object_int_add(json_route, "ecmpCount", ecmp_count);
594+
json_object_int_add(json_route, "nextHopGroupId", re->nhe_id);
595+
json_object_int_add(json_route, "ecmpCount", nh_ecmp_count);
584596
json_object_int_add(json_route, "fibInstalledCount", fib_nh_count);
585597

586598
if (re->nhe_installed_id != 0)
@@ -706,13 +718,13 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, struct rou
706718

707719
/* Show ECMP summary instead of full nexthop details */
708720
if (show_nhg_summary) {
709-
uint16_t ecmp_count = nexthop_group_nexthop_num_no_recurse(nhg);
721+
uint16_t nh_ecmp_count = nexthop_group_nexthop_num_no_recurse(nhg);
710722
uint16_t fib_nh_count = nexthop_group_fib_nexthop_num(nhg);
711723
uint32_t ins_id = re->nhe_installed_id ? re->nhe_installed_id : re->nhe_id;
712724
uint32_t rcv_id = re->nhe_received ? re->nhe_received->id : re->nhe_id;
713725

714726
vty_out(vty, " Rcv/Ins NHG ID: %u/%u", rcv_id, ins_id);
715-
vty_out(vty, " ECMP/FIB count: %u/%u", ecmp_count, fib_nh_count);
727+
vty_out(vty, " ECMP/FIB count: %u/%u", nh_ecmp_count, fib_nh_count);
716728
if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ||
717729
CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED) ||
718730
CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED)) {
@@ -820,7 +832,8 @@ static void vty_show_ip_route_detail_json(struct vty *vty,
820832
*/
821833
if (use_fib && re != dest->selected_fib)
822834
continue;
823-
vty_show_ip_route(vty, rn, re, json_prefix, use_fib, false, false);
835+
vty_show_ip_route(vty, rn, re, json_prefix, use_fib, false, false, false, false,
836+
false, 0);
824837

825838
/* Add flags and status to the last object */
826839
json_object *json_route =
@@ -866,7 +879,8 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
866879
route_tag_t tag, const struct prefix *longer_prefix_p,
867880
bool supernets_only, int type, unsigned short ospf_instance_id,
868881
bool use_json, uint32_t tableid, bool show_ng,
869-
bool show_nhg_summary, struct route_show_ctx *ctx)
882+
bool show_nhg_summary, bool ecmp_gt, bool ecmp_lt, bool ecmp_eq,
883+
uint16_t ecmp_count, struct route_show_ctx *ctx)
870884
{
871885
struct route_node *rn;
872886
struct route_entry *re;
@@ -944,13 +958,18 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
944958
}
945959

946960
vty_show_ip_route(vty, rn, re, json_prefix, use_fib, show_ng,
947-
show_nhg_summary);
961+
show_nhg_summary, ecmp_gt, ecmp_lt, ecmp_eq, ecmp_count);
948962
}
949963

950964
if (json_prefix) {
951-
prefix2str(&rn->p, buf, sizeof(buf));
952-
vty_json_key(vty, buf, &first_json);
953-
vty_json_no_pretty(vty, json_prefix);
965+
/* Only output if array has elements */
966+
if (json_object_array_length(json_prefix) > 0) {
967+
prefix2str(&rn->p, buf, sizeof(buf));
968+
vty_json_key(vty, buf, &first_json);
969+
vty_json_no_pretty(vty, json_prefix);
970+
} else {
971+
json_object_put(json_prefix);
972+
}
954973

955974
json_prefix = NULL;
956975
}
@@ -964,7 +983,8 @@ static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, afi_t
964983
bool use_fib, bool use_json, route_tag_t tag,
965984
const struct prefix *longer_prefix_p, bool supernets_only,
966985
int type, unsigned short ospf_instance_id, bool show_ng,
967-
bool show_nhg_summary, struct route_show_ctx *ctx)
986+
bool show_nhg_summary, bool ecmp_gt, bool ecmp_lt, bool ecmp_eq,
987+
uint16_t ecmp_count, struct route_show_ctx *ctx)
968988
{
969989
struct zebra_router_table *zrt;
970990
struct rib_table_info *info;
@@ -980,15 +1000,17 @@ static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, afi_t
9801000

9811001
do_show_ip_route(vty, zvrf_name(zvrf), afi, safi, use_fib, use_json, tag,
9821002
longer_prefix_p, supernets_only, type, ospf_instance_id,
983-
zrt->tableid, show_ng, show_nhg_summary, ctx);
1003+
zrt->tableid, show_ng, show_nhg_summary, ecmp_gt, ecmp_lt,
1004+
ecmp_eq, ecmp_count, ctx);
9841005
}
9851006
}
9861007

9871008
static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, safi_t safi,
9881009
bool use_fib, bool use_json, route_tag_t tag,
9891010
const struct prefix *longer_prefix_p, bool supernets_only, int type,
9901011
unsigned short ospf_instance_id, uint32_t tableid, bool show_ng,
991-
bool show_nhg_summary, struct route_show_ctx *ctx)
1012+
bool show_nhg_summary, bool ecmp_gt, bool ecmp_lt, bool ecmp_eq,
1013+
uint16_t ecmp_count, struct route_show_ctx *ctx)
9921014
{
9931015
struct route_table *table;
9941016
struct zebra_vrf *zvrf = NULL;
@@ -1021,7 +1043,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, sa
10211043

10221044
do_show_route_helper(vty, zvrf, table, afi, safi, use_fib, tag, longer_prefix_p,
10231045
supernets_only, type, ospf_instance_id, use_json, tableid, show_ng,
1024-
show_nhg_summary, ctx);
1046+
show_nhg_summary, ecmp_gt, ecmp_lt, ecmp_eq, ecmp_count, ctx);
10251047

10261048
return CMD_SUCCESS;
10271049
}
@@ -1708,7 +1730,7 @@ DEFPY (show_route,
17081730
}]\
17091731
[" FRR_IP6_REDIST_STR_ZEBRA "$type_str]\
17101732
>\
1711-
[nexthop-group$ng [summary$ng_summary]] [json$json]",
1733+
[nexthop-group$ng [summary$ng_summary [ecmp-count <gt$ecmp_gt|lt$ecmp_lt|eq$ecmp_eq> (1-256)$ecmp_count]]] [json$json]",
17121734
SHOW_STR
17131735
IP_STR
17141736
"IP forwarding table\n"
@@ -1739,9 +1761,14 @@ DEFPY (show_route,
17391761
"IPv6 prefix\n"
17401762
"Show route matching the specified Network/Mask pair only\n"
17411763
FRR_IP6_REDIST_HELP_STR_ZEBRA
1742-
JSON_STR
17431764
"Nexthop Group Information\n"
1744-
"Show ECMP count summary\n")
1765+
"Show ECMP count summary\n"
1766+
"Filter by ECMP count\n"
1767+
"Greater than (>)\n"
1768+
"Less than (<)\n"
1769+
"Equal to (=)\n"
1770+
"ECMP count value\n"
1771+
JSON_STR)
17451772
{
17461773
afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
17471774
safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST;
@@ -1787,12 +1814,16 @@ DEFPY (show_route,
17871814
do_show_ip_route_all(vty, zvrf, afi, safi, !!fib, !!json,
17881815
tag, prefix_str ? prefix : NULL,
17891816
!!supernets_only, type,
1790-
ospf_instance_id, !!ng, true, &ctx);
1817+
ospf_instance_id, !!ng, true,
1818+
!!ecmp_gt, !!ecmp_lt, !!ecmp_eq,
1819+
ecmp_count ? ecmp_count : 0, &ctx);
17911820
else
17921821
do_show_ip_route(vty, zvrf_name(zvrf), afi, safi, !!fib,
17931822
!!json, tag, prefix_str ? prefix : NULL,
17941823
!!supernets_only, type, ospf_instance_id,
1795-
table, false, true, &ctx);
1824+
table, false, true, !!ecmp_gt, !!ecmp_lt,
1825+
!!ecmp_eq, ecmp_count ? ecmp_count : 0,
1826+
&ctx);
17961827
}
17971828
if (json)
17981829
vty_json_close(vty, first_vrf_json);
@@ -1814,11 +1845,15 @@ DEFPY (show_route,
18141845
if (table_all)
18151846
do_show_ip_route_all(vty, zvrf, afi, safi, !!fib, !!json, tag,
18161847
prefix_str ? prefix : NULL, !!supernets_only,
1817-
type, ospf_instance_id, !!ng, true, &ctx);
1848+
type, ospf_instance_id, !!ng, true, !!ecmp_gt,
1849+
!!ecmp_lt, !!ecmp_eq,
1850+
ecmp_count ? ecmp_count : 0, &ctx);
18181851
else
18191852
do_show_ip_route(vty, vrf->name, afi, safi, !!fib, !!json, tag,
18201853
prefix_str ? prefix : NULL, !!supernets_only,
1821-
type, ospf_instance_id, table, false, true, &ctx);
1854+
type, ospf_instance_id, table, false, true,
1855+
!!ecmp_gt, !!ecmp_lt, !!ecmp_eq,
1856+
ecmp_count ? ecmp_count : 0, &ctx);
18221857
}
18231858

18241859
return CMD_SUCCESS;
@@ -1836,11 +1871,13 @@ DEFPY (show_route,
18361871
if (table_all)
18371872
do_show_ip_route_all(vty, zvrf, afi, safi, !!fib, !!json, tag,
18381873
prefix_str ? prefix : NULL, !!supernets_only,
1839-
type, ospf_instance_id, !!ng, false, &ctx);
1874+
type, ospf_instance_id, !!ng, false, false,
1875+
false, false, 0, &ctx);
18401876
else
18411877
do_show_ip_route(vty, zvrf_name(zvrf), afi, safi, !!fib, !!json,
18421878
tag, prefix_str ? prefix : NULL, !!supernets_only,
1843-
type, ospf_instance_id, table, !!ng, false, &ctx);
1879+
type, ospf_instance_id, table, !!ng, false, false,
1880+
false, false, 0, &ctx);
18441881
}
18451882
if (json)
18461883
vty_json_close(vty, first_vrf_json);
@@ -1862,11 +1899,13 @@ DEFPY (show_route,
18621899
if (table_all)
18631900
do_show_ip_route_all(vty, zvrf, afi, safi, !!fib, !!json, tag,
18641901
prefix_str ? prefix : NULL, !!supernets_only, type,
1865-
ospf_instance_id, !!ng, false, &ctx);
1902+
ospf_instance_id, !!ng, false, false, false, false, 0,
1903+
&ctx);
18661904
else
18671905
do_show_ip_route(vty, vrf->name, afi, safi, !!fib, !!json, tag,
18681906
prefix_str ? prefix : NULL, !!supernets_only, type,
1869-
ospf_instance_id, table, !!ng, false, &ctx);
1907+
ospf_instance_id, table, !!ng, false, false, false, false,
1908+
0, &ctx);
18701909
}
18711910

18721911
return CMD_SUCCESS;

0 commit comments

Comments
 (0)