Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net-timestamp: no-payload option

Add timestamping option SOF_TIMESTAMPING_OPT_TSONLY. For transmit
timestamps, this loops timestamps on top of empty packets.

Doing so reduces the pressure on SO_RCVBUF. Payload inspection and
cmsg reception (aside from timestamps) are no longer possible. This
works together with a follow on patch that allows administrators to
only allow tx timestamping if it does not loop payload or metadata.

Signed-off-by: Willem de Bruijn <willemb@google.com>

----

Changes (rfc -> v1)
- add documentation
- remove unnecessary skb->len test (thanks to Richard Cochran)
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Willem de Bruijn and committed by
David S. Miller
49ca0d8b 9766e97a

+48 -12
+21
Documentation/networking/timestamping.txt
··· 162 162 option IP_PKTINFO simultaneously. 163 163 164 164 165 + SOF_TIMESTAMPING_OPT_TSONLY: 166 + 167 + Applies to transmit timestamps only. Makes the kernel return the 168 + timestamp as a cmsg alongside an empty packet, as opposed to 169 + alongside the original packet. This reduces the amount of memory 170 + charged to the socket's receive budget (SO_RCVBUF) and delivers 171 + the timestamp even if sysctl net.core.tstamp_allow_data is 0. 172 + This option disables SOF_TIMESTAMPING_OPT_CMSG. 173 + 174 + 175 + New applications are encouraged to pass SOF_TIMESTAMPING_OPT_ID to 176 + disambiguate timestamps and SOF_TIMESTAMPING_OPT_TSONLY to operate 177 + regardless of the setting of sysctl net.core.tstamp_allow_data. 178 + 179 + An exception is when a process needs additional cmsg data, for 180 + instance SOL_IP/IP_PKTINFO to detect the egress network interface. 181 + Then pass option SOF_TIMESTAMPING_OPT_CMSG. This option depends on 182 + having access to the contents of the original packet, so cannot be 183 + combined with SOF_TIMESTAMPING_OPT_TSONLY. 184 + 185 + 165 186 1.4 Bytestream Timestamps 166 187 167 188 The SO_TIMESTAMPING interface supports timestamping of bytes in a
+2 -1
include/uapi/linux/net_tstamp.h
··· 24 24 SOF_TIMESTAMPING_TX_SCHED = (1<<8), 25 25 SOF_TIMESTAMPING_TX_ACK = (1<<9), 26 26 SOF_TIMESTAMPING_OPT_CMSG = (1<<10), 27 + SOF_TIMESTAMPING_OPT_TSONLY = (1<<11), 27 28 28 - SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_CMSG, 29 + SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_TSONLY, 29 30 SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | 30 31 SOF_TIMESTAMPING_LAST 31 32 };
+14 -5
net/core/skbuff.c
··· 3710 3710 struct sock *sk, int tstype) 3711 3711 { 3712 3712 struct sk_buff *skb; 3713 + bool tsonly = sk->sk_tsflags & SOF_TIMESTAMPING_OPT_TSONLY; 3713 3714 3714 3715 if (!sk) 3715 3716 return; 3716 3717 3717 - if (hwtstamps) 3718 - *skb_hwtstamps(orig_skb) = *hwtstamps; 3718 + if (tsonly) 3719 + skb = alloc_skb(0, GFP_ATOMIC); 3719 3720 else 3720 - orig_skb->tstamp = ktime_get_real(); 3721 - 3722 - skb = skb_clone(orig_skb, GFP_ATOMIC); 3721 + skb = skb_clone(orig_skb, GFP_ATOMIC); 3723 3722 if (!skb) 3724 3723 return; 3724 + 3725 + if (tsonly) { 3726 + skb_shinfo(skb)->tx_flags = skb_shinfo(orig_skb)->tx_flags; 3727 + skb_shinfo(skb)->tskey = skb_shinfo(orig_skb)->tskey; 3728 + } 3729 + 3730 + if (hwtstamps) 3731 + *skb_hwtstamps(skb) = *hwtstamps; 3732 + else 3733 + skb->tstamp = ktime_get_real(); 3725 3734 3726 3735 __skb_complete_tx_timestamp(skb, sk, tstype); 3727 3736 }
+4 -3
net/ipv4/ip_sockglue.c
··· 483 483 484 484 serr = SKB_EXT_ERR(skb); 485 485 486 - if (sin) { 486 + if (sin && skb->len) { 487 487 sin->sin_family = AF_INET; 488 488 sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) + 489 489 serr->addr_offset); ··· 496 496 sin = &errhdr.offender; 497 497 memset(sin, 0, sizeof(*sin)); 498 498 499 - if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP || 500 - ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin)) { 499 + if (skb->len && 500 + (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP || 501 + ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin))) { 501 502 sin->sin_family = AF_INET; 502 503 sin->sin_addr.s_addr = ip_hdr(skb)->saddr; 503 504 if (inet_sk(sk)->cmsg_flags)
+2 -3
net/ipv6/datagram.c
··· 369 369 370 370 serr = SKB_EXT_ERR(skb); 371 371 372 - if (sin) { 372 + if (sin && skb->len) { 373 373 const unsigned char *nh = skb_network_header(skb); 374 374 sin->sin6_family = AF_INET6; 375 375 sin->sin6_flowinfo = 0; ··· 394 394 memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); 395 395 sin = &errhdr.offender; 396 396 memset(sin, 0, sizeof(*sin)); 397 - 398 - if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) { 397 + if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL && skb->len) { 399 398 sin->sin6_family = AF_INET6; 400 399 if (np->rxopt.all) { 401 400 if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP &&
+5
net/rxrpc/ar-error.c
··· 42 42 _leave("UDP socket errqueue empty"); 43 43 return; 44 44 } 45 + if (!skb->len) { 46 + _leave("UDP empty message"); 47 + kfree_skb(skb); 48 + return; 49 + } 45 50 46 51 rxrpc_new_skb(skb); 47 52