diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c index 937ef8eceb..7de138104a 100644 --- a/controller/ovn-controller.c +++ b/controller/ovn-controller.c @@ -79,7 +79,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; @@ -3262,11 +3261,6 @@ flow_output_lflow_output_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 @@ -3338,9 +3332,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 = {}; int retval; ovs_cmdl_proctitle_init(argc, argv); @@ -3357,7 +3349,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(); @@ -3770,11 +3762,9 @@ main(int argc, char *argv[]) VLOG_INFO("OVN internal version is : [%s]", ovn_version); /* Main loop. */ - exiting = false; - restart = false; int64_t startup_ts = time_wall_msec(); bool sb_monitor_all = false; - while (!exiting) { + while (!exit_args.exiting) { memory_run(); if (memory_should_report()) { struct simap usage = SIMAP_INITIALIZER(&usage); @@ -4165,7 +4155,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(); } @@ -4217,7 +4207,7 @@ main(int argc, char *argv[]) memory_wait(); poll_block(); if (should_service_stop()) { - exiting = true; + exit_args.exiting = true; } } @@ -4225,7 +4215,7 @@ main(int argc, char *argv[]) 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, @@ -4277,7 +4267,6 @@ main(int argc, char *argv[]) } free(ovn_version); - unixctl_server_destroy(unixctl); lflow_destroy(); ofctrl_destroy(); pinctrl_destroy(); @@ -4294,6 +4283,8 @@ main(int argc, char *argv[]) ovs_feature_support_destroy(); free(ovs_remote); + ovn_exit_args_finish(&exit_args); + unixctl_server_destroy(unixctl); service_stop(); exit(retval); @@ -4410,16 +4401,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 8499d9a1fc..1fde64505d 100644 --- a/lib/ovn-util.c +++ b/lib/ovn-util.c @@ -809,3 +809,34 @@ get_bridge(const struct ovsrec_bridge_table *bridge_table, const char *br_name) } return NULL; } + +/* 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 22f17f64c4..000b0d06a4 100644 --- a/lib/ovn-util.h +++ b/lib/ovn-util.h @@ -320,4 +320,16 @@ const struct ovsrec_bridge *get_bridge(const struct ovsrec_bridge_table *, const char *br_name); +/* 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 4e18519fad..2a361ad906 100644 --- a/northd/ovn-northd.c +++ b/northd/ovn-northd.c @@ -44,7 +44,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; @@ -680,7 +679,7 @@ main(int argc, char *argv[]) int res = EXIT_SUCCESS; struct unixctl_server *unixctl; int retval; - bool exiting; + struct ovn_exit_args exit_args = {}; struct northd_state state = { .had_lock = false, .paused = false @@ -701,7 +700,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, @@ -775,10 +775,9 @@ main(int argc, char *argv[]) unsigned int ovnsb_cond_seqno = UINT_MAX; /* Main loop. */ - exiting = false; bool recompute = false; - while (!exiting) { + while (!exit_args.exiting) { update_ssl_config(); memory_run(); if (memory_should_report()) { @@ -910,7 +909,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(); } @@ -941,30 +940,21 @@ 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(); 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_)