LDPRELOAD: Add ioctl, fcntl, and setsockopt support 96/8796/2
authorSteven <sluong@cisco.com>
Fri, 13 Oct 2017 00:10:33 +0000 (17:10 -0700)
committerKeith Burns <alagalah@gmail.com>
Fri, 13 Oct 2017 16:46:51 +0000 (16:46 +0000)
Add support for the following system calls:

ioctl (FIONREAD)
fcntl (F_GETFL)
fcntl (F_SETFL)
setsockopt (SOL_IPV6, IPV6_V6ONLY)
setsockopt (SOL_TCP, TCP_NODELAY)
setsockopt (SOL_SOCKET, SO_REUSEADDR)
setsockopt (SOL_SOCKET, SO_BROADCAST)

This patch supersedes https://gerrit.fd.io/r/#/c/8765/

Change-Id: I5d5309d9f43d93a990b389d8cb667631de1903fe
Signed-off-by: Steven <sluong@cisco.com>
extras/vcl-ldpreload/src/libvcl-ldpreload/vcom.c
extras/vcl-ldpreload/src/libvcl-ldpreload/vcom.h
extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.c
extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.h
extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c
extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.h

index 6245c5d..d5b3e12 100644 (file)
@@ -426,6 +426,61 @@ out:
   return rv;
 }
 
+int
+vcom_ioctl_va (int __fd, unsigned long int __cmd, va_list __ap)
+{
+  if (vcom_init () != 0)
+    {
+      return -1;
+    }
+
+  return vcom_socket_ioctl_va (__fd, __cmd, __ap);
+}
+
+int
+vcom_ioctl (int __fd, unsigned long int __cmd, ...)
+{
+  int rv = -1;
+  va_list ap;
+
+  if (is_vcom_socket_fd (__fd))
+    {
+      va_start (ap, __cmd);
+      rv = vcom_ioctl_va (__fd, __cmd, ap);
+      va_end (ap);
+    }
+  return rv;
+}
+
+int
+ioctl (int __fd, unsigned long int __cmd, ...)
+{
+  int rv;
+  va_list ap;
+  pid_t pid = getpid ();
+
+  va_start (ap, __cmd);
+  if (is_vcom_socket_fd (__fd))
+    {
+      rv = vcom_ioctl_va (__fd, __cmd, ap);
+      if (VCOM_DEBUG > 0)
+       fprintf (stderr,
+                "[%d] ioctl: "
+                "'%04d'='%04d', '%04ld'\n", pid, rv, __fd, __cmd);
+      if (rv < 0)
+       {
+         errno = -rv;
+         rv = -1;
+       }
+      goto out;
+    }
+  rv = libc_vioctl (__fd, __cmd, ap);
+
+out:
+  va_end (ap);
+  return rv;
+}
+
 /*
  * Check the first NFDS descriptors each in READFDS (if not NULL) for
  *  read readiness, in WRITEFDS (if not NULL) for write readiness,
index f6ee8a2..bedeef8 100644 (file)
@@ -55,6 +55,11 @@ extern ssize_t __wur vcom_writev (int __fd, const struct iovec *__iov,
  */
 extern int vcom_fcntl (int __fd, int __cmd, ...);
 
+/*
+ * VPP implementation of glibc APIs ioctl
+ */
+extern int vcom_ioctl (int __fd, unsigned long int __cmd, ...);
+
 /*
  * vpp implementation of glibc APIs from <sys/select.h>
  */
index 86b923c..5378548 100644 (file)
@@ -18,6 +18,7 @@
 #include <limits.h>
 #define __need_IOV_MAX
 #include <bits/stdio_lim.h>
+#include <netinet/tcp.h>
 
 #include <vppinfra/types.h>
 #include <vppinfra/hash.h>
@@ -653,8 +654,6 @@ vcom_socket_check_fcntl_cmd (int __cmd)
       /* Fallthrough */
     case F_GETFD:
     case F_SETFD:
-    case F_GETFL:
-    case F_SETFL:
     case F_GETLK:
     case F_SETLK:
     case F_SETLKW:
@@ -662,25 +661,36 @@ vcom_socket_check_fcntl_cmd (int __cmd)
     case F_SETOWN:
       return 2;
 
-#if 0
-      /* cmd handled by vppcom */
-    case F_XXXXX:
+      /* cmd handled by vcom and vppcom */
+    case F_SETFL:
+    case F_GETFL:
       return 3;
-#endif
-      /* invalid cmd */
+
+      /* cmd not handled by vcom and vppcom */
     default:
