Skip to content

Commit bec4a0a

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 dd9b8af commit bec4a0a

1 file changed

Lines changed: 243 additions & 18 deletions

File tree

zebra/zebra_vty.c

Lines changed: 243 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,62 @@
5555
#include "zebra/zebra_neigh.h"
5656
#include "zebra/zebra_ptm.h"
5757

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

106+
/* If we're yielding/resuming large show output, we'll allocate a context
107+
* struct and use it until we're done with the entire operation.
108+
*/
109+
static struct route_show_ctx *resume_show_ctx;
110+
111+
/* Max routes to show before yielding */
112+
uint32_t show_yield_limit = 1000;
113+
65114
static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, safi_t safi,
66115
bool use_fib, bool use_json, route_tag_t tag,
67116
const struct prefix *longer_prefix_p, bool supernets_only, int type,
@@ -76,6 +125,7 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty,
76125
struct route_table *table,
77126
json_object *vrf_json,
78127
bool use_json);
128+
79129
/* Helper api to format a nexthop in the 'detailed' output path. */
80130
static void show_nexthop_detail_helper(struct vty *vty,
81131
const struct route_node *rn,
@@ -782,6 +832,26 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, struct rou
782832

783833
}
784834

835+
/*
836+
* Callback for yield/resume cycles during show command output.
837+
*/
838+
static void show_resume_cb(struct vty *vty, void *arg)
839+
{
840+
/* Check 'vty' - will be NULL if this is a cleanup notification */
841+
if (vty == NULL) {
842+
if (arg == resume_show_ctx)
843+
resume_show_ctx = NULL;
844+
XFREE(MTYPE_TMP, arg);
845+
return;
846+
}
847+
848+
/* Ok to continue */
849+
850+
}
851+
852+
/*
853+
*
854+
*/
785855
static void vty_show_ip_route_detail_json(struct vty *vty,
786856
struct route_node *rn, bool use_fib)
787857
{
@@ -845,13 +915,13 @@ static void zebra_vty_display_vrf_header(struct vty *vty, struct zebra_vrf *zvrf
845915
}
846916
}
847917

848-
static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
849-
struct route_table *table, afi_t afi, safi_t safi, bool use_fib,
850-
route_tag_t tag, const struct prefix *longer_prefix_p,
851-
bool supernets_only, int type, unsigned short ospf_instance_id,
852-
bool use_json, uint32_t tableid, bool show_ng,
853-
bool show_nhg_summary, bool ecmp_gt, bool ecmp_lt, bool ecmp_eq,
854-
uint16_t ecmp_count, bool failed_only, struct route_show_ctx *ctx)
918+
static int do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
919+
struct route_table *table, afi_t afi, safi_t safi, bool use_fib,
920+
route_tag_t tag, const struct prefix *longer_prefix_p,
921+
bool supernets_only, int type, unsigned short ospf_instance_id,
922+
bool use_json, uint32_t tableid, bool show_ng,
923+
bool show_nhg_summary, bool ecmp_gt, bool ecmp_lt, bool ecmp_eq,
924+
uint16_t ecmp_count, bool failed_only, struct route_show_ctx *ctx)
855925
{
856926
struct route_node *rn;
857927
struct route_entry *re;
@@ -861,6 +931,10 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
861931
json_object *json_prefix = NULL;
862932
uint32_t addr;
863933
char buf[BUFSIZ];
934+
const struct rib_table_info *zinfo = table->info;
935+
const struct prefix_ipv6 *src_pfx;
936+
const struct prefix *pfx;
937+
int ret = CMD_SUCCESS;
864938

865939
/*
866940
* ctx->multi indicates if we are dumping multiple tables or vrfs.
@@ -873,8 +947,20 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
873947
* => display the VRF and table if specific
874948
*/
875949

950+
/* Determine whether we're resuming an iteration, or starting one */
951+
if (ctx->resuming) {
952+
src_pfx = NULL;
953+
if (ctx->last_src_prefix.prefixlen > 0)
954+
src_pfx = &(ctx->last_src_prefix);
955+
rn = srcdest_rnode_lookup(table, &(ctx->last_prefix), src_pfx);
956+
/* TODO -- decide whether to advance to "next" here or not */
957+
958+
} else {
959+
rn = route_top(table);
960+
}
961+
876962
/* Show all routes. */
877-
for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) {
963+
for ( ; rn; rn = srcdest_route_next(rn)) {
878964
dest = rib_dest_from_rnode(rn);
879965

880966
if (longer_prefix_p && !prefix_match(longer_prefix_p, &rn->p))
@@ -934,7 +1020,8 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
9341020
vty_show_ip_route(vty, rn, re, json_prefix, use_fib, show_ng,
9351021
show_nhg_summary, ecmp_gt, ecmp_lt, ecmp_eq, ecmp_count,
9361022
ctx->brief);
937-
}
1023+
ctx->curr_counter++;
1024+
} /* for each re in rn */
9381025

