diff mbox

[ovs-dev,v2] socket-util: Support sendmmsg() regardless of platform.

Message ID 20170713003913.13571-1-blp@ovn.org
State Accepted
Headers show

Commit Message

Ben Pfaff July 13, 2017, 12:39 a.m. UTC
This will have its first user in an upcoming commit.

Signed-off-by: Ben Pfaff <blp@ovn.org>
---
v1->v2: Note that FreeBSD also has sendmmsg.  Fix sendmsg() return type.

 configure.ac                |  3 ++-
 include/sparse/sys/socket.h |  5 +++++
 lib/socket-util.c           | 38 ++++++++++++++++++++++++++++++++++++++
 lib/socket-util.h           | 27 +++++++++++++++++++++++++++
 4 files changed, 72 insertions(+), 1 deletion(-)

Comments

Gao Zhenyu July 13, 2017, 2:46 a.m. UTC | #1
LGTM.

Thanks
Zhenyu Gao

2017-07-13 8:39 GMT+08:00 Ben Pfaff <blp@ovn.org>:

> This will have its first user in an upcoming commit.
>
> Signed-off-by: Ben Pfaff <blp@ovn.org>
> ---
> v1->v2: Note that FreeBSD also has sendmmsg.  Fix sendmsg() return type.
>
>  configure.ac                |  3 ++-
>  include/sparse/sys/socket.h |  5 +++++
>  lib/socket-util.c           | 38 ++++++++++++++++++++++++++++++++++++++
>  lib/socket-util.h           | 27 +++++++++++++++++++++++++++
>  4 files changed, 72 insertions(+), 1 deletion(-)
>
> diff --git a/configure.ac b/configure.ac
> index 6404b5fc1222..9ef6aad3a36e 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -106,7 +106,8 @@ AC_CHECK_DECLS([sys_siglist], [], [], [[#include
> <signal.h>]])
>  AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec],
>    [], [], [[#include <sys/stat.h>]])
>  AC_CHECK_MEMBERS([struct ifreq.ifr_flagshigh], [], [], [[#include
> <net/if.h>]])
> -AC_CHECK_FUNCS([mlockall strnlen getloadavg statvfs getmntent_r])
> +AC_CHECK_MEMBERS([struct mmsghdr.msg_len], [], [], [[#include
> <sys/socket.h>]])
> +AC_CHECK_FUNCS([mlockall strnlen getloadavg statvfs getmntent_r sendmmsg])
>  AC_CHECK_HEADERS([mntent.h sys/statvfs.h linux/types.h linux/if_ether.h
> stdatomic.h])
>  AC_CHECK_HEADERS([net/if_mib.h], [], [], [[#include <sys/types.h>
>  #include <net/if.h>]])
> diff --git a/include/sparse/sys/socket.h b/include/sparse/sys/socket.h
> index 3212bf4b7f13..88a5387e7f9b 100644
> --- a/include/sparse/sys/socket.h
> +++ b/include/sparse/sys/socket.h
> @@ -75,6 +75,11 @@ __cmsg_nxthdr(struct msghdr *msg, struct cmsghdr *cmsg)
>              : NULL);
>  }
>
> +struct mmsghdr {
> +    struct msghdr msg_hdr;
> +    unsigned int msg_len;
> +};
> +
>  enum {
>      SCM_RIGHTS = 1
>  };
> diff --git a/lib/socket-util.c b/lib/socket-util.c
> index 2c0f1e62bd99..7148ae3da67c 100644
> --- a/lib/socket-util.c
> +++ b/lib/socket-util.c
> @@ -1020,3 +1020,41 @@ sock_strerror(int error)
>      return ovs_strerror(error);
>  #endif
>  }
> +
> +static int
> +emulate_sendmmsg(int fd, struct mmsghdr *msgs, unsigned int n,
> +                 unsigned int flags)
> +{
> +    for (unsigned int i = 0; i < n; i++) {
> +        ssize_t retval = sendmsg(fd, &msgs[i].msg_hdr, flags);
> +        if (retval < 0) {
> +            return i ? i : retval;
> +        }
> +        msgs[i].msg_len = retval;
> +    }
> +    return n;
> +}
> +
> +#ifndef HAVE_SENDMMSG
> +int
> +sendmmsg(int fd, struct mmsghdr *msgs, unsigned int n, unsigned int flags)
> +{
> +    return emulate_sendmmsg(fd, msgs, n, flags);
> +}
> +#else
> +int
> +wrap_sendmmsg(int fd, struct mmsghdr *msgs, unsigned int n, unsigned int
> flags)
> +{
> +    static bool sendmmsg_broken = false;
> +    if (!sendmmsg_broken) {
> +        int save_errno = errno;
> +        int retval = sendmmsg(fd, msgs, n, flags);
> +        if (retval >= 0 || errno != ENOSYS) {
> +            return retval;
> +        }
> +        sendmmsg_broken = true;
> +        errno = save_errno;
> +    }
> +    return emulate_sendmmsg(fd, msgs, n, flags);
> +}
> +#endif
> diff --git a/lib/socket-util.h b/lib/socket-util.h
> index 5bf76a40eb84..ef316cb8cc72 100644
> --- a/lib/socket-util.h
> +++ b/lib/socket-util.h
> @@ -87,6 +87,33 @@ int make_unix_socket(int style, bool nonblock,
>                       const char *bind_path, const char *connect_path);
>  int get_unix_name_len(const struct sockaddr_un *sun, socklen_t sun_len);
>
> +/* Universal sendmmsg support.
> + *
> + * Some platforms, such as new enough Linux and FreeBSD, support
> sendmmsg, but
> + * other platforms (or older ones) do not.  We add the following
> infrastructure
> + * to allow all code to use sendmmsg, regardless of platform support:
> + *
> + *   - For platforms that lack sendmmsg entirely, we emulate it.
> + *
> + *   - Some platforms have sendmmsg() in the C library but not in the
> kernel.
> + *     For example, this is true if a Linux system has a newer glibc with
> an
> + *     old kernel.  To compensate, even if sendmmsg() appears to be
> available,
> + *     we still wrap it with a handler that uses our emulation if
> sendmmsg()
> + *     returns ENOSYS.
> + */
> +#ifndef HAVE_STRUCT_MMSGHDR_MSG_LEN
> +struct mmsghdr {
> +    struct msghdr msg_hdr;
> +    unsigned int msg_len;
> +};
> +#endif
> +#ifndef HAVE_SENDMMSG
> +int sendmmsg(int, struct mmsghdr *, unsigned int, unsigned int);
> +#else
> +#define sendmmsg wrap_sendmmsg
> +int wrap_sendmmsg(int, struct mmsghdr *, unsigned int, unsigned int);
> +#endif
> +
>  /* Helpers for calling ioctl() on an AF_INET socket. */
>  struct ifreq;
>  int af_inet_ioctl(unsigned long int command, const void *arg);
> --
> 2.10.2
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
Ben Pfaff July 13, 2017, 3:38 a.m. UTC | #2
Thanks.  I applied this to master.

On Thu, Jul 13, 2017 at 10:46:44AM +0800, Gao Zhenyu wrote:
> LGTM.
> 
> Thanks
> Zhenyu Gao
> 
> 2017-07-13 8:39 GMT+08:00 Ben Pfaff <blp@ovn.org>:
> 
> > This will have its first user in an upcoming commit.
> >
> > Signed-off-by: Ben Pfaff <blp@ovn.org>
> > ---
> > v1->v2: Note that FreeBSD also has sendmmsg.  Fix sendmsg() return type.
> >
> >  configure.ac                |  3 ++-
> >  include/sparse/sys/socket.h |  5 +++++
> >  lib/socket-util.c           | 38 ++++++++++++++++++++++++++++++++++++++
> >  lib/socket-util.h           | 27 +++++++++++++++++++++++++++
> >  4 files changed, 72 insertions(+), 1 deletion(-)
> >
> > diff --git a/configure.ac b/configure.ac
> > index 6404b5fc1222..9ef6aad3a36e 100644
> > --- a/configure.ac
> > +++ b/configure.ac
> > @@ -106,7 +106,8 @@ AC_CHECK_DECLS([sys_siglist], [], [], [[#include
> > <signal.h>]])
> >  AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec],
> >    [], [], [[#include <sys/stat.h>]])
> >  AC_CHECK_MEMBERS([struct ifreq.ifr_flagshigh], [], [], [[#include
> > <net/if.h>]])
> > -AC_CHECK_FUNCS([mlockall strnlen getloadavg statvfs getmntent_r])
> > +AC_CHECK_MEMBERS([struct mmsghdr.msg_len], [], [], [[#include
> > <sys/socket.h>]])
> > +AC_CHECK_FUNCS([mlockall strnlen getloadavg statvfs getmntent_r sendmmsg])
> >  AC_CHECK_HEADERS([mntent.h sys/statvfs.h linux/types.h linux/if_ether.h
> > stdatomic.h])
> >  AC_CHECK_HEADERS([net/if_mib.h], [], [], [[#include <sys/types.h>
> >  #include <net/if.h>]])
> > diff --git a/include/sparse/sys/socket.h b/include/sparse/sys/socket.h
> > index 3212bf4b7f13..88a5387e7f9b 100644
> > --- a/include/sparse/sys/socket.h
> > +++ b/include/sparse/sys/socket.h
> > @@ -75,6 +75,11 @@ __cmsg_nxthdr(struct msghdr *msg, struct cmsghdr *cmsg)
> >              : NULL);
> >  }
> >
> > +struct mmsghdr {
> > +    struct msghdr msg_hdr;
> > +    unsigned int msg_len;
> > +};
> > +
> >  enum {
> >      SCM_RIGHTS = 1
> >  };
> > diff --git a/lib/socket-util.c b/lib/socket-util.c
> > index 2c0f1e62bd99..7148ae3da67c 100644
> > --- a/lib/socket-util.c
> > +++ b/lib/socket-util.c
> > @@ -1020,3 +1020,41 @@ sock_strerror(int error)
> >      return ovs_strerror(error);
> >  #endif
> >  }
> > +
> > +static int
> > +emulate_sendmmsg(int fd, struct mmsghdr *msgs, unsigned int n,
> > +                 unsigned int flags)
> > +{
> > +    for (unsigned int i = 0; i < n; i++) {
> > +        ssize_t retval = sendmsg(fd, &msgs[i].msg_hdr, flags);
> > +        if (retval < 0) {
> > +            return i ? i : retval;
> > +        }
> > +        msgs[i].msg_len = retval;
> > +    }
> > +    return n;
> > +}
> > +
> > +#ifndef HAVE_SENDMMSG
> > +int
> > +sendmmsg(int fd, struct mmsghdr *msgs, unsigned int n, unsigned int flags)
> > +{
> > +    return emulate_sendmmsg(fd, msgs, n, flags);
> > +}
> > +#else
> > +int
> > +wrap_sendmmsg(int fd, struct mmsghdr *msgs, unsigned int n, unsigned int
> > flags)
> > +{
> > +    static bool sendmmsg_broken = false;
> > +    if (!sendmmsg_broken) {
> > +        int save_errno = errno;
> > +        int retval = sendmmsg(fd, msgs, n, flags);
> > +        if (retval >= 0 || errno != ENOSYS) {
> > +            return retval;
> > +        }
> > +        sendmmsg_broken = true;
> > +        errno = save_errno;
> > +    }
> > +    return emulate_sendmmsg(fd, msgs, n, flags);
> > +}
> > +#endif
> > diff --git a/lib/socket-util.h b/lib/socket-util.h
> > index 5bf76a40eb84..ef316cb8cc72 100644
> > --- a/lib/socket-util.h
> > +++ b/lib/socket-util.h
> > @@ -87,6 +87,33 @@ int make_unix_socket(int style, bool nonblock,
> >                       const char *bind_path, const char *connect_path);
> >  int get_unix_name_len(const struct sockaddr_un *sun, socklen_t sun_len);
> >
> > +/* Universal sendmmsg support.
> > + *
> > + * Some platforms, such as new enough Linux and FreeBSD, support
> > sendmmsg, but
> > + * other platforms (or older ones) do not.  We add the following
> > infrastructure
> > + * to allow all code to use sendmmsg, regardless of platform support:
> > + *
> > + *   - For platforms that lack sendmmsg entirely, we emulate it.
> > + *
> > + *   - Some platforms have sendmmsg() in the C library but not in the
> > kernel.
> > + *     For example, this is true if a Linux system has a newer glibc with
> > an
> > + *     old kernel.  To compensate, even if sendmmsg() appears to be
> > available,
> > + *     we still wrap it with a handler that uses our emulation if
> > sendmmsg()
> > + *     returns ENOSYS.
> > + */
> > +#ifndef HAVE_STRUCT_MMSGHDR_MSG_LEN
> > +struct mmsghdr {
> > +    struct msghdr msg_hdr;
> > +    unsigned int msg_len;
> > +};
> > +#endif
> > +#ifndef HAVE_SENDMMSG
> > +int sendmmsg(int, struct mmsghdr *, unsigned int, unsigned int);
> > +#else
> > +#define sendmmsg wrap_sendmmsg
> > +int wrap_sendmmsg(int, struct mmsghdr *, unsigned int, unsigned int);
> > +#endif
> > +
> >  /* Helpers for calling ioctl() on an AF_INET socket. */
> >  struct ifreq;
> >  int af_inet_ioctl(unsigned long int command, const void *arg);
> > --
> > 2.10.2
> >
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
diff mbox

Patch

diff --git a/configure.ac b/configure.ac
index 6404b5fc1222..9ef6aad3a36e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -106,7 +106,8 @@  AC_CHECK_DECLS([sys_siglist], [], [], [[#include <signal.h>]])
 AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec],
   [], [], [[#include <sys/stat.h>]])
 AC_CHECK_MEMBERS([struct ifreq.ifr_flagshigh], [], [], [[#include <net/if.h>]])
-AC_CHECK_FUNCS([mlockall strnlen getloadavg statvfs getmntent_r])
+AC_CHECK_MEMBERS([struct mmsghdr.msg_len], [], [], [[#include <sys/socket.h>]])
+AC_CHECK_FUNCS([mlockall strnlen getloadavg statvfs getmntent_r sendmmsg])
 AC_CHECK_HEADERS([mntent.h sys/statvfs.h linux/types.h linux/if_ether.h stdatomic.h])
 AC_CHECK_HEADERS([net/if_mib.h], [], [], [[#include <sys/types.h>
 #include <net/if.h>]])
diff --git a/include/sparse/sys/socket.h b/include/sparse/sys/socket.h
index 3212bf4b7f13..88a5387e7f9b 100644
--- a/include/sparse/sys/socket.h
+++ b/include/sparse/sys/socket.h
@@ -75,6 +75,11 @@  __cmsg_nxthdr(struct msghdr *msg, struct cmsghdr *cmsg)
             : NULL);
 }
 
+struct mmsghdr {
+    struct msghdr msg_hdr;
+    unsigned int msg_len;
+};
+
 enum {
     SCM_RIGHTS = 1
 };
diff --git a/lib/socket-util.c b/lib/socket-util.c
index 2c0f1e62bd99..7148ae3da67c 100644
--- a/lib/socket-util.c
+++ b/lib/socket-util.c
@@ -1020,3 +1020,41 @@  sock_strerror(int error)
     return ovs_strerror(error);
 #endif
 }
+
+static int
+emulate_sendmmsg(int fd, struct mmsghdr *msgs, unsigned int n,
+                 unsigned int flags)
+{
+    for (unsigned int i = 0; i < n; i++) {
+        ssize_t retval = sendmsg(fd, &msgs[i].msg_hdr, flags);
+        if (retval < 0) {
+            return i ? i : retval;
+        }
+        msgs[i].msg_len = retval;
+    }
+    return n;
+}
+
+#ifndef HAVE_SENDMMSG
+int
+sendmmsg(int fd, struct mmsghdr *msgs, unsigned int n, unsigned int flags)
+{
+    return emulate_sendmmsg(fd, msgs, n, flags);
+}
+#else
+int
+wrap_sendmmsg(int fd, struct mmsghdr *msgs, unsigned int n, unsigned int flags)
+{
+    static bool sendmmsg_broken = false;
+    if (!sendmmsg_broken) {
+        int save_errno = errno;
+        int retval = sendmmsg(fd, msgs, n, flags);
+        if (retval >= 0 || errno != ENOSYS) {
+            return retval;
+        }
+        sendmmsg_broken = true;
+        errno = save_errno;
+    }
+    return emulate_sendmmsg(fd, msgs, n, flags);
+}
+#endif
diff --git a/lib/socket-util.h b/lib/socket-util.h
index 5bf76a40eb84..ef316cb8cc72 100644
--- a/lib/socket-util.h
+++ b/lib/socket-util.h
@@ -87,6 +87,33 @@  int make_unix_socket(int style, bool nonblock,
                      const char *bind_path, const char *connect_path);
 int get_unix_name_len(const struct sockaddr_un *sun, socklen_t sun_len);
 
+/* Universal sendmmsg support.
+ *
+ * Some platforms, such as new enough Linux and FreeBSD, support sendmmsg, but
+ * other platforms (or older ones) do not.  We add the following infrastructure
+ * to allow all code to use sendmmsg, regardless of platform support:
+ *
+ *   - For platforms that lack sendmmsg entirely, we emulate it.
+ *
+ *   - Some platforms have sendmmsg() in the C library but not in the kernel.
+ *     For example, this is true if a Linux system has a newer glibc with an
+ *     old kernel.  To compensate, even if sendmmsg() appears to be available,
+ *     we still wrap it with a handler that uses our emulation if sendmmsg()
+ *     returns ENOSYS.
+ */
+#ifndef HAVE_STRUCT_MMSGHDR_MSG_LEN
+struct mmsghdr {
+    struct msghdr msg_hdr;
+    unsigned int msg_len;
+};
+#endif
+#ifndef HAVE_SENDMMSG
+int sendmmsg(int, struct mmsghdr *, unsigned int, unsigned int);
+#else
+#define sendmmsg wrap_sendmmsg
+int wrap_sendmmsg(int, struct mmsghdr *, unsigned int, unsigned int);
+#endif
+
 /* Helpers for calling ioctl() on an AF_INET socket. */
 struct ifreq;
 int af_inet_ioctl(unsigned long int command, const void *arg);