On 3/30/22 16:07, Dumitru Ceara wrote:
> On 3/30/22 15:08, Ilya Maximets wrote:
>> On 3/21/22 11:45, Dumitru Ceara wrote:
>>> Hi Ilya.
>>>
>>> On 3/10/22 23:33, Ilya Maximets wrote:
>>>> Clustered OVSDB allows to use DNS names as addresses of raft members.
>>>> However, if DNS resolution fails during the initial database read,
>>>> this causes a fatal failure and exit of the ovsdb-server process.
>>>>
>>>> Also, if DNS name of a joining server is not resolvable for one of the
>>>> followers, this follower will reject append requests for a new server
>>>> to join until the name is successfully resolved.  This makes a follower
>>>> effectively non-functional while DNS is unavailable.
>>>>
>>>> To fix the problem relaxing the address verification.  Allowing
>>>
>>> s/relaxing/relax/
>>>
>>>> validation to pass if only name resolution failed and the address
>>>> is valid otherwise.  This will allow addresses to be added to the
>>>> database, so connections could be established later when the DNS
>>>> is available.
>>>
>>> This sounds reasonable to me.
>>>
>>>>
>>>> Additionally fixing missed initialization of the dns-resolve module.
>>>> Wihtout it, DNS requests are blocking.  This causes unexpected delays
>>>
>>> Typo: Wihtout
>>>
>>>> in runtime.
>>>>
>>>> Fixes: 771680d96fb6 ("DNS: Add basic support for asynchronous DNS 
>>>> resolving")
>>>> Reported-at: https://bugzilla.redhat.com/2055097
>>>> Signed-off-by: Ilya Maximets <[email protected]>
>>>> ---
>>>>  lib/dns-resolve.c            |  2 +-
>>>>  lib/socket-util.c            | 39 ++++++++++++++++++++++++------------
>>>>  lib/socket-util.h            |  3 ++-
>>>>  lib/stream.c                 |  2 +-
>>>>  ofproto/ofproto-dpif-sflow.c |  3 ++-
>>>>  ovsdb/ovsdb-server.c         |  3 +++
>>>>  ovsdb/raft-private.c         |  5 ++++-
>>>>  7 files changed, 39 insertions(+), 18 deletions(-)
>>>>
>>>> diff --git a/lib/dns-resolve.c b/lib/dns-resolve.c
>>>> index d34451434..8bcecb90c 100644
>>>> --- a/lib/dns-resolve.c
>>>> +++ b/lib/dns-resolve.c
>>>> @@ -265,7 +265,7 @@ resolve_callback__(void *req_, int err, struct 
>>>> ub_result *result)
>>>>      if (err != 0 || (result->qtype == ns_t_aaaa && !result->havedata)) {
>>>>          ub_resolve_free(result);
>>>>          req->state = RESOLVE_ERROR;
>>>> -        VLOG_ERR_RL(&rl, "%s: failed to resolve", req->name);
>>>> +        VLOG_WARN_RL(&rl, "%s: failed to resolve", req->name);
>>>>          return;
>>>>      }
>>>>  
>>>> diff --git a/lib/socket-util.c b/lib/socket-util.c
>>>> index 4f1ffecf5..38705cc51 100644
>>>> --- a/lib/socket-util.c
>>>> +++ b/lib/socket-util.c
>>>> @@ -62,7 +62,8 @@ static bool parse_sockaddr_components(struct 
>>>> sockaddr_storage *ss,
>>>>                                        const char *port_s,
>>>>                                        uint16_t default_port,
>>>>                                        const char *s,
>>>> -                                      bool resolve_host);
>>>> +                                      bool resolve_host,
>>>> +                                      bool *dns_failure);
>>>>  
>>>>  /* Sets 'fd' to non-blocking mode.  Returns 0 if successful, otherwise a
>>>>   * positive errno value. */
>>>> @@ -438,7 +439,7 @@ parse_sockaddr_components_dns(struct sockaddr_storage 
>>>> *ss OVS_UNUSED,
>>>>      dns_resolve(host_s, &tmp_host_s);
>>>>      if (tmp_host_s != NULL) {
>>>>          parse_sockaddr_components(ss, tmp_host_s, port_s,
>>>> -                                  default_port, s, false);
>>>> +                                  default_port, s, false, NULL);
>>>>          free(tmp_host_s);
>>>>          return true;
>>>>      }
>>>> @@ -450,11 +451,15 @@ parse_sockaddr_components(struct sockaddr_storage 
>>>> *ss,
>>>>                            char *host_s,
>>>>                            const char *port_s, uint16_t default_port,
>>>>                            const char *s,
>>>> -                          bool resolve_host)
>>>> +                          bool resolve_host, bool *dns_failure)
>>>>  {
>>>>      struct sockaddr_in *sin = sin_cast(sa_cast(ss));
>>>>      int port;
>>>>  
>>>> +    if (dns_failure) {
>>>> +        *dns_failure = false;
>>>> +    }
>>>> +
>>>>      if (port_s && port_s[0]) {
>>>>          if (!str_to_int(port_s, 10, &port) || port < 0 || port > 65535) {
>>>>              VLOG_ERR("%s: bad port number \"%s\"", s, port_s);
>>>> @@ -501,10 +506,15 @@ parse_sockaddr_components(struct sockaddr_storage 
>>>> *ss,
>>>>      return true;
>>>>  
>>>>  resolve:
>>>> -    if (resolve_host && parse_sockaddr_components_dns(ss, host_s, port_s,
>>>> -                                                      default_port, s)) {
>>>> -        return true;
>>>> -    } else if (!resolve_host) {
>>>> +    if (resolve_host) {
>>>> +        if (parse_sockaddr_components_dns(ss, host_s, port_s,
>>>> +                                          default_port, s)) {
>>>> +            return true;
>>>> +        }
>>>> +        if (dns_failure) {
>>>> +            *dns_failure = true;
>>>> +        }
>>>> +    } else {
>>>>          VLOG_ERR("%s: bad IP address \"%s\"", s, host_s);
>>>>      }
>>>>  exit:
>>>> @@ -521,10 +531,12 @@ exit:
>>>>   * It resolves the host if 'resolve_host' is true.
>>>>   *
>>>>   * On success, returns true and stores the parsed remote address into 
>>>> '*ss'.
>>>> - * On failure, logs an error, stores zeros into '*ss', and returns false. 
>>>> */
>>>> + * On failure, logs an error, stores zeros into '*ss', and returns false,
>>>> + * '*dns_failure' indicates if the host resolution failed. */
>>>>  bool
>>>>  inet_parse_active(const char *target_, int default_port,
>>>> -                  struct sockaddr_storage *ss, bool resolve_host)
>>>> +                  struct sockaddr_storage *ss,
>>>> +                  bool resolve_host, bool *dns_failure)
>>>
>>> It's not really a fair ask I guess, but would it be possible to avoid
>>> changing this signature?
>>>
>>> OVN uses it in a few places.  I know there's no real contract for
>>> functions in lib/*.h but OVN does use them directly.
>>>
>>> If you don't see a simple way of avoiding the signature change, it's not
>>> a big deal I guess, we can always just bump the OVS submodule version in
>>> OVN.
>>
>> Yeah, I'm not sure we can actually keep the signature intact.
>> In general, DNS resolve is a bit hacked into the process and
>> it's hard to manage it in a good way.  I think, this API should
>> be split in parts or changed to make error reporting more
>> clear, e.g. by returning a enum instead of bool.  But none of
>> these options will actually preserve the signature.
>>
>> Does that make sense?
>>
>> Also, the next submodule update in OVN will likely require
>> code changes due to UB fixes for loops, so it doesn't seem
>> important to keep update seamless for this part.
>>
> 
> Good point.  Let's keep it like in your original patch.
> 
>>>
>>>>  {
>>>>      char *target = xstrdup(target_);
>>>>      char *port, *host;
>>>> @@ -539,7 +551,7 @@ inet_parse_active(const char *target_, int 
>>>> default_port,
>>>>          ok = false;
>>>>      } else {
>>>>          ok = parse_sockaddr_components(ss, host, port, default_port,
>>>> -                                       target_, resolve_host);
>>>> +                                       target_, resolve_host, 
>>>> dns_failure);
>>>>      }
>>>>      if (!ok) {
>>>>          memset(ss, 0, sizeof *ss);
>>>> @@ -576,7 +588,7 @@ inet_open_active(int style, const char *target, int 
>>>> default_port,
>>>>      int error;
>>>>  
>>>>      /* Parse. */
>>>> -    if (!inet_parse_active(target, default_port, &ss, true)) {
>>>> +    if (!inet_parse_active(target, default_port, &ss, true, NULL)) {
>>>>          error = EAFNOSUPPORT;
>>>>          goto exit;
>>>>      }
>>>> @@ -660,7 +672,7 @@ inet_parse_passive(const char *target_, int 
>>>> default_port,
>>>>          ok = false;
>>>>      } else {
>>>>          ok = parse_sockaddr_components(ss, host, port, default_port,
>>>> -                                       target_, true);
>>>> +                                       target_, true, NULL);
>>>>      }
>>>>      if (!ok) {
>>>>          memset(ss, 0, sizeof *ss);
>>>> @@ -783,7 +795,8 @@ inet_parse_address(const char *target_, struct 
>>>> sockaddr_storage *ss)
>>>>  {
>>>>      char *target = xstrdup(target_);
>>>>      char *host = unbracket(target);
>>>> -    bool ok = parse_sockaddr_components(ss, host, NULL, 0, target_, 
>>>> false);
>>>> +    bool ok = parse_sockaddr_components(ss, host, NULL, 0,
>>>> +                                        target_, false, NULL);
>>>>      if (!ok) {
>>>>          memset(ss, 0, sizeof *ss);
>>>>      }
>>>> diff --git a/lib/socket-util.h b/lib/socket-util.h
>>>> index 9ccb7d4cc..bf66393df 100644
>>>> --- a/lib/socket-util.h
>>>> +++ b/lib/socket-util.h
>>>> @@ -49,7 +49,8 @@ ovs_be32 guess_netmask(ovs_be32 ip);
>>>>  void inet_parse_host_port_tokens(char *s, char **hostp, char **portp);
>>>>  void inet_parse_port_host_tokens(char *s, char **portp, char **hostp);
>>>>  bool inet_parse_active(const char *target, int default_port,
>>>> -                       struct sockaddr_storage *ssp, bool resolve_host);
>>>> +                       struct sockaddr_storage *ssp,
>>>> +                       bool resolve_host, bool *dns_failure);
>>>>  int inet_open_active(int style, const char *target, int default_port,
>>>>                       struct sockaddr_storage *ssp, int *fdp, uint8_t 
>>>> dscp);
>>>>  
>>>> diff --git a/lib/stream.c b/lib/stream.c
>>>> index fcaddf10a..71039e24f 100644
>>>> --- a/lib/stream.c
>>>> +++ b/lib/stream.c
>>>> @@ -788,7 +788,7 @@ stream_parse_target_with_default_port(const char 
>>>> *target, int default_port,
>>>>                                        struct sockaddr_storage *ss)
>>>>  {
>>>>      return ((!strncmp(target, "tcp:", 4) || !strncmp(target, "ssl:", 4))
>>>> -            && inet_parse_active(target + 4, default_port, ss, true));
>>>> +            && inet_parse_active(target + 4, default_port, ss, true, 
>>>> NULL));
>>>>  }
>>>>  
>>>>  /* Attempts to guess the content type of a stream whose first few bytes 
>>>> were
>>>> diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
>>>> index 30e7caf54..36b5c1768 100644
>>>> --- a/ofproto/ofproto-dpif-sflow.c
>>>> +++ b/ofproto/ofproto-dpif-sflow.c
>>>> @@ -468,7 +468,8 @@ sflow_choose_agent_address(const char *agent_device,
>>>>      const char *target;
>>>>      SSET_FOR_EACH (target, targets) {
>>>>          struct sockaddr_storage ss;
>>>> -        if (inet_parse_active(target, SFL_DEFAULT_COLLECTOR_PORT, &ss, 
>>>> true)) {
>>>> +        if (inet_parse_active(target, SFL_DEFAULT_COLLECTOR_PORT,
>>>> +                              &ss, true, NULL)) {
>>>>              /* sFlow only supports target in default routing table with
>>>>               * packet mark zero.
>>>>               */
>>>> diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c
>>>> index b975c17fc..a4f6bca73 100644
>>>> --- a/ovsdb/ovsdb-server.c
>>>> +++ b/ovsdb/ovsdb-server.c
>>>> @@ -26,6 +26,7 @@
>>>>  #include "command-line.h"
>>>>  #include "daemon.h"
>>>>  #include "dirs.h"
>>>> +#include "dns-resolve.h"
>>>>  #include "openvswitch/dynamic-string.h"
>>>>  #include "fatal-signal.h"
>>>>  #include "file.h"
>>>> @@ -329,6 +330,7 @@ main(int argc, char *argv[])
>>>>      service_start(&argc, &argv);
>>>>      fatal_ignore_sigpipe();
>>>>      process_init();
>>>> +    dns_resolve_init(true);
>>>>  
>>>>      bool active = false;
>>>>      parse_options(argc, argv, &db_filenames, &remotes, &unixctl_path,
>>>> @@ -511,6 +513,7 @@ main(int argc, char *argv[])
>>>>                        run_command, process_status_msg(status));
>>>>          }
>>>>      }
>>>> +    dns_resolve_destroy();
>>>>      perf_counters_destroy();
>>>>      service_stop();
>>>>      return 0;
>>>> diff --git a/ovsdb/raft-private.c b/ovsdb/raft-private.c
>>>> index 30760233e..970cf3b54 100644
>>>> --- a/ovsdb/raft-private.c
>>>> +++ b/ovsdb/raft-private.c
>>>> @@ -36,7 +36,10 @@ raft_address_validate(const char *address)
>>>>          return NULL;
>>>>      } else if (!strncmp(address, "ssl:", 4) || !strncmp(address, "tcp:", 
>>>> 4)) {
>>>>          struct sockaddr_storage ss;
>>>> -        if (!inet_parse_active(address + 4, -1, &ss, true)) {
>>>> +        bool dns_failure;
>>>
>>> Not really an issue, but just to make it more clear, could we explicitly
>>> initialize dns_failure here?
>>
>> ok.
>>
>>>
>>>> +
>>>> +        if (!inet_parse_active(address + 4, -1, &ss, true, &dns_failure)
>>>> +            && !dns_failure) {
>>>>              return ovsdb_error(NULL, "%s: syntax error in address", 
>>>> address);
>>>>          }
>>>>          return NULL;
>>>
>>> Not really mandatory for this patch but we might as well update some
>>> comments in raft.c to make it clear that it's allowed to refer to
>>> servers by name, e.g., the comment for raft_join_cluster() mentions:
>>>
>>>  * The new server is located at 'local_address', which must take one of the
>>>  * forms "tcp:IP:PORT" or "ssl:IP:PORT", where IP is an IPv4 address or a
>>>  * square bracket enclosed IPv6 address and PORT is a TCP port number.
>>>
>>> The same thing applies to raft_create_cluster().
>>
>> As I said, DNS resolve is a bit hacked into the logic here, so there
>> are lots of fairly confusing comments in both raft and socket-util
>> modules.  When I worked on the patch I started re-writing and clarifying
>> all of them but stopped in the middle.  It's just a lot of comment
>> changes and it's not really relevant to the current patch, so deserves
>> a separate one.  What do you think?
>>
> 
> Sounds good to me, therefore:
> 
> Acked-by: Dumitru Ceara <[email protected]>

Thanks!  I addressed all other minor comments and applied the fix.
Also backported down to 2.13.

Best regards, Ilya Maximets.

> 
>>>
>>> Most of the minor comments above can be addressed at apply time so
>>> there's no need for a v2 but I'd like to see if there's a way to avoid
>>> changing the signature of inet_parse_active() before ACKing the patch.
>>>
>>> Regards,
>>> Dumitru
>>>
>>
> 

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to