9391026
if (json_prefix) {
9401027
/* Only output if array has elements */
@@ -948,10 +1035,48 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
9481035

9491036
json_prefix = NULL;
9501037
}
1038+
1039+
/* Time to yield? */
1040+
if (ctx->curr_counter > show_yield_limit) {
1041+
ctx->total_counter += ctx->curr_counter;
1042+
ctx->curr_counter = 0;
1043+
1044+
/* Capture info needed for resume */
1045+
if (ctx != resume_show_ctx) {
1046+
resume_show_ctx =
1047+
XCALLOC(MTYPE_TMP,
1048+
sizeof(struct route_show_ctx));
1049+
1050+
*resume_show_ctx = *ctx;
1051+
}
1052+
1053+
resume_show_ctx->last_afi = afi;
1054+
resume_show_ctx->last_safi = SAFI_UNICAST;
1055+
resume_show_ctx->last_vrfid = zvrf->vrf->vrf_id;
1056+
resume_show_ctx->last_tableid = zinfo->table_id;
1057+
resume_show_ctx->last_first_json = first_json;
1058+
prefix_copy(&(resume_show_ctx->last_prefix), &(rn->p));
1059+
srcdest_rnode_prefixes(rn, NULL, &pfx);
1060+
if (pfx)
1061+
prefix_copy(&(resume_show_ctx->last_src_prefix), pfx);
1062+
else
1063+
memset(&(resume_show_ctx->last_src_prefix), 0,
1064+
sizeof(resume_show_ctx->last_src_prefix));
1065+
1066+
ret = CMD_YIELD;
1067+
break;
1068+
}
1069+
} /* for each rn in table */
1070+
1071+
if (ret == CMD_SUCCESS) {
1072+
/* Finished with this table */
1073+
if (use_json)
1074+
vty_json_close(vty, first_json);
1075+
} else {
1076+
9511077
}
9521078

953-
if (use_json)
954-
vty_json_close(vty, first_json);
1079+
return ret;
9551080
}
9561081

9571082
static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi, safi_t safi,
@@ -980,6 +1105,100 @@ static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, afi_t
9801105
}
9811106
}
9821107