-      return 0;
+      return 1;
     }
   return 0;
 }
 
-/* TBD: move it to vppcom */
 static int
-vppcom_session_fcntl_va (int __fd, int __cmd, va_list __ap)
+vppcom_session_fcntl_va (int __sid, int __cmd, va_list __ap)
 {
-  int rv;
+  int flags = va_arg (__ap, int);
+  int rv = -EOPNOTSUPP;
+  uint32_t size;
 
-  rv = -EINVAL;
+  size = sizeof (flags);
+  if (__cmd == F_SETFL)
+    {
+      rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_FLAGS, &flags, &size);
+    }
+  else if (__cmd == F_GETFL)
+    {
+      rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_FLAGS, &flags, &size);
+      if (rv == VPPCOM_OK)
+       rv = flags;
+    }
 
   return rv;
 }
@@ -712,7 +722,7 @@ vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
       break;
       /*cmd not handled by vcom and vppcom */
     case 1:
-      rv = -EBADF;
+      rv = libc_vfcntl (vsock->fd, __cmd, __ap);
       break;
       /* cmd handled by vcom socket resource */
     case 2:
@@ -731,6 +741,93 @@ vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap)
   return rv;
 }
 
+/*
+ * RETURN:  0 - invalid cmd
+ *          1 - cmd not handled by vcom and vppcom
+ *          2 - cmd handled by vcom socket resource
+ *          3 - cmd handled by vppcom
+ */
+static int
+vcom_socket_check_ioctl_cmd (unsigned long int __cmd)
+{
+  int rc;
+
+  switch (__cmd)
+    {
+      /* cmd handled by vppcom */
+    case FIONREAD:
+      rc = 3;
+      break;
+
+      /* cmd not handled by vcom and vppcom */
+    default:
+      rc = 1;
+      break;
+    }
+  return rc;
+}
+
+static int
+vppcom_session_ioctl_va (int __sid, int __cmd, va_list __ap)
+{
+  int rv;
+
+  if (__cmd == FIONREAD)
+    rv = vppcom_session_attr (__sid, VPPCOM_ATTR_GET_NREAD, 0, 0);
+  else
+    rv = -EOPNOTSUPP;
+  return rv;
+}
+
+int
+vcom_socket_ioctl_va (int __fd, unsigned long int __cmd, va_list __ap)
+{
+  int rv = -EBADF;
+  vcom_socket_main_t *vsm = &vcom_socket_main;
+  uword *p;
+  vcom_socket_t *vsock;
+
+  p = hash_get (vsm->sockidx_by_fd, __fd);
+  if (!p)
+    return -EBADF;
+
+  vsock = pool_elt_at_index (vsm->vsockets, p[0]);
+  if (!vsock)
+    return -ENOTSOCK;
+
+  if (vsock->type != SOCKET_TYPE_VPPCOM_BOUND)
+    return -EINVAL;
+
+  switch (vcom_socket_check_ioctl_cmd (__cmd))
+    {
+      /* Not supported cmd */
+    case 0:
+      rv = -EOPNOTSUPP;
+      break;
+
+      /* cmd not handled by vcom and vppcom */
+    case 1:
+      rv = libc_vioctl (vsock->fd, __cmd, __ap);
+      break;
+
+      /* cmd handled by vcom socket resource */
+    case 2:
+      rv = libc_vioctl (vsock->fd, __cmd, __ap);
+      break;
+
+      /* cmd handled by vppcom */
+    case 3:
+      rv = vppcom_session_ioctl_va (vsock->sid, __cmd, __ap);
+      break;
+
+    default:
+      rv = -EINVAL;
+      break;
+    }
+
+  return rv;
+}
+
 static inline int
 vcom_socket_fds_2_sid_fds (
                            /* dest */
@@ -1809,17 +1906,41 @@ vcom_socket_getsockopt (int __fd, int __level, int __optname,
 
 /* TBD: move it to vppcom */
 int
-vppcom_setsockopt (int __fd, int __level, int __optname,
-                  const void *__optval, socklen_t __optlen)
+vppcom_session_setsockopt (int __sid, int __level, int __optname,
+                          const void *__optval, socklen_t __optlen)
 {
-  /* 1. for socket level options that are NOT socket attributes
-   *    and that has corresponding vpp options set it from vppcom */
-#if 0
-  return 0;
-#endif
+  int rv = -EOPNOTSUPP;
 
-  /* 2. unhandled options */
-  return -ENOPROTOOPT;
+  switch (__level)
+    {
+    case SOL_IPV6:
+      switch (__optname)
+       {
+       case IPV6_V6ONLY:
+         rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_V6ONLY, 0, 0);
+         return rv;
+       default:
+         return rv;
+       }
+      break;
+    case SOL_SOCKET:
+      switch (__optname)
+       {
+       case SO_REUSEADDR:
+         rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_REUSEADDR, 0, 0);
+         return rv;
+       case SO_BROADCAST:
+         rv = vppcom_session_attr (__sid, VPPCOM_ATTR_SET_BROADCAST, 0, 0);
+         return rv;
+       default:
+         return rv;
+       }
+      break;
+    default:
+      return rv;
+    }
+
+  return rv;
 }
 
 int
