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 */
5959struct 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+
65114static 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. */
80130static 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+ */
785855static 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
9571082static 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+
9831202static 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