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_TXTIME		61 | ||||
| #define SCM_TXTIME		SO_TXTIME | ||||
| 
 | ||||
| #endif /* _UAPI_ASM_SOCKET_H */ | ||||
|  | ||||
| @ -114,4 +114,7 @@ | ||||
| 
 | ||||
| #define SO_ZEROCOPY		60 | ||||
| 
 | ||||
| #define SO_TXTIME		61 | ||||
| #define SCM_TXTIME		SO_TXTIME | ||||
| 
 | ||||
| #endif /* _ASM_IA64_SOCKET_H */ | ||||
|  | ||||
| @ -123,4 +123,7 @@ | ||||
| 
 | ||||
| #define SO_ZEROCOPY		60 | ||||
| 
 | ||||
| #define SO_TXTIME		61 | ||||
| #define SCM_TXTIME		SO_TXTIME | ||||
| 
 | ||||
| #endif /* _UAPI_ASM_SOCKET_H */ | ||||
|  | ||||
| @ -104,4 +104,7 @@ | ||||
| 
 | ||||
| #define SO_ZEROCOPY		0x4035 | ||||
| 
 | ||||
| #define SO_TXTIME		0x4036 | ||||
| #define SCM_TXTIME		SO_TXTIME | ||||
| 
 | ||||
| #endif /* _UAPI_ASM_SOCKET_H */ | ||||
|  | ||||
| @ -111,4 +111,7 @@ | ||||
| 
 | ||||
| #define SO_ZEROCOPY		60 | ||||
| 
 | ||||
| #define SO_TXTIME		61 | ||||
| #define SCM_TXTIME		SO_TXTIME | ||||
| 
 | ||||
| #endif /* _ASM_SOCKET_H */ | ||||
|  | ||||
| @ -101,6 +101,9 @@ | ||||
| 
 | ||||
| #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 | ||||
|  | ||||
| @ -116,4 +116,7 @@ | ||||
| 
 | ||||
| #define SO_ZEROCOPY		60 | ||||
| 
 | ||||
| #define SO_TXTIME		61 | ||||
| #define SCM_TXTIME		SO_TXTIME | ||||
| 
 | ||||
| #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_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; | ||||
| }; | ||||
|  | ||||
| @ -107,4 +107,7 @@ | ||||
| 
 | ||||
| #define SO_ZEROCOPY		60 | ||||
| 
 | ||||
| #define SO_TXTIME		61 | ||||
| #define SCM_TXTIME		SO_TXTIME | ||||
| 
 | ||||
| #endif /* __ASM_GENERIC_SOCKET_H */ | ||||
|  | ||||
| @ -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 */ | ||||
|  | ||||
| @ -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: | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user