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 */
5858struct 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+
63106static 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. */
79123static 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+ */
728792static 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
8801000static 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+
9041108static 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