On 7 Jul 2023, at 14:19, Ilya Maximets wrote:
> On 7/7/23 14:12, Eelco Chaudron wrote:
>>
>>
>> On 7 Jul 2023, at 12:58, Ilya Maximets wrote:
>>
>>> On 7/5/23 15:54, Eelco Chaudron wrote:
>>>>
>>>>
>>>> On 4 Jul 2023, at 15:11, Ilya Maximets wrote:
>>>>
>>>>> Before the cleanup option, the bridge_exit() call was fairly fast,
>>>>> because it didn't include any particularly long operations. However,
>>>>> with the cleanup flag, this function destroys a lot of datapath
>>>>> resources freeing a lot of memory, waiting on RCU and talking to
>>>>> the kernel. That may take a noticeable amount of time, especially
>>>>> on a busy system or under profilers/sanitizers. However, the unixctl
>>>>> 'exit' command replies instantly without waiting for any work to
>>>>> actually be done. This may cause system test failures or other
>>>>> issues where scripts expect ovs-vswitchd to exit or destroy all the
>>>>> datapath resources shortly after appctl call.
>>>>>
>>>>> Fix that by waiting for the bridge_exit() before replying to the user.
>>>>> At least, all the datapath resources will actually be destroyed by
>>>>> the time ovs-appctl exits.
>>>>>
>>>>> Also moving a structure from stack to global. Seems cleaner this way.
>>>>
>>>> Thanks, yes it looks cleaner. One comment inline below.
>>>>
>>>> //Eelco
>>>>
>>>>
>>>>> Fixes: fe13ccdca6a2 ("vswitchd: Add --cleanup option to the 'appctl exit'
>>>>> command")
>>>>> Signed-off-by: Ilya Maximets <i.maxim...@ovn.org>
>>>>> ---
>>>>> vswitchd/ovs-vswitchd.c | 38 +++++++++++++++++++-------------------
>>>>> 1 file changed, 19 insertions(+), 19 deletions(-)
>>>>>
>>>>> diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c
>>>>> index a244d2f70..55b437871 100644
>>>>> --- a/vswitchd/ovs-vswitchd.c
>>>>> +++ b/vswitchd/ovs-vswitchd.c
>>>>> @@ -68,19 +68,18 @@ static unixctl_cb_func ovs_vswitchd_exit;
>>>>> static char *parse_options(int argc, char *argv[], char **unixctl_path);
>>>>> OVS_NO_RETURN static void usage(void);
>>>>>
>>>>> -struct ovs_vswitchd_exit_args {
>>>>> - bool *exiting;
>>>>> - bool *cleanup;
>>>>> -};
>>>>> +static struct ovs_vswitchd_exit_args {
>>>>> + struct unixctl_conn *conn;
>>>>> + bool exiting;
>>>>> + bool cleanup;
>>>>> +} exit_args;
>>>>>
>>>>> int
>>>>> main(int argc, char *argv[])
>>>>> {
>>>>> - char *unixctl_path = NULL;
>>>>> struct unixctl_server *unixctl;
>>>>> + char *unixctl_path = NULL;
>>>>> char *remote;
>>>>> - bool exiting, cleanup;
>>>>> - struct ovs_vswitchd_exit_args exit_args = {&exiting, &cleanup};
>>>>> int retval;
>>>>>
>>>>> set_program_name(argv[0]);
>>>>> @@ -111,14 +110,12 @@ main(int argc, char *argv[])
>>>>> exit(EXIT_FAILURE);
>>>>> }
>>>>> unixctl_command_register("exit", "[--cleanup]", 0, 1,
>>>>> - ovs_vswitchd_exit, &exit_args);
>>>>> + ovs_vswitchd_exit, NULL);
>>>>>
>>>>> bridge_init(remote);
>>>>> free(remote);
>>>>>
>>>>> - exiting = false;
>>>>> - cleanup = false;
>>>>> - while (!exiting) {
>>>>> + while (!exit_args.exiting) {
>>>>> OVS_USDT_PROBE(main, run_start);
>>>>> memory_run();
>>>>> if (memory_should_report()) {
>>>>> @@ -137,16 +134,20 @@ main(int argc, char *argv[])
>>>>> bridge_wait();
>>>>> unixctl_server_wait(unixctl);
>>>>> netdev_wait();
>>>>> - if (exiting) {
>>>>> + if (exit_args.exiting) {
>>>>> poll_immediate_wake();
>>>>> }
>>>>> OVS_USDT_PROBE(main, poll_block);
>>>>> poll_block();
>>>>> if (should_service_stop()) {
>>>>> - exiting = true;
>>>>> + exit_args.exiting = true;
>>>>> }
>>>>> }
>>>>> - bridge_exit(cleanup);
>>>>> + bridge_exit(exit_args.cleanup);
>>>>> +
>>>>> + if (exit_args.conn) {
>>>>> + unixctl_command_reply(exit_args.conn, NULL);
>>>>> + }
>>>>> unixctl_server_destroy(unixctl);
>>>>> service_stop();
>>>>> vlog_disable_async();
>>>>> @@ -304,10 +305,9 @@ usage(void)
>>>>>
>>>>> static void
>>>>> ovs_vswitchd_exit(struct unixctl_conn *conn, int argc,
>>>>> - const char *argv[], void *exit_args_)
>>>>> + const char *argv[], void *args OVS_UNUSED)
>>>>> {
>>>>> - struct ovs_vswitchd_exit_args *exit_args = exit_args_;
>>>>> - *exit_args->exiting = true;
>>>>> - *exit_args->cleanup = argc == 2 && !strcmp(argv[1], "--cleanup");
>>>>> - unixctl_command_reply(conn, NULL);
>>>>> + exit_args.conn = conn;
>>>>
>>>> Should we try to protect from two exit command in the same
>>>> unixctl_server_run()?
>>>> Something like:
>>>>
>>>> if (exit_args.conn) {
>>>> unixctl_command_reply(conn, NULL);
>>>> } else {
>>>> exit_args.conn = conn;
>>>> }
>>>>
>>>
>>> Good point. It's unlikely, but can happen.
>>> We could either do what you suggested or store an array of connections
>>> and try to reply to all of them. It becomes a bit inconsistent though
>>> if different calls have different options.
>>>
>>> What do you think?
>>
>> I was thinking of an array also but what happens with the one not fitting in
>> the array!?
>
> People created realloc for that. :)
>
>>
>> However giving it another thought, it might just break with a pipe error and
>> quit. So maybe we should just reply to the first one and let the other
>> dingle until the application get killed?
>
> That also an option. Not sure what is better.
> An array is the most clean solution, I guess.
ACK lets go with the realloc() array ;)
>
> Best regards, Ilya Maximets.
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev