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>
Unified · Split
| @@ -162,6 +162,27 @@ SOF_TIMESTAMPING_OPT_CMSG: · 161 unmodified lines | ||
| 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 |
| @@ -24,8 +24,9 @@ enum { · 23 unmodified lines | ||
| 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 | }; |
| @@ -3710,19 +3710,28 @@ void __skb_tstamp_tx(struct sk_buff *orig_skb, · 3709 unmodified lines | ||
| 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; |
| 3725 | 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(); | |
| 3734 | + | |
| 3726 | 3735 | __skb_complete_tx_timestamp(skb, sk, tstype); |
| 3727 | 3736 | } |
| 3728 | 3737 | EXPORT_SYMBOL_GPL(__skb_tstamp_tx); |
| @@ -483,7 +483,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) · 482 unmodified lines | ||
| 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,8 +496,9 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) · 6 unmodified lines | ||
| 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) |
| @@ -369,7 +369,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) · 368 unmodified lines | ||
| 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,8 +394,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) · 18 unmodified lines | ||
| 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 && |
| @@ -42,6 +42,11 @@ void rxrpc_UDP_error_report(struct sock *sk) · 41 unmodified lines | ||
| 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 | |