All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Daniel P. Berrangé" <berrange@redhat.com>
To: Het Gala <het.gala@nutanix.com>
Cc: qemu-devel@nongnu.org, quintela@redhat.com, dgilbert@redhat.com,
	pbonzini@redhat.com, armbru@redhat.com, eblake@redhat.com,
	prerna.saxena@nutanix.com,
	Manish Mishra <manish.mishra@nutanix.com>
Subject: Re: [PATCH v2 5/7] multifd: establishing connection between any non-default src and dest pair
Date: Tue, 26 Jul 2022 11:44:02 +0100	[thread overview]
Message-ID: <Yt/Fcj7ylaOzFpQx@redhat.com> (raw)
In-Reply-To: <20220721195620.123837-6-het.gala@nutanix.com>

In $SUBJECT      s/multifd:/io:/ as this is not migration related.

On Thu, Jul 21, 2022 at 07:56:18PM +0000, Het Gala wrote:
> i) Binding of the socket to source ip address and port on the non-default
>    interface has been implemented for multi-FD connection, which was not
>    necessary earlier because the binding was on the default interface itself.
> 
> ii) Created an end to end connection between all multi-FD source and
>     destination pairs.
> 
> Suggested-by: Manish Mishra <manish.mishra@nutanix.com>
> Signed-off-by: Het Gala <het.gala@nutanix.com>
> ---
>  include/io/channel-socket.h    | 44 ++++++++++++++++
>  include/qemu/sockets.h         |  6 ++-
>  io/channel-socket.c            | 93 ++++++++++++++++++++++++++--------
>  migration/socket.c             |  4 +-
>  tests/unit/test-util-sockets.c | 16 +++---
>  util/qemu-sockets.c            | 90 +++++++++++++++++++++++---------
>  6 files changed, 196 insertions(+), 57 deletions(-)
> 
> diff --git a/include/io/channel-socket.h b/include/io/channel-socket.h
> index 513c428fe4..8168866b06 100644
> --- a/include/io/channel-socket.h
> +++ b/include/io/channel-socket.h
> @@ -211,6 +211,50 @@ void qio_channel_socket_dgram_async(QIOChannelSocket *ioc,
>                                      GMainContext *context);
>  
>  
> +/**
> + * qio_channel_socket_connect_all_sync:

This needs to be called qio_channel_socket_connect_full_sync to
match the naming conventions in use in IO code.


> + * @ioc: the socket channel object
> + * @dst_addr: the destination address to connect to
> + * @src_addr: the source address to be connected

'the optional source address to bind to'


> + * @errp: pointer to a NULL-initialized error object
> + *
> + * Attempt to connect to the address @dst_addr with @src_addr.

  * Attempt to connect to the address @dst_addr. If @src_addr
  * is non-NULL, it will be bound to in order to control outbound
  * interface routing.


> + * This method will run in the foreground so the caller will not
> + * regain execution control until the connection is established or
> + * an error occurs.
> + */
> +int qio_channel_socket_connect_all_sync(QIOChannelSocket *ioc,
> +                                    SocketAddress *dst_addr,
> +                                    SocketAddress *src_addr,
> +                                    Error **errp);

Vertical mis-alignment of parameters 

