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: 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>
This commit is contained in:
parent
c47d8c2f38
commit
80b14dee2b
@ -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 @@
|
|||||||
|
|
||||||
#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 @@
|
|||||||
|
|
||||||
#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 @@
|
|||||||
|
|
||||||
#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 @@
|
|||||||
|
|
||||||
#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 @@
|
|||||||
|
|
||||||
#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 @@
|
|||||||
|
|
||||||
#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 {
|
|||||||
* @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 {
|
|||||||
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 {
|
|||||||
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);
|
|||||||
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 @@
|
|||||||
|
|
||||||
#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 {
|
|||||||
__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 @@
|
|||||||
|
|
||||||
#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);
|
|||||||
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 @@ set_rcvbuf:
|
|||||||
}
|
}
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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:
|
||||||
|
Loading…
Reference in New Issue
Block a user