Commit 80b14dee authored by Richard Cochran's avatar Richard Cochran Committed by David S. Miller

net: Add a new socket option for a future transmit time.

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: default avatarRichard Cochran <rcochran@linutronix.de>
Signed-off-by: default avatarJesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c47d8c2f
...@@ -112,4 +112,7 @@ ...@@ -112,4 +112,7 @@
#define SO_ZEROCOPY 60 #define SO_ZEROCOPY 60
#define SO_TXTIME 61
#define SCM_TXTIME SO_TXTIME
#endif /* _UAPI_ASM_SOCKET_H */ #endif /* _UAPI_ASM_SOCKET_H */
...@@ -114,4 +114,7 @@ ...@@ -114,4 +114,7 @@
#define SO_ZEROCOPY 60 #define SO_ZEROCOPY 60
#define SO_TXTIME 61
#define SCM_TXTIME SO_TXTIME
#endif /* _ASM_IA64_SOCKET_H */ #endif /* _ASM_IA64_SOCKET_H */
...@@ -123,4 +123,7 @@ ...@@ -123,4 +123,7 @@
#define SO_ZEROCOPY 60 #define SO_ZEROCOPY 60
#define SO_TXTIME 61
#define SCM_TXTIME SO_TXTIME
#endif /* _UAPI_ASM_SOCKET_H */ #endif /* _UAPI_ASM_SOCKET_H */
...@@ -104,4 +104,7 @@ ...@@ -104,4 +104,7 @@
#define SO_ZEROCOPY 0x4035 #define SO_ZEROCOPY 0x4035
#define SO_TXTIME 0x4036
#define SCM_TXTIME SO_TXTIME
#endif /* _UAPI_ASM_SOCKET_H */ #endif /* _UAPI_ASM_SOCKET_H */
...@@ -111,4 +111,7 @@ ...@@ -111,4 +111,7 @@
#define SO_ZEROCOPY 60 #define SO_ZEROCOPY 60
#define SO_TXTIME 61
#define SCM_TXTIME SO_TXTIME
#endif /* _ASM_SOCKET_H */ #endif /* _ASM_SOCKET_H */
...@@ -101,6 +101,9 @@ ...@@ -101,6 +101,9 @@
#define SO_ZEROCOPY 0x003e #define SO_ZEROCOPY 0x003e
#define SO_TXTIME 0x003f
#define SCM_TXTIME SO_TXTIME
/* Security levels - as per NRL IPv6 - don't actually do anything */ /* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001 #define SO_SECURITY_AUTHENTICATION 0x5001
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 #define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
......
...@@ -116,4 +116,7 @@ ...@@ -116,4 +116,7 @@
#define SO_ZEROCOPY 60 #define SO_ZEROCOPY 60
#define SO_TXTIME 61
#define SCM_TXTIME SO_TXTIME
#endif /* _XTENSA_SOCKET_H */ #endif /* _XTENSA_SOCKET_H */
...@@ -319,6 +319,9 @@ struct sock_common { ...@@ -319,6 +319,9 @@ struct sock_common {
* @sk_destruct: called at sock freeing time, i.e. when all refcnt == 0 * @sk_destruct: called at sock freeing time, i.e. when all refcnt == 0
* @sk_reuseport_cb: reuseport group container * @sk_reuseport_cb: reuseport group container
* @sk_rcu: used during RCU grace period * @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 { struct sock {
/* /*
...@@ -475,6 +478,11 @@ struct sock { ...@@ -475,6 +478,11 @@ struct sock {
u8 sk_shutdown; u8 sk_shutdown;
u32 sk_tskey; u32 sk_tskey;
atomic_t sk_zckey; atomic_t sk_zckey;
u8 sk_clockid;
u8 sk_txtime_deadline_mode : 1,
sk_txtime_unused : 7;
struct socket *sk_socket; struct socket *sk_socket;
void *sk_user_data; void *sk_user_data;
#ifdef CONFIG_SECURITY #ifdef CONFIG_SECURITY
...@@ -790,6 +798,7 @@ enum sock_flags { ...@@ -790,6 +798,7 @@ enum sock_flags {
SOCK_FILTER_LOCKED, /* Filter cannot be changed anymore */ SOCK_FILTER_LOCKED, /* Filter cannot be changed anymore */
SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */ SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */
SOCK_RCU_FREE, /* wait rcu grace period in sk_destruct() */ SOCK_RCU_FREE, /* wait rcu grace period in sk_destruct() */
SOCK_TXTIME,
}; };
#define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) #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); ...@@ -1585,6 +1594,7 @@ void sock_kzfree_s(struct sock *sk, void *mem, int size);
void sk_send_sigurg(struct sock *sk); void sk_send_sigurg(struct sock *sk);
struct sockcm_cookie { struct sockcm_cookie {
u64 transmit_time;
u32 mark; u32 mark;
u16 tsflags; u16 tsflags;
}; };
......
...@@ -107,4 +107,7 @@ ...@@ -107,4 +107,7 @@
#define SO_ZEROCOPY 60 #define SO_ZEROCOPY 60
#define SO_TXTIME 61
#define SCM_TXTIME SO_TXTIME
#endif /* __ASM_GENERIC_SOCKET_H */ #endif /* __ASM_GENERIC_SOCKET_H */
...@@ -141,4 +141,19 @@ struct scm_ts_pktinfo { ...@@ -141,4 +141,19 @@ struct scm_ts_pktinfo {
__u32 reserved[2]; __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 */ #endif /* _NET_TIMESTAMPING_H */
...@@ -91,6 +91,7 @@ ...@@ -91,6 +91,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <asm/unaligned.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/errqueue.h> #include <linux/errqueue.h>
...@@ -697,6 +698,7 @@ EXPORT_SYMBOL(sk_mc_loop); ...@@ -697,6 +698,7 @@ EXPORT_SYMBOL(sk_mc_loop);
int sock_setsockopt(struct socket *sock, int level, int optname, int sock_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, unsigned int optlen) char __user *optval, unsigned int optlen)
{ {
struct sock_txtime sk_txtime;
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int val; int val;
int valbool; int valbool;
...@@ -1070,6 +1072,24 @@ int sock_setsockopt(struct socket *sock, int level, int optname, ...@@ -1070,6 +1072,24 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
} }
break; 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: default:
ret = -ENOPROTOOPT; ret = -ENOPROTOOPT;
break; break;
...@@ -1115,6 +1135,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname, ...@@ -1115,6 +1135,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
u64 val64; u64 val64;
struct linger ling; struct linger ling;
struct timeval tm; struct timeval tm;
struct sock_txtime txtime;
} v; } v;
int lv = sizeof(int); int lv = sizeof(int);
...@@ -1403,6 +1424,13 @@ int sock_getsockopt(struct socket *sock, int level, int optname, ...@@ -1403,6 +1424,13 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
v.val = sock_flag(sk, SOCK_ZEROCOPY); v.val = sock_flag(sk, SOCK_ZEROCOPY);
break; 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: default:
/* We implement the SO_SNDLOWAT etc to not be settable /* We implement the SO_SNDLOWAT etc to not be settable
* (1003.1g 7). * (1003.1g 7).
...@@ -2137,6 +2165,13 @@ int __sock_cmsg_send(struct sock *sk, struct msghdr *msg, struct cmsghdr *cmsg, ...@@ -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 &= ~SOF_TIMESTAMPING_TX_RECORD_MASK;
sockc->tsflags |= tsflags; sockc->tsflags |= tsflags;
break; 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. */ /* SCM_RIGHTS and SCM_CREDENTIALS are semantically in SOL_UNIX. */
case SCM_RIGHTS: case SCM_RIGHTS:
case SCM_CREDENTIALS: case SCM_CREDENTIALS:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment