On Fri, Oct 20, 2023 at 10:46 PM Ihar Hrachyshka <ihrac...@redhat.com> wrote:
> On 10/6/23 3:02 AM, Ales Musil wrote: > > The unixctl exit command would receive reply immediately > > which is confusing and can cause some issues in some tests > > if the cleanup takes longer than expected. To avoid that > > make sure we reply to the exit command only after the > > main cleanup was done so there shouldn't be any possible > > window when the services are working when they are no longer > > expected to. > > > > Because it is in theory possible that we will receive multiple > > exit commands while waiting for the cleanup, make sure that we > > will reply to all of them by storing them in array. > > > > At the same time unify the exit structure for both ovn-controller > > and northd, so it can be easily extended as needed. > > > > This is inspired by OvS commit that was solving similar issue: > > 24520a401e06 ("vswitchd: Wait for a bridge exit before replying to exit > unixctl.") > > > > Signed-off-by: Ales Musil <amu...@redhat.com> > > --- > > controller/ovn-controller.c | 35 ++++++++--------------------------- > > lib/ovn-util.c | 31 +++++++++++++++++++++++++++++++ > > lib/ovn-util.h | 13 +++++++++++++ > > northd/ovn-northd.c | 27 ++++++++------------------- > > 4 files changed, 60 insertions(+), 46 deletions(-) > > > > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c > > index 9a81f1a80..a8c48630f 100644 > > --- a/controller/ovn-controller.c > > +++ b/controller/ovn-controller.c > > @@ -88,7 +88,6 @@ > > > > VLOG_DEFINE_THIS_MODULE(main); > > > > -static unixctl_cb_func ovn_controller_exit; > > static unixctl_cb_func ct_zone_list; > > static unixctl_cb_func extend_table_list; > > static unixctl_cb_func inject_pkt; > > @@ -4901,11 +4900,6 @@ controller_output_mac_cache_handler(struct > engine_node *node, > > return true; > > } > > > > -struct ovn_controller_exit_args { > > - bool *exiting; > > - bool *restart; > > -}; > > - > > /* Handles sbrec_chassis changes. > > * If a new chassis is added or removed return false, so that > > * flows are recomputed. For any updates, there is no need for > > @@ -4980,9 +4974,7 @@ int > > main(int argc, char *argv[]) > > { > > struct unixctl_server *unixctl; > > - bool exiting; > > - bool restart; > > - struct ovn_controller_exit_args exit_args = {&exiting, &restart}; > > + struct ovn_exit_args exit_args = {}; > > AFAIU = {} is allowed in C23+ only. Should we assume that the compiler > is C23 compliant? (If not, I think = { 0 } would initialize all members > to zero for all C versions.) > > See: https://en.cppreference.com/w/c/language/struct_initialization (in > Notes section) for details. > Hi Ihar, you are right we shouldn't assume C23 compatibility, interesting thing is that both GCC and Clang generate the same instruction for both interpretations AFIACT. I will send a patch to fix any occurence of "= {}" within the codebase. > > int retval; > > > > /* Read from system-id-override file once on startup. */ > > @@ -5002,7 +4994,7 @@ main(int argc, char *argv[]) > > if (retval) { > > exit(EXIT_FAILURE); > > } > > - unixctl_command_register("exit", "", 0, 1, ovn_controller_exit, > > + unixctl_command_register("exit", "", 0, 1, > ovn_exit_command_callback, > > &exit_args); > > > > daemonize_complete(); > > @@ -5514,10 +5506,8 @@ main(int argc, char *argv[]) > > VLOG_INFO("OVN internal version is : [%s]", ovn_version); > > > > /* Main loop. */ > > - exiting = false; > > - restart = false; > (you can see that previously, we were explicit about the starting values > for the variables - which in theory also allowed a "exit" command issued > right before these two lines above to have no effect, but that's a > separate problem.) > > bool sb_monitor_all = false; > > - while (!exiting) { > > + while (!exit_args.exiting) { > > memory_run(); > > if (memory_should_report()) { > > struct simap usage = SIMAP_INITIALIZER(&usage); > > @@ -5954,7 +5944,7 @@ main(int argc, char *argv[]) > > unixctl_server_run(unixctl); > > > > unixctl_server_wait(unixctl); > > - if (exiting || pending_pkt.conn) { > > + if (exit_args.exiting || pending_pkt.conn) { > > poll_immediate_wake(); > > } > > > > @@ -6005,7 +5995,7 @@ loop_done: > > memory_wait(); > > poll_block(); > > if (should_service_stop()) { > > - exiting = true; > > + exit_args.exiting = true; > > } > > } > > > > @@ -6013,7 +6003,7 @@ loop_done: > > engine_cleanup(); > > > > /* It's time to exit. Clean up the databases if we are not > restarting */ > > - if (!restart) { > > + if (!exit_args.restart) { > > bool done = !ovsdb_idl_has_ever_connected(ovnsb_idl_loop.idl); > > while (!done) { > > update_sb_db(ovs_idl_loop.idl, ovnsb_idl_loop.idl, > > @@ -6065,7 +6055,6 @@ loop_done: > > } > > > > free(ovn_version); > > - unixctl_server_destroy(unixctl); > > lflow_destroy(); > > ofctrl_destroy(); > > pinctrl_destroy(); > > @@ -6090,6 +6079,8 @@ loop_done: > > if (cli_system_id) { > > free(cli_system_id); > > } > > + ovn_exit_args_finish(&exit_args); > > + unixctl_server_destroy(unixctl); > > service_stop(); > > ovsrcu_exit(); > > > > @@ -6213,16 +6204,6 @@ usage(void) > > exit(EXIT_SUCCESS); > > } > > > > -static void > > -ovn_controller_exit(struct unixctl_conn *conn, int argc, > > - const char *argv[], void *exit_args_) > > -{ > > - struct ovn_controller_exit_args *exit_args = exit_args_; > > - *exit_args->exiting = true; > > - *exit_args->restart = argc == 2 && !strcmp(argv[1], "--restart"); > > - unixctl_command_reply(conn, NULL); > > -} > > - > > static void > > ct_zone_list(struct unixctl_conn *conn, int argc OVS_UNUSED, > > const char *argv[] OVS_UNUSED, void *ct_zones_) > > diff --git a/lib/ovn-util.c b/lib/ovn-util.c > > index ffe295696..33105202f 100644 > > --- a/lib/ovn-util.c > > +++ b/lib/ovn-util.c > > @@ -1302,3 +1302,34 @@ sorted_array_apply_diff(const struct sorted_array > *a1, > > apply_callback(arg, a2->arr[idx2], false); > > } > > } > > + > > +/* Call for the unixctl command that will store the connection and > > + * set the appropriate conditions. */ > > +void > > +ovn_exit_command_callback(struct unixctl_conn *conn, int argc, > > + const char *argv[], void *exit_args_) > > +{ > > + struct ovn_exit_args *exit_args = exit_args_; > > + > > + exit_args->n_conns++; > > + exit_args->conns = xrealloc(exit_args->conns, > > + exit_args->n_conns * sizeof > *exit_args->conns); > > + > > + exit_args->exiting = true; > > + exit_args->conns[exit_args->n_conns - 1] = conn; > > + > > + if (!exit_args->restart) { > > + exit_args->restart = argc == 2 && !strcmp(argv[1], "--restart"); > > + } > > +} > > + > > +/* Reply to all waiting unixctl connections and free the connection > array. > > + * This function should be called after the heaviest cleanup has > finished. */ > > +void > > +ovn_exit_args_finish(struct ovn_exit_args *exit_args) > > +{ > > + for (size_t i = 0; i < exit_args->n_conns; i++) { > > + unixctl_command_reply(exit_args->conns[i], NULL); > > + } > > + free(exit_args->conns); > > +} > > diff --git a/lib/ovn-util.h b/lib/ovn-util.h > > index 16f18353d..bff50dbde 100644 > > --- a/lib/ovn-util.h > > +++ b/lib/ovn-util.h > > @@ -474,4 +474,17 @@ void sorted_array_apply_diff(const struct > sorted_array *a1, > > const char *item, > > bool add), > > const void *arg); > > + > > +/* Utilities around properly handling exit command. */ > > +struct ovn_exit_args { > > + struct unixctl_conn **conns; > > + size_t n_conns; > > + bool exiting; > > + bool restart; > > +}; > > + > > +void ovn_exit_command_callback(struct unixctl_conn *conn, int argc, > > + const char *argv[], void *exit_args_); > > +void ovn_exit_args_finish(struct ovn_exit_args *exit_args); > > + > > #endif /* OVN_UTIL_H */ > > diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c > > index 68fc8836e..b2ec67c06 100644 > > --- a/northd/ovn-northd.c > > +++ b/northd/ovn-northd.c > > @@ -47,7 +47,6 @@ > > > > VLOG_DEFINE_THIS_MODULE(ovn_northd); > > > > -static unixctl_cb_func ovn_northd_exit; > > static unixctl_cb_func ovn_northd_pause; > > static unixctl_cb_func ovn_northd_resume; > > static unixctl_cb_func ovn_northd_is_paused; > > @@ -752,7 +751,7 @@ main(int argc, char *argv[]) > > int res = EXIT_SUCCESS; > > struct unixctl_server *unixctl; > > int retval; > > - bool exiting; > > + struct ovn_exit_args exit_args = {}; > > int n_threads = 1; > > struct northd_state state = { > > .had_lock = false, > > @@ -774,7 +773,8 @@ main(int argc, char *argv[]) > > if (retval) { > > exit(EXIT_FAILURE); > > } > > - unixctl_command_register("exit", "", 0, 0, ovn_northd_exit, > &exiting); > > + unixctl_command_register("exit", "", 0, 0, > ovn_exit_command_callback, > > + &exit_args); > > unixctl_command_register("pause", "", 0, 0, ovn_northd_pause, > &state); > > unixctl_command_register("resume", "", 0, 0, ovn_northd_resume, > &state); > > unixctl_command_register("is-paused", "", 0, 0, > ovn_northd_is_paused, > > @@ -878,11 +878,9 @@ main(int argc, char *argv[]) > > run_update_worker_pool(n_threads); > > > > /* Main loop. */ > > - exiting = false; > > - > > struct northd_engine_context eng_ctx = {}; > > > > - while (!exiting) { > > + while (!exit_args.exiting) { > > update_ssl_config(); > > memory_run(); > > if (memory_should_report()) { > > @@ -1024,7 +1022,7 @@ main(int argc, char *argv[]) > > unixctl_server_run(unixctl); > > unixctl_server_wait(unixctl); > > memory_wait(); > > - if (exiting) { > > + if (exit_args.exiting) { > > poll_immediate_wake(); > > } > > > > @@ -1057,15 +1055,16 @@ main(int argc, char *argv[]) > > stopwatch_stop(NORTHD_LOOP_STOPWATCH_NAME, time_msec()); > > poll_block(); > > if (should_service_stop()) { > > - exiting = true; > > + exit_args.exiting = true; > > } > > stopwatch_start(NORTHD_LOOP_STOPWATCH_NAME, time_msec()); > > } > > inc_proc_northd_cleanup(); > > > > - unixctl_server_destroy(unixctl); > > ovsdb_idl_loop_destroy(&ovnnb_idl_loop); > > ovsdb_idl_loop_destroy(&ovnsb_idl_loop); > > + ovn_exit_args_finish(&exit_args); > > + unixctl_server_destroy(unixctl); > > service_stop(); > > run_update_worker_pool(0); > > ovsrcu_exit(); > > @@ -1073,16 +1072,6 @@ main(int argc, char *argv[]) > > exit(res); > > } > > > > -static void > > -ovn_northd_exit(struct unixctl_conn *conn, int argc OVS_UNUSED, > > - const char *argv[] OVS_UNUSED, void *exiting_) > > -{ > > - bool *exiting = exiting_; > > - *exiting = true; > > - > > - unixctl_command_reply(conn, NULL); > > -} > > - > > static void > > ovn_northd_pause(struct unixctl_conn *conn, int argc OVS_UNUSED, > > const char *argv[] OVS_UNUSED, void *state_) > > _______________________________________________ > dev mailing list > d...@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > Thanks, Ales -- Ales Musil Senior Software Engineer - OVN Core Red Hat EMEA <https://www.redhat.com> amu...@redhat.com <https://red.ht/sig> _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev