net: Add a new socket option for a future transmit time.
authorRichard Cochran <rcochran@linutronix.de>
Tue, 3 Jul 2018 22:42:48 +0000 (15:42 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 4 Jul 2018 13:30:27 +0000 (22:30 +0900)
This patch introduces SO_TXTIME. User space enables this option in
order to pass a desired future transmit time in a CMSG when calling
sendmsg(2). The argument to this socket option is a 8-bytes long struct
provided by the uapi header net_tstamp.h defined as:

struct sock_txtime {
clockid_t  clockid;
u32 flags;
};

Note that new fields were added to struct sock by filling a 2-bytes
hole found in the struct. For that reason, neither the struct size or
number of cachelines were altered.

Signed-off-by: Richard Cochran <rcochran@linutronix.de>
Signed-off-by: Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
arch/alpha/include/uapi/asm/socket.h
arch/ia64/include/uapi/asm/socket.h
arch/mips/include/uapi/asm/socket.h
arch/parisc/include/uapi/asm/socket.h
arch/s390/include/uapi/asm/socket.h
arch/sparc/include/uapi/asm/socket.h
arch/xtensa/include/uapi/asm/socket.h
include/net/sock.h
include/uapi/asm-generic/socket.h
include/uapi/linux/net_tstamp.h
net/core/sock.c

index be14f16149d5faf64902441f39ba5c1a08be6104..065fb372e355cf86905fc1be80b97be5ef3218b3 100644 (file)
 
 #define SO_ZEROCOPY            60
 
+#define SO_TXTIME              61
+#define SCM_TXTIME             SO_TXTIME
+
 #endif /* _UAPI_ASM_SOCKET_H */
index 3efba40adc5411ce5981ce611390c084ce7eddf0..c872c4e6bafb64c4334810f73475eb21845481a6 100644 (file)
 
 #define SO_ZEROCOPY            60
 
+#define SO_TXTIME              61
+#define SCM_TXTIME             SO_TXTIME
+
 #endif /* _ASM_IA64_SOCKET_H */
index 49c3d47959637a8653067bc903fbcb8b0bb16e1e..71370fb3ceef4ee4c235876bd1ac7056cff7f1e8 100644 (file)
 
 #define SO_ZEROCOPY            60
 
+#define SO_TXTIME              61
+#define SCM_TXTIME             SO_TXTIME
+
 #endif /* _UAPI_ASM_SOCKET_H */
index 1d0fdc3b5d228279b3863bd581f56fc8ed2cbe9c..061b9cf2a77988a6b82eb47f3d1fd1a53e3264a2 100644 (file)
 
 #define SO_ZEROCOPY            0x4035
 
+#define SO_TXTIME              0x4036
+#define SCM_TXTIME             SO_TXTIME
+
 #endif /* _UAPI_ASM_SOCKET_H */
index 3510c0fd06f4004aeccc4d1e21dded8f5ca8a00a..39d901476ee5d351f1e34a66f0828ca9d9fe522b 100644 (file)
 
 #define SO_ZEROCOPY            60
 
+#define SO_TXTIME              61
+#define SCM_TXTIME             SO_TXTIME
+
 #endif /* _ASM_SOCKET_H */
index d58520c2e6ff2c77788d3546d17c960fd067714f..7ea35e5601b6bed654363456c4127f28beb7cada 100644 (file)
 
 #define SO_ZEROCOPY            0x003e
 
+#define SO_TXTIME              0x003f
+#define SCM_TXTIME             SO_TXTIME
+
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION             0x5001
 #define SO_SECURITY_ENCRYPTION_TRANSPORT       0x5002
index 75a07b8119a96b9eea2258c7d235972552265f46..1de07a7f76806984e504bc03638df7e0610a3455 100644 (file)
 
 #define SO_ZEROCOPY            60
 
+#define SO_TXTIME              61
+#define SCM_TXTIME             SO_TXTIME
+
 #endif /* _XTENSA_SOCKET_H */
index 2ed99bfa45951a4db0c6da8b7291e0ca264a2fec..68347b9821c66dbdc9194ec3a3ec44a95cc979da 100644 (file)
@@ -319,6 +319,9 @@ struct sock_common {
   *    @sk_destruct: called at sock freeing time, i.e. when all refcnt == 0
   *    @sk_reuseport_cb: reuseport group container
   *    @sk_rcu: used during RCU grace period
+  *    @sk_clockid: clockid used by time-based scheduling (SO_TXTIME)
+  *    @sk_txtime_deadline_mode: set deadline mode for SO_TXTIME
+  *    @sk_txtime_unused: unused txtime flags
   */
 struct sock {
        /*
@@ -475,6 +478,11 @@ struct sock {
        u8                      sk_shutdown;
        u32                     sk_tskey;
        atomic_t                sk_zckey;
+
+       u8                      sk_clockid;
+       u8                      sk_txtime_deadline_mode : 1,
+                               sk_txtime_unused : 7;
+
        struct socket           *sk_socket;
        void                    *sk_user_data;
 #ifdef CONFIG_SECURITY
@@ -790,6 +798,7 @@ enum sock_flags {
        SOCK_FILTER_LOCKED, /* Filter cannot be changed anymore */
        SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */
        SOCK_RCU_FREE, /* wait rcu grace period in sk_destruct() */
+       SOCK_TXTIME,
 };
 
 #define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE))
@@ -1585,6 +1594,7 @@ void sock_kzfree_s(struct sock *sk, void *mem, int size);
 void sk_send_sigurg(struct sock *sk);
 
 struct sockcm_cookie {
+       u64 transmit_time;
        u32 mark;
        u16 tsflags;
 };
index 0ae758c90e546b84ff503f8aa1a84809454eccd1..a12692e5f7a8462b22791a09fcb0ef41d0450938 100644 (file)
 
 #define SO_ZEROCOPY            60
 
+#define SO_TXTIME              61
+#define SCM_TXTIME             SO_TXTIME
+
 #endif /* __ASM_GENERIC_SOCKET_H */
index 4fe104b2411f0dcda877b8c83b1c0dcfc4e68c7f..c9a77c353b98b4228217021d399a2813c1059bd6 100644 (file)
@@ -141,4 +141,19 @@ struct scm_ts_pktinfo {
        __u32 reserved[2];
 };
 
+/*
+ * SO_TXTIME gets a struct sock_txtime with flags being an integer bit
+ * field comprised of these values.
+ */
+enum txtime_flags {
+       SOF_TXTIME_DEADLINE_MODE = (1 << 0),
+
+       SOF_TXTIME_FLAGS_MASK = (SOF_TXTIME_DEADLINE_MODE)
+};
+
+struct sock_txtime {
+       clockid_t       clockid;        /* reference clockid */
+       u32             flags;          /* flags defined by enum txtime_flags */
+};
+
 #endif /* _NET_TIMESTAMPING_H */
index 6429982eb9760bc7c3efbc0efcb937c3817ad305..fe64b839f1b2a3337448feaab40cf8ad4f20e9a7 100644 (file)
@@ -91,6 +91,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <asm/unaligned.h>
 #include <linux/capability.h>
 #include <linux/errno.h>
 #include <linux/errqueue.h>
@@ -697,6 +698,7 @@ EXPORT_SYMBOL(sk_mc_loop);
 int sock_setsockopt(struct socket *sock, int level, int optname,
                    char __user *optval, unsigned int optlen)
 {
+       struct sock_txtime sk_txtime;
        struct sock *sk = sock->sk;
        int val;
        int valbool;
@@ -1070,6 +1072,24 @@ set_rcvbuf:
                }
                break;
 
+       case SO_TXTIME:
+               if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) {
+                       ret = -EPERM;
+               } else if (optlen != sizeof(struct sock_txtime)) {
+                       ret = -EINVAL;
+               } else if (copy_from_user(&sk_txtime, optval,
+                          sizeof(struct sock_txtime))) {
+                       ret = -EFAULT;
+               } else if (sk_txtime.flags & ~SOF_TXTIME_FLAGS_MASK) {
+                       ret = -EINVAL;
+               } else {
+                       sock_valbool_flag(sk, SOCK_TXTIME, true);
+                       sk->sk_clockid = sk_txtime.clockid;
+                       sk->sk_txtime_deadline_mode =
+                               !!(sk_txtime.flags & SOF_TXTIME_DEADLINE_MODE);
+               }
+               break;
+
        default:
                ret = -ENOPROTOOPT;
                break;
@@ -1115,6 +1135,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                u64 val64;
                struct linger ling;
                struct timeval tm;
+               struct sock_txtime txtime;
        } v;
 
        int lv = sizeof(int);
@@ -1403,6 +1424,13 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                v.val = sock_flag(sk, SOCK_ZEROCOPY);
                break;
 
+       case SO_TXTIME:
+               lv = sizeof(v.txtime);
+               v.txtime.clockid = sk->sk_clockid;
+               v.txtime.flags |= sk->sk_txtime_deadline_mode ?
+                                 SOF_TXTIME_DEADLINE_MODE : 0;
+               break;
+
        default:
                /* We implement the SO_SNDLOWAT etc to not be settable
                 * (1003.1g 7).
@@ -2137,6 +2165,13 @@ int __sock_cmsg_send(struct sock *sk, struct msghdr *msg, struct cmsghdr *cmsg,
                sockc->tsflags &= ~SOF_TIMESTAMPING_TX_RECORD_MASK;
                sockc->tsflags |= tsflags;
                break;
+       case SCM_TXTIME:
+               if (!sock_flag(sk, SOCK_TXTIME))
+                       return -EINVAL;
+               if (cmsg->cmsg_len != CMSG_LEN(sizeof(u64)))
+                       return -EINVAL;
+               sockc->transmit_time = get_unaligned((u64 *)CMSG_DATA(cmsg));
+               break;
        /* SCM_RIGHTS and SCM_CREDENTIALS are semantically in SOL_UNIX. */
        case SCM_RIGHTS:
        case SCM_CREDENTIALS: