@@ -83,6 +83,9 @@ int (*nb_cli_apply_changes_mgmt_cb)(struct vty *vty, const char *xpath_base_abs)
8383int (* nb_cli_rpc_mgmt_cb )(struct vty * vty , const char * xpath , const struct lyd_node * input );
8484
8585
86+ /* Master of the tasks. */
87+ static struct event_loop * vty_master ;
88+
8689PREDECL_DLIST (vtyservs );
8790
8891struct vty_serv {
@@ -139,22 +142,27 @@ void vty_resume_response(struct vty *vty, int ret)
139142 uint8_t header [4 ] = {0 , 0 , 0 , 0 };
140143
141144 if (vty -> type != VTY_FILE ) {
145+ /* Send end-of-output marker */
142146 header [3 ] = ret ;
143147 buffer_put (vty -> obuf , header , 4 );
144- if (!vty -> t_write && (vtysh_flush (vty ) < 0 )) {
145- zlog_err ("failed to vtysh_flush" );
146- /* Try to flush results; exit if a write error occurs */
147- return ;
148+
149+ /* Try to flush results; exit if a write error occurs */
150+ if (vty -> t_write == NULL ) {
151+ if (vtysh_flush (vty ) < 0 ) {
152+ zlog_err ("failed to vtysh_flush" );
153+ return ;
154+ }
148155 }
149156 }
150157
158+ /* Resume reading if possible */
151159 if (vty -> status == VTY_CLOSE )
152160 vty_close (vty );
153161 else if (vty -> type != VTY_FILE )
154162 vty_event (VTYSH_READ , vty );
155163 else
156164 /* should we assert here? */
157- zlog_err ("mgmtd : unexpected resume while reading config file" );
165+ zlog_err ("vty : unexpected resume while reading config file" );
158166}
159167
160168void vty_frame (struct vty * vty , const char * format , ...)
@@ -175,6 +183,86 @@ void vty_endframe(struct vty *vty, const char *endtext)
175183 vty -> frame_pos = 0 ;
176184}
177185
186+ /*
187+ * Callback function for yield/resume; call through to application's
188+ * callback.
189+ */
190+ static void yield_resume_cb (struct event * event )
191+ {
192+ struct vty * vty = EVENT_ARG (event );
193+ struct vty_yield_resume_s ctx ;
194+
195+ /* Capture application callback info */
196+ ctx = vty -> yield_resume ;
197+
198+ /* Clear vty's yield callback info before calling into the application:
199+ * the application may call the "finish" or the "yield" api, so we can't
200+ * make any assumptions about the state of the 'vty' info after calling in.
201+ */
202+ vty -> yield_resume .app_cb = NULL ;
203+ vty -> yield_resume .arg = NULL ;
204+
205+ /* Call through to application */
206+ ctx .app_cb (vty , ctx .arg );
207+ }
208+
209+ /*
210+ * Application process wants to yield while sending results/replies.
211+ * We'll schedule a task to resume, and call the application's callback.
212+ */
213+ bool vty_yield (struct vty * vty , void (* func )(struct vty * vty , void * arg ),
214+ void * arg )
215+ {
216+ vty -> yield_resume .app_cb = func ;
217+ vty -> yield_resume .arg = arg ;
218+
219+ event_add_event (vty_master , yield_resume_cb , vty , 0 ,
220+ & vty -> yield_resume .t_resume );
221+
222+ /* Ensure reading new input is disabled */
223+ event_cancel (& vty -> t_read );
224+
225+ /* Try to send buffered output */
226+ if (vty -> type == VTY_SHELL_SERV )
227+ vtysh_flush (vty );
228+ else
229+ vty_event (VTY_WRITE , vty );
230+
231+ return true;
232+ }
233+
234+ /*
235+ *
236+ */
237+ static void yield_finish_internal (struct vty * vty )
238+ {
239+ event_cancel (& (vty -> yield_resume .t_resume ));
240+
241+ /* Clear vty's yield/resume callback info */
242+ vty -> yield_resume .app_cb = NULL ;
243+ vty -> yield_resume .arg = NULL ;
244+ }
245+
246+ /*
247+ * Yield/resume is complete; cancel any scheduled resume task, and return
248+ * to normal vty operation (turn on reads, e.g.)
249+ */
250+ void vty_yield_finish (struct vty * vty , int retcode )
251+ {
252+ if (vty -> status != VTY_CLOSE ) {
253+ if (vty -> type == VTY_SHELL_SERV ) {
254+
255+ /* Send end-of-output marker and resume normal processing */
256+ vty_resume_response (vty , retcode );
257+ vty_event (VTYSH_READ , vty );
258+ } else {
259+ vty_event (VTY_READ , vty );
260+ }
261+
262+ yield_finish_internal (vty );
263+ }
264+ }
265+
178266bool vty_set_include (struct vty * vty , const char * regexp )
179267{
180268 int errcode ;
@@ -1618,7 +1706,7 @@ static void vty_flush(struct event *event)
16181706 buffer_status_t flushrc ;
16191707 struct vty * vty = EVENT_ARG (event );
16201708
1621- /* Tempolary disable read event . */
1709+ /* Temporarily disable reads . */
16221710 if (vty -> lines == 0 )
16231711 event_cancel (& vty -> t_read );
16241712
@@ -2300,10 +2388,11 @@ static void vtysh_read(struct event *event)
23002388 if (* p == '\0' ) {
23012389 /* Pass this line to parser. */
23022390 ret = vty_execute (vty );
2303- /* Note that vty_execute clears the command buffer and resets
2304- vty->length to 0. */
2391+ /* Note that vty_execute clears the command buffer and
2392+ * resets vty->length to 0.
2393+ */
23052394
2306- /* Return result. */
2395+ /* Return result. */
23072396#ifdef VTYSH_DEBUG
23082397 printf ("result: %d\n" , ret );
23092398 printf ("vtysh node: %d\n" , vty -> node );
@@ -2352,6 +2441,12 @@ static void vtysh_read(struct event *event)
23522441 return ;
23532442 }
23542443
2444+ /* If the application has asked to yield during
2445+ * processing, don't continue reading.
2446+ */
2447+ if (event_is_scheduled (vty -> yield_resume .t_resume ))
2448+ break ;
2449+
23552450 /* warning: watchfrr hardcodes this result write
23562451 */
23572452 header [3 ] = ret ;
@@ -2369,6 +2464,12 @@ static void vtysh_read(struct event *event)
23692464 }
23702465 }
23712466
2467+ /* If the application has asked to yield during
2468+ * processing, don't continue reading.
2469+ */
2470+ if (event_is_scheduled (vty -> yield_resume .t_resume ))
2471+ return ;
2472+
23722473 if (vty -> status == VTY_CLOSE )
23732474 vty_close (vty );
23742475 else
@@ -2428,6 +2529,14 @@ void vty_close(struct vty *vty)
24282529
24292530 vty -> status = VTY_CLOSE ;
24302531
2532+ /* If application was doing yield/resume, notify it by calling
2533+ * its callback with a NULL vty argument.
2534+ */
2535+ if (vty -> yield_resume .app_cb ) {
2536+ (vty -> yield_resume .app_cb )(NULL , vty -> yield_resume .arg );
2537+ yield_finish_internal (vty );
2538+ }
2539+
24312540 /*
24322541 * If we reach here with pending config to commit we will be losing it
24332542 * so warn the user.
@@ -2753,6 +2862,7 @@ FILE *vty_open_config(const char *config_file, char *config_default_dir)
27532862 }
27542863#endif /* VTYSH */
27552864 confp = fopen (config_default_dir , "r" );
2865+
27562866 if (confp == NULL ) {
27572867 flog_err (
27582868 EC_LIB_SYSTEM_CALL ,
@@ -2911,9 +3021,6 @@ int vty_config_node_exit(struct vty *vty)
29113021 return 1 ;
29123022}
29133023
2914- /* Master of the threads. */
2915- static struct event_loop * vty_master ;
2916-
29173024static void vty_event_serv (enum vty_event event , struct vty_serv * vty_serv )
29183025{
29193026 switch (event ) {
0 commit comments