[ovs-dev] [PATCH] socket-util: Support sendmmsg() on Linux and non-Linux platforms.

Ben Pfaff blp at ovn.org
Wed Jul 12 16:23:40 UTC 2017


This will have its first user in an upcoming commit.

Signed-off-by: Ben Pfaff <blp at ovn.org>
---
 configure.ac                |  3 ++-
 include/sparse/sys/socket.h |  5 +++++
 lib/socket-util.c           | 38 ++++++++++++++++++++++++++++++++++++++
 lib/socket-util.h           | 25 +++++++++++++++++++++++++
 4 files changed, 70 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..0927ac9ac6c4 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++) {
+        int 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..0041345b0ba2 100644
--- a/lib/socket-util.h
+++ b/lib/socket-util.h
@@ -87,6 +87,31 @@ 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);
 
+/* sendmmsg support.
+ *
+ * We add the following infrastructure to allow all code to use sendmmsg()
+ * without caring what platform it runs on:
+ *
+ *   - Non-Linux platforms do not have sendmmsg.  For these, we emulate it.
+ *
+ *   - Linux platforms might have sendmmsg in their C library but not in the
+ *     kernel, which means that it will always return ENOSYS.  To compensate,
+ *     we wrap sendmmsg() 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



More information about the dev mailing list