Skip to content

Commit fd2d932

Browse files
author
Mark Stapp
committed
zebra: initial use of vty yield during "show ip route"
Yield and resume long-running show operation using the vty yield feature; capture "resume" context as we iterate through route tables. Signed-off-by: Mark Stapp <mjs@cisco.com>
1 parent b48a5e4 commit fd2d932

1 file changed

Lines changed: 222 additions & 11 deletions

File tree

zebra/zebra_vty.c

Lines changed: 222 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,55 @@
5454
#include "zebra/zebra_neigh.h"
5555
#include "zebra/zebra_ptm.h"
5656

57-
/* context to manage dumps in multiple tables or vrfs */
57+
/* context to manage show output in multiple tables or vrfs */
5858
struct route_show_ctx {
5959
bool multi; /* dump multiple tables or vrf */
6060
bool header_done; /* common header already displayed */
61+
bool allocated; /* malloc'd (vs on-stack) */
62+
63+
safi_t safi;
64+
afi_t afi;
65+
uint32_t tableid;
66+
route_tag_t tag;
67+
int type;
68+
unsigned short ospf_instance_id;
69+
70+
/* Filter/specifier arguments from show command */
71+
bool supernets_only;
72+
bool use_fib;
73+
bool use_json;
74+
bool show_nhg;
75+
76+
struct vty *vty;
77+
char vrf_name[VRF_NAMSIZ];
78+
struct zebra_vrf *zvrf;
79+
struct route_table *table;
80+
struct prefix longer_prefix;
81+
82+
struct json_object *json_obj;
83+
84+
/* For yield/resume */
85+
bool resuming;
86+
uint32_t total_counter;
87+
uint32_t curr_counter;
88+
89+
afi_t last_afi;
90+
safi_t last_safi;
91+
vrf_id_t last_vrfid;
92+
uint32_t last_tableid;
93+
bool last_first_json;
94+
struct prefix last_prefix;
95+
struct prefix_ipv6 last_src_prefix;
6196
};
6297

98+
/* If we're yielding/resuming large show output, we'll allocate a context
99+
* struct and use it until we're done with the entire operation.
100+
*/
101+
static struct route_show_ctx *resume_show_ctx;
102+
103+
/* Max routes to show before yielding */
104+
uint32_t show_yield_limit = 1000;
105+
63106
static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
64107
safi_t safi, bool use_fib, bool use_json,
65108
route_tag_t tag,
@@ -75,6 +118,7 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty,
75118
struct route_table *table,
76119
json_object *vrf_json,
77120
bool use_json);
121+
78122
/* Helper api to format a nexthop in the 'detailed' output path. */
79123
static void show_nexthop_detail_helper(struct vty *vty,
80124
const struct route_node *rn,
@@ -725,6 +769,26 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
725769

726770
}
727771

772+
/*
773+
* Callback for yield/resume cycles during show command output.
774+
*/
775+
static void show_resume_cb(struct vty *vty, void *arg)
776+
{
777+
/* Check 'vty' - will be NULL if this is a cleanup notification */
778+
if (vty == NULL) {
779+
if (arg == resume_show_ctx)
780+
resume_show_ctx = NULL;
781+
XFREE(MTYPE_TMP, arg);
782+
return;
783+
}
784+
785+
/* Ok to continue */
786+
787+
}
788+
789+
/*
790+
*
791+
*/
728792
static void vty_show_ip_route_detail_json(struct vty *vty,
729793
struct route_node *rn, bool use_fib)
730794
{
@@ -779,7 +843,7 @@ static void zebra_vty_display_vrf_header(struct vty *vty, struct zebra_vrf *zvrf
779843
}
780844
}
781845

782-
static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, struct route_table *table,
846+
static int do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, struct route_table *table,
783847
afi_t afi, safi_t safi, bool use_fib, route_tag_t tag,
784848
const struct prefix *longer_prefix_p, bool supernets_only,
785849
int type, unsigned short ospf_instance_id, bool use_json,
@@ -793,6 +857,10 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, struct
793857
json_object *json_prefix = NULL;
794858
uint32_t addr;
795859
char buf[BUFSIZ];
860+
struct zebra_router_table *zrt = table->info;
861+
const struct prefix_ipv6 *src_pfx;
862+
const struct prefix *pfx;
863+
int ret = CMD_SUCCESS;
796864