1108+
/*
1109+
* Show routes for all tables in the vrf indicated by 'ctx'
1110+
*/
1111+
static void do_show_ip_route_all_ctx(struct vty *vty, struct route_show_ctx *ctx)
1112+
{
1113+
struct zebra_router_table *zrt;
1114+
struct rib_table_info *info;
1115+
const struct prefix *longer_prefix_p = NULL;
1116+
struct zebra_router_table finder = {};
1117+
int ret = CMD_SUCCESS;
1118+
1119+
if (ctx->longer_prefix.prefixlen > 0)
1120+
longer_prefix_p = &ctx->longer_prefix;
1121+
1122+
/* Locate starting point if we're resuming an iteration; otherwise start
1123+
* with the first table.
1124+
*/
1125+
if (ctx->resuming) {
1126+
finder.tableid = ctx->last_tableid;
1127+
zrt = RB_NFIND(zebra_router_table_head, &zrouter.tables, &finder);
1128+
} else {
1129+
zrt = RB_MIN(zebra_router_table_head, &zrouter.tables);
1130+
}
1131+
1132+
while (zrt != NULL) {
1133+
info = route_table_get_info(zrt->table);
1134+
1135+
if (ctx->zvrf != info->zvrf)
1136+
continue;
1137+
if (zrt->afi != ctx->afi || zrt->safi != SAFI_UNICAST)
1138+
continue;
1139+
1140+
ret = do_show_ip_route(vty, zvrf_name(ctx->zvrf), ctx->afi,
1141+
ctx->safi, ctx->use_fib, ctx->use_json,
1142+
ctx->tag, longer_prefix_p, ctx->supernets_only,
1143+
ctx->type, ctx->ospf_instance_id, zrt->tableid,
1144+
ctx->show_nhg, ctx->show_nhg_summary, ctx->ecmp_gt,
1145+
ctx->ecmp_lt, ctx->ecmp_eq, ctx->ecmp_count,
1146+
ctx->failed_only, ctx);
1147+
1148+
if (ret != CMD_SUCCESS)
1149+
break;
1150+
1151+
zrt = RB_NEXT(zebra_router_table_head, zrt);
1152+
}
1153+
1154+
/* Capture iteration context if we're going to yield */
1155+
if (ret == CMD_YIELD) {
1156+
/* Schedule the yield - the lower level of the iteration needs to have
1157+
* set up the resume params like last table, last vrf,
1158+
* last prefix seen, etc.
1159+
*/
1160+
vty_yield(vty, show_resume_cb, resume_show_ctx);
1161+
}
1162+
}
1163+
1164+
/*
1165+
* Copy various route show params into a single 'show context' object
1166+
*/
1167+
static void show_route_ctx_setup(struct route_show_ctx *ctx,
1168+
struct zebra_vrf *zvrf, afi_t afi, safi_t safi,
1169+
bool use_fib, bool use_json, route_tag_t tag,
1170+
const struct prefix *longer_prefix_p,
1171+
bool supernets_only, int type,
1172+
unsigned short instance_id, uint32_t tableid,
1173+
bool show_nhg, bool show_nhg_summary, bool ecmp_gt,
1174+
bool ecmp_lt, bool ecmp_eq, uint16_t ecmp_count,
1175+
bool failed_only)
1176+
{
1177+
memset(ctx, 0, sizeof(struct route_show_ctx));
1178+
1179+
ctx->afi = afi;
1180+
ctx->safi = safi;
1181+
ctx->use_fib = use_fib;
1182+
ctx->use_json = use_json;
1183+
ctx->tag = tag;
1184+
ctx->supernets_only = supernets_only;
1185+
ctx->type = type;
1186+
ctx->ospf_instance_id = instance_id;
1187+
ctx->tableid = tableid;
1188+
ctx->show_nhg = show_nhg;
1189+
ctx->zvrf = zvrf;
1190+
ctx->show_nhg_summary = show_nhg_summary;
1191+
ctx->ecmp_gt = ecmp_gt;
1192+
ctx->ecmp_lt = ecmp_lt;
1193+
ctx->ecmp_eq = ecmp_eq;
1194+
ctx->ecmp_count = ecmp_count;
1195+
ctx->failed_only = failed_only;
1196+
1197+
if (longer_prefix_p)
1198+
prefix_copy(&(ctx->longer_prefix), longer_prefix_p);
1199+
1200+
}
1201+
9831202
static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, safi_t safi,
9841203
bool use_fib, bool use_json, route_tag_t tag,
9851204
const struct prefix *longer_prefix_p, bool supernets_only, int type,
@@ -1871,16 +2090,22 @@ DEFPY (show_route,
18712090
if (json)
18722091
vty_json_key(vty, zvrf_name(zvrf),
18732092
&first_vrf_json);
1874-
if (table_all)
1875-
do_show_ip_route_all(vty, zvrf, afi, safi, !!fib, !!json, tag,
1876-
prefix_str ? prefix : NULL, !!supernets_only,
1877-
type, ospf_instance_id, !!ng, false, false,
1878-
false, false, 0, !!failed, &ctx);
1879-
else
2093+
if (table_all) {
2094+
show_route_ctx_setup(
2095+
&ctx, zvrf, afi, safi, !!fib,
2096+
!!json, tag, (prefix_str ? prefix : NULL),
2097+
!!supernets_only, type, ospf_instance_id,
2098+
0, !!ng, false, false, false, false, 0, !!failed);
2099+
2100+
ctx.multi = (vrf_all || table_all);
2101+
2102+
do_show_ip_route_all_ctx(vty, &ctx);
2103+
} else {
18802104
do_show_ip_route(vty, zvrf_name(zvrf), afi, safi, !!fib, !!json,
18812105
tag, prefix_str ? prefix : NULL, !!supernets_only,
18822106
type, ospf_instance_id, table, !!ng, false, false,
18832107
false, false, 0, !!failed, &ctx);
2108+
}
18842109
}
18852110
if (json)
18862111
vty_json_close(vty, first_vrf_json);

0 commit comments

Comments
 (0)