Skip to content

Commit

Permalink
controller, northd: Wait for cleanup before replying to exit
Browse files Browse the repository at this point in the history
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 <amusil@redhat.com>
Acked-by: Mark Michelson <mmichels@redhat.com>
Signed-off-by: Mark Michelson <mmichels@redhat.com>
  • Loading branch information
almusil authored and putnopvut committed Oct 20, 2023
1 parent e47d782 commit 0deaaa5
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 45 deletions.
35 changes: 8 additions & 27 deletions controller/ovn-controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -4217,15 +4207,15 @@ main(int argc, char *argv[])
memory_wait();
poll_block();
if (should_service_stop()) {
exiting = true;
exit_args.exiting = true;
}
}

engine_set_context(NULL);
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,
Expand Down Expand Up @@ -4277,7 +4267,6 @@ main(int argc, char *argv[])
}

free(ovn_version);
unixctl_server_destroy(unixctl);
lflow_destroy();
ofctrl_destroy();
pinctrl_destroy();
Expand All @@ -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);
Expand Down Expand Up @@ -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_)
Expand Down
31 changes: 31 additions & 0 deletions lib/ovn-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
12 changes: 12 additions & 0 deletions lib/ovn-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
26 changes: 8 additions & 18 deletions northd/ovn-northd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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()) {
Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -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_)
Expand Down

0 comments on commit 0deaaa5

Please sign in to comment.