@@ -1864,10 +1985,36 @@ vcom_socket_setsockopt (int __fd, int __level, int __optname,
 
   switch (__level)
     {
+    case SOL_IPV6:
+      switch (__optname)
+       {
+       case IPV6_V6ONLY:
+         rv = vppcom_session_setsockopt (vsock->sid, __level, __optname,
+                                         __optval, __optlen);
+         return rv;
+       default:
+         return -EOPNOTSUPP;
+       }
+      break;
+    case SOL_TCP:
+      switch (__optname)
+       {
+       case TCP_NODELAY:
+         return 0;
+       default:
+         return -EOPNOTSUPP;
+       }
+      break;
       /* handle options at socket level */
     case SOL_SOCKET:
       switch (__optname)
        {
+       case SO_REUSEADDR:
+       case SO_BROADCAST:
+         rv = vppcom_session_setsockopt (vsock->sid, __level, __optname,
+                                         __optval, __optlen);
+         return rv;
+
          /*
           * 1. for socket level options that are socket attributes,
           *    set it from libc_getsockopt
@@ -1878,10 +2025,8 @@ vcom_socket_setsockopt (int __fd, int __level, int __optname,
           *    return -ENOPROTOOPT */
        case SO_DEBUG:
        case SO_DONTROUTE:
-       case SO_BROADCAST:
        case SO_SNDBUF:
        case SO_RCVBUF:
-       case SO_REUSEADDR:
        case SO_REUSEPORT:
        case SO_KEEPALIVE:
        case SO_TYPE:
@@ -1942,15 +2087,7 @@ vcom_socket_setsockopt (int __fd, int __level, int __optname,
       break;
 
     default:
-      /* 1. handle options that are NOT socket level options,
-       *    but have corresponding vpp otions. */
-      rv = vppcom_setsockopt (vsock->sid, __level, __optname,
-                             __optval, __optlen);
-      return rv;
-#if 0
-      /* 2. unhandled options */
       return -ENOPROTOOPT;
-#endif
     }
 
   return rv;
index 7170e20..ef57646 100644 (file)
@@ -347,6 +347,8 @@ ssize_t vcom_socket_writev (int __fd, const struct iovec *__iov,
 
 int vcom_socket_fcntl_va (int __fd, int __cmd, va_list __ap);
 
+int vcom_socket_ioctl_va (int __fd, unsigned long int __cmd, va_list __ap);
+
 int
 vcom_socket_select (int vcom_nfds, fd_set * __restrict vcom_readfds,
                    fd_set * __restrict vcom_writefds,
index 74a0dcf..087cd6b 100644 (file)
@@ -555,6 +555,27 @@ libc_vfcntl (int fd, int cmd, va_list ap)
   return rc;
 }
 
+DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE int
+libc_vioctl (int fd, int cmd, va_list ap)
+{
+  long int args[4];
+  int rc;
+  int i;
+
+  swrap_bind_symbol_libc (ioctl);
+
+  for (i = 0; i < 4; i++)
+    {
+      args[i] = va_arg (ap, long int);
+    }
+
+  rc = swrap.libc.symbols._libc_ioctl.f (fd,
+                                        cmd,
+                                        args[0], args[1], args[2], args[3]);
+
+  return rc;
+}
+
 int
 libc_getpeername (int sockfd, struct sockaddr *addr, socklen_t * addrlen)
 {
index ef3ece0..49ee7ee 100644 (file)
@@ -131,6 +131,9 @@ int libc_eventfd (int count, int flags);
 DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE int
 libc_vfcntl (int fd, int cmd, va_list ap);
 
+DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE int
+libc_vioctl (int fd, int cmd, va_list ap);
+
 int libc_getpeername (int sockfd, struct sockaddr *addr, socklen_t * addrlen);
 
 int libc_getsockname (int sockfd, struct sockaddr *addr, socklen_t * addrlen);