797865
/*
798866
* ctx->multi indicates if we are dumping multiple tables or vrfs.
@@ -805,8 +873,20 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, struct
805873
* => display the VRF and table if specific
806874
*/
807875

876+
/* Determine whether we're resuming an iteration, or starting one */
877+
if (ctx->resuming) {
878+
src_pfx = NULL;
879+
if (ctx->last_src_prefix.prefixlen > 0)
880+
src_pfx = &(ctx->last_src_prefix);
881+
rn = srcdest_rnode_lookup(table, &(ctx->last_prefix), src_pfx);
882+
/* TODO -- decide whether to advance to "next" here or not */
883+
884+
} else {
885+
rn = route_top(table);
886+
}
887+
808888
/* Show all routes. */
809-
for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) {
889+
for ( ; rn; rn = srcdest_route_next(rn)) {
810890
dest = rib_dest_from_rnode(rn);
811891

812892
if (longer_prefix_p && !prefix_match(longer_prefix_p, &rn->p))
@@ -862,7 +942,9 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, struct
862942

863943
vty_show_ip_route(vty, rn, re, json_prefix, use_fib,
864944
show_ng);
865-
}
945+
946+
ctx->curr_counter++;
947+
} /* for each re in rn */
866948

867949
if (json_prefix) {
868950
prefix2str(&rn->p, buf, sizeof(buf));
@@ -871,10 +953,48 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, struct
871953

872954
json_prefix = NULL;
873955
}
956+
957+
/* Time to yield? */
958+
if (ctx->curr_counter > show_yield_limit) {
959+
ctx->total_counter += ctx->curr_counter;
960+
ctx->curr_counter = 0;
961+
962+
/* Capture info needed for resume */
963+
if (ctx != resume_show_ctx) {
964+
resume_show_ctx =
965+
XCALLOC(MTYPE_TMP,
966+
sizeof(struct route_show_ctx));
967+
968+
*resume_show_ctx = *ctx;
969+
}
970+
971+
resume_show_ctx->last_afi = afi;
972+
resume_show_ctx->last_safi = SAFI_UNICAST;
973+
resume_show_ctx->last_vrfid = zvrf->vrf->vrf_id;
974+
resume_show_ctx->last_tableid = zrt->tableid;
975+
resume_show_ctx->last_first_json = first_json;
976+
prefix_copy(&(resume_show_ctx->last_prefix), &(rn->p));
977+
srcdest_rnode_prefixes(rn, NULL, &pfx);
978+
if (pfx)
979+
prefix_copy(&(resume_show_ctx->last_src_prefix), pfx);
980+
else
981+
memset(&(resume_show_ctx->last_src_prefix), 0,
982+
sizeof(resume_show_ctx->last_src_prefix));
983+
984+
ret = CMD_YIELD;
985+
break;
986+
}
987+
} /* for each rn in table */
988+
989+
if (ret == CMD_SUCCESS) {
990+
/* Finished with this table */
991+
if (use_json)
992+
vty_json_close(vty, first_json);
993+
} else {
994+
874995
}
875996

876-
if (use_json)
877-
vty_json_close(vty, first_json);
997+
return ret;
878998
}
879999

8801000
static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi, safi_t safi,
@@ -901,6 +1021,90 @@ static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, afi_t
9011021
}
9021022
}
9031023

1024+
/*
1025+
* Show routes for all tables in the vrf indicated by 'ctx'
1026+
*/
1027+
static void do_show_ip_route_all_ctx(struct vty *vty, struct route_show_ctx *ctx)
1028+
{
1029+
struct zebra_router_table *zrt;
1030+
struct rib_table_info *info;
1031+
const struct prefix *longer_prefix_p = NULL;
1032+
struct zebra_router_table finder = {};
1033+
int ret;
1034+
1035+
if (ctx->longer_prefix.prefixlen > 0)
1036+
longer_prefix_p = &ctx->longer_prefix;
1037+
1038+
/* Locate starting point if we're resuming an iteration; otherwise start
1039+
* with the first table.
1040+
*/
1041+
if (ctx->resuming) {
1042+
finder.tableid = ctx->last_tableid;
1043+
zrt = RB_NFIND(zebra_router_table_head, &zrouter.tables, &finder);
1044+
} else {
1045+
zrt = RB_MIN(zebra_router_table_head, &zrouter.tables);
1046+
}
1047+
1048+
while (zrt != NULL) {
1049+
info = route_table_get_info(zrt->table);
1050+
1051+
if (ctx->zvrf != info->zvrf)
1052+
continue;
1053+
if (zrt->afi != ctx->afi || zrt->safi != SAFI_UNICAST)
1054+
continue;
1055+
1056+
ret = do_show_ip_route(vty, zvrf_name(ctx->zvrf), ctx->afi,
1057+
ctx->safi, ctx->use_fib, ctx->use_json,
1058+
ctx->tag, longer_prefix_p, ctx->supernets_only,
1059+
ctx->type, ctx->ospf_instance_id, zrt->tableid,
1060+
ctx->show_nhg, ctx);
1061+
1062+
if (ret != CMD_SUCCESS)
1063+
break;
1064+
1065+
zrt = RB_NEXT(zebra_router_table_head, zrt);
1066+
}
1067+
1068+
/* Capture iteration context if we're going to yield */
1069+
if (ret == CMD_YIELD) {
1070+
/* Schedule the yield - the lower level of the iteration needs to have
1071+
* set up the resume params like last table, last vrf,
1072+
* last prefix seen, etc.
1073+
*/
1074+
vty_yield(vty, show_resume_cb, resume_show_ctx);
1075+
}
1076+
}
1077+
1078+
/*
1079+
* Copy various route show params into a single 'show context' object
1080+
*/
1081+
static void show_route_ctx_setup(struct route_show_ctx *ctx,
1082+
struct zebra_vrf *zvrf, afi_t afi, safi_t safi,
1083+
bool use_fib, bool use_json, route_tag_t tag,
1084+
const struct prefix *longer_prefix_p,
1085+
bool supernets_only, int type,
1086+
unsigned short instance_id, uint32_t tableid,
1087+
bool show_nhg)
1088+
{
1089+
memset(ctx, 0, sizeof(struct route_show_ctx));
1090+
1091+
ctx->afi = afi;
1092+
ctx->safi = safi;
1093+
ctx->use_fib = use_fib;
1094+
ctx->use_json = use_json;
1095+
ctx->tag = tag;
1096+
ctx->supernets_only = supernets_only;
1097+
ctx->type = type;
1098+
ctx->ospf_instance_id = instance_id;
1099+
ctx->tableid = tableid;
1100+
ctx->show_nhg = show_nhg;
1101+
ctx->zvrf = zvrf;
1102+
1103+
if (longer_prefix_p)
1104+
prefix_copy(&(ctx->longer_prefix), longer_prefix_p);
1105+
1106+
}
1107+
9041108
static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
9051109
safi_t safi, bool use_fib, bool use_json,
9061110
route_tag_t tag,
@@ -1689,14 +1893,21 @@ DEFPY (show_route,
16891893
if (json)
16901894
vty_json_key(vty, zvrf_name(zvrf),
16911895
&first_vrf_json);
1692-
if (table_all)
1693-
do_show_ip_route_all(vty, zvrf, afi, safi, !!fib, !!json, tag,
1694-
prefix_str ? prefix : NULL, !!supernets_only,
1695-
type, ospf_instance_id, !!ng, &ctx);
1696-
else
1896+
if (table_all) {
1897+
show_route_ctx_setup(
1898+
&ctx, zvrf, afi, safi, !!fib,
1899+
!!json, tag, (prefix_str ? prefix : NULL),
1900+
!!supernets_only, type, ospf_instance_id,
1901+
0, !!ng);
1902+
1903+
ctx.multi = (vrf_all || table_all);
1904+
1905+
do_show_ip_route_all_ctx(vty, &ctx);
1906+
} else {
16971907
do_show_ip_route(vty, zvrf_name(zvrf), afi, safi, !!fib, !!json,
16981908
tag, prefix_str ? prefix : NULL, !!supernets_only,
16991909
type, ospf_instance_id, table, !!ng, &ctx);
1910+
}
17001911
}
17011912
if (json)
17021913
vty_json_close(vty, first_vrf_json);

0 commit comments

Comments
 (0)