> +
> +/**
> + * qio_channel_socket_connect_all_async:

Needs to be qio_channel_socket_connect_full_async


> + * @ioc: the socket channel object
> + * @dst_addr: the destination address to connect to

@src_addr needs to be placed here...

> + * @callback: the function to invoke on completion
> + * @opaque: user data to pass to @callback
> + * @destroy: the function to free @opaque
> + * @context: the context to run the async task. If %NULL, the default
> + *           context will be used.
> + * @src_addr: the source address to be connected

...not here

and same note about the docs comment

> + *
> + * Attempt to connect to the address @dst_addr with the @src_addr.

Same note about the docs comment

> + * This method will run in the background so the caller will regain
> + * execution control immediately. The function @callback
> + * will be invoked on completion or failure. The @dst_addr
> + * parameter will be copied, so may be freed as soon
> + * as this function returns without waiting for completion.
> + */
> +void qio_channel_socket_connect_all_async(QIOChannelSocket *ioc,
> +                                          SocketAddress *dst_addr,
> +                                          QIOTaskFunc callback,
> +                                          gpointer opaque,
> +                                          GDestroyNotify destroy,
> +                                          GMainContext *context,
> +                                          SocketAddress *src_addr);
> +
> +
>  /**
>   * qio_channel_socket_get_local_address:
>   * @ioc: the socket channel object





> diff --git a/migration/socket.c b/migration/socket.c
> index dab872a0fe..69fda774ba 100644
> --- a/migration/socket.c
> +++ b/migration/socket.c
> @@ -57,8 +57,8 @@ int outgoing_param_total_multifds(void)
>  void socket_send_channel_create(QIOTaskFunc f, void *data)
>  {
>      QIOChannelSocket *sioc = qio_channel_socket_new();
> -    qio_channel_socket_connect_async(sioc, outgoing_args.saddr,
> -                                     f, data, NULL, NULL);
> +    qio_channel_socket_connect_all_async(sioc, outgoing_args.saddr,
> +                                     f, data, NULL, NULL, NULL);
>  }

Don't change this call at all until the next patch which actually
needs to pass a non-NULL parameter for src.

>  QIOChannel *socket_send_channel_create_sync(Error **errp)
> diff --git a/tests/unit/test-util-sockets.c b/tests/unit/test-util-sockets.c
> index 63909ccb2b..aa26630045 100644
> --- a/tests/unit/test-util-sockets.c
> +++ b/tests/unit/test-util-sockets.c
> @@ -89,7 +89,7 @@ static void test_socket_fd_pass_name_good(void)
>      addr.type = SOCKET_ADDRESS_TYPE_FD;
>      addr.u.fd.str = g_strdup(mon_fdname);
>  
> -    fd = socket_connect(&addr, &error_abort);
> +    fd = socket_connect(&addr, NULL, &error_abort);
>      g_assert_cmpint(fd, !=, -1);
>      g_assert_cmpint(fd, !=, mon_fd);
>      close(fd);
> @@ -121,7 +121,7 @@ static void test_socket_fd_pass_name_bad(void)
>      addr.type = SOCKET_ADDRESS_TYPE_FD;
>      addr.u.fd.str = g_strdup(mon_fdname);
>  
> -    fd = socket_connect(&addr, &err);
> +    fd = socket_connect(&addr, NULL, &err);
>      g_assert_cmpint(fd, ==, -1);
>      error_free_or_abort(&err);
>  
> @@ -148,7 +148,7 @@ static void test_socket_fd_pass_name_nomon(void)
>      addr.type = SOCKET_ADDRESS_TYPE_FD;
>      addr.u.fd.str = g_strdup("myfd");
>  
> -    fd = socket_connect(&addr, &err);
> +    fd = socket_connect(&addr, NULL, &err);
>      g_assert_cmpint(fd, ==, -1);
>      error_free_or_abort(&err);
>  
> @@ -172,7 +172,7 @@ static void test_socket_fd_pass_num_good(void)
>      addr.type = SOCKET_ADDRESS_TYPE_FD;
>      addr.u.fd.str = g_strdup_printf("%d", sfd);
>  
> -    fd = socket_connect(&addr, &error_abort);
> +    fd = socket_connect(&addr, NULL, &error_abort);
>      g_assert_cmpint(fd, ==, sfd);
>  
>      fd = socket_listen(&addr, 1, &error_abort);
> @@ -194,7 +194,7 @@ static void test_socket_fd_pass_num_bad(void)
>      addr.type = SOCKET_ADDRESS_TYPE_FD;
>      addr.u.fd.str = g_strdup_printf("%d", sfd);
>  
> -    fd = socket_connect(&addr, &err);
> +    fd = socket_connect(&addr, NULL, &err);
>      g_assert_cmpint(fd, ==, -1);
>      error_free_or_abort(&err);
>  
> @@ -217,7 +217,7 @@ static void test_socket_fd_pass_num_nocli(void)
>      addr.type = SOCKET_ADDRESS_TYPE_FD;
>      addr.u.fd.str = g_strdup_printf("%d", STDOUT_FILENO);
>  
> -    fd = socket_connect(&addr, &err);
> +    fd = socket_connect(&addr, NULL, &err);
>      g_assert_cmpint(fd, ==, -1);
>      error_free_or_abort(&err);
>  
> @@ -246,10 +246,10 @@ static gpointer unix_client_thread_func(gpointer user_data)
>  
>      for (i = 0; i < ABSTRACT_SOCKET_VARIANTS; i++) {
>          if (row->expect_connect[i]) {
> -            fd = socket_connect(row->client[i], &error_abort);
> +            fd = socket_connect(row->client[i], NULL, &error_abort);
>              g_assert_cmpint(fd, >=, 0);
>          } else {
> -            fd = socket_connect(row->client[i], &err);
> +            fd = socket_connect(row->client[i], NULL, &err);
>              g_assert_cmpint(fd, ==, -1);
>              error_free_or_abort(&err);
>          }

I'd expect something added to the test suite to exercise the new
codepath. Obviously we'd be limted to dealing with 127.0.0.1,
but it can at least run the code paths.

> diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
> index 13b5b197f9..491e2f2bc9 100644
> --- a/util/qemu-sockets.c
> +++ b/util/qemu-sockets.c
> @@ -358,8 +358,10 @@ listen_ok:
>      ((rc) == -EINPROGRESS)
>  #endif
>  
> -static int inet_connect_addr(const InetSocketAddress *saddr,
> -                             struct addrinfo *addr, Error **errp)
> +static int inet_connect_addr(const InetSocketAddress *dst_addr,
> +                             const InetSocketAddress *src_addr,
> +                             struct addrinfo *addr, struct addrinfo *saddr,
> +                             Error **errp)
>  {
>      int sock, rc;
>  
> @@ -371,8 +373,28 @@ static int inet_connect_addr(const InetSocketAddress *saddr,
>      }
>      socket_set_fast_reuse(sock);
>  
> +    /* to bind the socket if src_addr is available */
> +
> +    if (src_addr) {
> +        struct sockaddr_in servaddr;
> +
> +        /* bind to a specific interface in the internet domain */
> +        /* to make sure the sin_zero filed is cleared */
> +        memset(&servaddr, 0, sizeof(servaddr));
> +
> +        servaddr.sin_family = AF_INET;
> +        servaddr.sin_addr.s_addr = inet_addr(src_addr->host);

My feedback from the previous posting has been ignored. This code is
broken for IPv6. Never call the IPv4-only APIs, getaddrinfo is the
 only way to get a 'struct sockaddr *' in a protocol portable manner.

> +        servaddr.sin_port = 0;
> +
> +        if (bind(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
> +            error_setg_errno(errp, errno, "Failed to bind socket");
> +            return -1;
> +        }
> +    }
> +
>      /* connect to peer */
>      do {
> +

Arbitrary whitespace change should be removed

>          rc = 0;
>          if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) {
>              rc = -errno;
> @@ -380,8 +402,14 @@ static int inet_connect_addr(const InetSocketAddress *saddr,

> @@ -446,41 +474,55 @@ static struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr,
>   *
>   * Returns: -1 on error, file descriptor on success.
>   */
> -int inet_connect_saddr(InetSocketAddress *saddr, Error **errp)
> +int inet_connect_saddr(InetSocketAddress *dst_addr,
> +                       InetSocketAddress *src_addr, Error **errp)
>  {
>      Error *local_err = NULL;
> -    struct addrinfo *res, *e;
> +    struct addrinfo *res_d, *res_s, *e, *x;
>      int sock = -1;
>  
> -    res = inet_parse_connect_saddr(saddr, errp);
> -    if (!res) {
> +    res_d = inet_parse_connect_saddr(dst_addr, errp);
> +    if (!res_d) {
>          return -1;
>      }
>  
> -    for (e = res; e != NULL; e = e->ai_next) {
> +    if (src_addr) {
> +        res_s = inet_parse_connect_saddr(src_addr, errp);
> +        if (!res_s) {
> +            return -1;
> +        }
> +    }
> +
> +    for (e = res_d; e != NULL; e = e->ai_next) {
>          error_free(local_err);
>          local_err = NULL;
>  
>  #ifdef HAVE_IPPROTO_MPTCP
> -        if (saddr->has_mptcp && saddr->mptcp) {
> +        if (dst_addr->has_mptcp && dst_addr->mptcp) {
>              e->ai_protocol = IPPROTO_MPTCP;
>          }
>  #endif
> +        for (x = res_s; x != NULL; x = x->ai_next) {
> +            if (!src_addr || e->ai_family == x->ai_family) {

>  
> -        sock = inet_connect_addr(saddr, e, &local_err);
> -        if (sock >= 0) {
> -            break;
> +                sock = inet_connect_addr(dst_addr, src_addr,
> +                                         e, x, &local_err);
> +                if (sock >= 0) {
> +                    break;
> +                }
> +            }
>          }
>      }

If the ai_family for the src is different from ai_family for
the dst, this loop will never call inet_connect_addr at all,
and leave local_err unset, and so the error_propagate call
below will have no error message to propagate.

>  
> -    freeaddrinfo(res);
> +    freeaddrinfo(res_d);
> +    freeaddrinfo(res_s);
>  
>      if (sock < 0) {
>          error_propagate(errp, local_err);
>          return sock;
>      }
>  
> -    if (saddr->keep_alive) {
> +    if (dst_addr->keep_alive) {
>          int val = 1;
>          int ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
>                               &val, sizeof(val));
> @@ -506,7 +548,7 @@ static int inet_dgram_saddr(InetSocketAddress *sraddr,
>      Error *err = NULL;
>  
>      /* lookup peer addr */
> -    memset(&ai,0, sizeof(ai));
> +    memset(&ai,0,sizeof(ai));

Unrelated whitespace change.

>      ai.ai_flags = AI_CANONNAME | AI_V4MAPPED | AI_ADDRCONFIG;
>      ai.ai_family = inet_ai_family_from_address(sraddr, &err);
>      ai.ai_socktype = SOCK_DGRAM;
> @@ -727,7 +769,7 @@ int inet_connect(const char *str, Error **errp)
>      InetSocketAddress *addr = g_new(InetSocketAddress, 1);
>  
>      if (!inet_parse(addr, str, errp)) {
> -        sock = inet_connect_saddr(addr, errp);
> +        sock = inet_connect_saddr(addr, NULL, errp);
>      }
>      qapi_free_InetSocketAddress(addr);
>      return sock;

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



  reply	other threads:[~2022-07-26 10:45 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-21 19:56 [PATCH v2 0/7] multifd: Multiple interface support on top of Multifd Het Gala
2022-07-21 19:56 ` [PATCH v2 1/7] multifd: adding more helper functions in util files for live migration Het Gala
2022-07-21 19:56 ` [PATCH v2 2/7] multifd: modifying 'migrate' qmp command to add multifd socket on particular src and dest pair Het Gala
2022-07-26 11:13   ` Daniel P. Berrangé
2022-07-28 15:02     ` Het Gala
2022-08-02  7:53       ` Markus Armbruster
2022-08-08  6:11         ` Het Gala
2022-08-08  9:29           ` Daniel P. Berrangé
2022-08-29  4:34           ` Het Gala
2022-09-21 10:08             ` Het Gala
2022-11-21 12:26         ` Juan Quintela
2022-11-22  9:26           ` Daniel P. Berrangé
2022-08-08  9:29       ` Daniel P. Berrangé
2022-07-21 19:56 ` [PATCH v2 3/7] multifd: adding multi-interface support for multifd on destination side Het Gala
2022-07-26 11:20   ` Daniel P. Berrangé
2022-07-28 15:05     ` Het Gala
2022-07-21 19:56 ` [PATCH v2 4/7] multifd: HMP changes for multifd source and " Het Gala
2022-07-21 19:56 ` [PATCH v2 5/7] multifd: establishing connection between any non-default src and dest pair Het Gala
2022-07-26 10:44   ` Daniel P. Berrangé [this message]
2022-07-28 15:15     ` Het Gala
2022-07-21 19:56 ` [PATCH v2 6/7] muitlfd: Correcting nit : whitespace error changes in qemu-sockets.c file Het Gala
2022-07-21 19:56 ` [PATCH v2 7/7] multifd: adding support for multifd connections dynamically Het Gala

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Yt/Fcj7ylaOzFpQx@redhat.com \
    --to=berrange@redhat.com \
    --cc=armbru@redhat.com \
    --cc=dgilbert@redhat.com \
    --cc=eblake@redhat.com \
    --cc=het.gala@nutanix.com \
    --cc=manish.mishra@nutanix.com \
    --cc=pbonzini@redhat.com \
    --cc=prerna.saxena@nutanix.com \
    --cc=qemu-devel@nongnu.org \
    --cc=quintela@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.