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.

Best regards, Ilya Maximets.
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to