diff options
author | Willem de Bruijn <willemb@google.com> | 2015-01-30 13:29:31 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-02-02 21:46:51 -0500 |
commit | 49ca0d8bfaf3bc46d5eef60ce67b00eb195bd392 (patch) | |
tree | d2f55a32923f6d91fcb2e0d0e0b6d2d4eb6f9abd | |
parent | 9766e97af1b901ffbb36fcc648e50626d926bb24 (diff) |
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>
-rw-r--r-- | Documentation/networking/timestamping.txt | 21 | ||||
-rw-r--r-- | include/uapi/linux/net_tstamp.h | 3 | ||||
-rw-r--r-- | net/core/skbuff.c | 19 | ||||
-rw-r--r-- | net/ipv4/ip_sockglue.c | 7 | ||||
-rw-r--r-- | net/ipv6/datagram.c | 5 | ||||
-rw-r--r-- | net/rxrpc/ar-error.c | 5 |
6 files changed, 48 insertions, 12 deletions
diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt index a5c784c89312..5f0922613f1a 100644 --- a/Documentation/networking/timestamping.txt +++ b/Documentation/networking/timestamping.txt | |||
@@ -162,6 +162,27 @@ SOF_TIMESTAMPING_OPT_CMSG: | |||
162 | option IP_PKTINFO simultaneously. | 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 | 1.4 Bytestream Timestamps | 186 | 1.4 Bytestream Timestamps |
166 | 187 | ||
167 | The SO_TIMESTAMPING interface supports timestamping of bytes in a | 188 | The SO_TIMESTAMPING interface supports timestamping of bytes in a |
diff --git a/include/uapi/linux/net_tstamp.h b/include/uapi/linux/net_tstamp.h index edbc888ceb51..6d1abea9746e 100644 --- a/include/uapi/linux/net_tstamp.h +++ b/include/uapi/linux/net_tstamp.h | |||
@@ -24,8 +24,9 @@ enum { | |||
24 | SOF_TIMESTAMPING_TX_SCHED = (1<<8), | 24 | SOF_TIMESTAMPING_TX_SCHED = (1<<8), |
25 | SOF_TIMESTAMPING_TX_ACK = (1<<9), | 25 | SOF_TIMESTAMPING_TX_ACK = (1<<9), |
26 | SOF_TIMESTAMPING_OPT_CMSG = (1<<10), | 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 | SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | | 30 | SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | |
30 | SOF_TIMESTAMPING_LAST | 31 | SOF_TIMESTAMPING_LAST |
31 | }; | 32 | }; |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 56db472e9b86..65a3798f43e6 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -3710,19 +3710,28 @@ void __skb_tstamp_tx(struct sk_buff *orig_skb, | |||
3710 | struct sock *sk, int tstype) | 3710 | struct sock *sk, int tstype) |
3711 | { | 3711 | { |
3712 | struct sk_buff *skb; | 3712 | struct sk_buff *skb; |
3713 | bool tsonly = sk->sk_tsflags & SOF_TIMESTAMPING_OPT_TSONLY; | ||
3713 | 3714 | ||
3714 | if (!sk) | 3715 | if (!sk) |
3715 | return; | 3716 | return; |
3716 | 3717 | ||
3717 | if (hwtstamps) | 3718 | if (tsonly) |
3718 | *skb_hwtstamps(orig_skb) = *hwtstamps; | 3719 | skb = alloc_skb(0, GFP_ATOMIC); |
3719 | else | 3720 | else |
3720 | orig_skb->tstamp = ktime_get_real(); | 3721 | skb = skb_clone(orig_skb, GFP_ATOMIC); |
3721 | |||
3722 | skb = skb_clone(orig_skb, GFP_ATOMIC); | ||
3723 | if (!skb) | 3722 | if (!skb) |
3724 | return; | 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 | __skb_complete_tx_timestamp(skb, sk, tstype); | 3735 | __skb_complete_tx_timestamp(skb, sk, tstype); |
3727 | } | 3736 | } |
3728 | EXPORT_SYMBOL_GPL(__skb_tstamp_tx); | 3737 | EXPORT_SYMBOL_GPL(__skb_tstamp_tx); |
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index db5e0f81ce0a..31d8c71986b4 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c | |||
@@ -483,7 +483,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
483 | 483 | ||
484 | serr = SKB_EXT_ERR(skb); | 484 | serr = SKB_EXT_ERR(skb); |
485 | 485 | ||
486 | if (sin) { | 486 | if (sin && skb->len) { |
487 | sin->sin_family = AF_INET; | 487 | sin->sin_family = AF_INET; |
488 | sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) + | 488 | sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) + |
489 | serr->addr_offset); | 489 | serr->addr_offset); |
@@ -496,8 +496,9 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
496 | sin = &errhdr.offender; | 496 | sin = &errhdr.offender; |
497 | memset(sin, 0, sizeof(*sin)); | 497 | memset(sin, 0, sizeof(*sin)); |
498 | 498 | ||
499 | if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP || | 499 | if (skb->len && |
500 | ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin)) { | 500 | (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP || |
501 | ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin))) { | ||
501 | sin->sin_family = AF_INET; | 502 | sin->sin_family = AF_INET; |
502 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; | 503 | sin->sin_addr.s_addr = ip_hdr(skb)->saddr; |
503 | if (inet_sk(sk)->cmsg_flags) | 504 | if (inet_sk(sk)->cmsg_flags) |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 49f5e73db122..c215be70cac0 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -369,7 +369,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
369 | 369 | ||
370 | serr = SKB_EXT_ERR(skb); | 370 | serr = SKB_EXT_ERR(skb); |
371 | 371 | ||
372 | if (sin) { | 372 | if (sin && skb->len) { |
373 | const unsigned char *nh = skb_network_header(skb); | 373 | const unsigned char *nh = skb_network_header(skb); |
374 | sin->sin6_family = AF_INET6; | 374 | sin->sin6_family = AF_INET6; |
375 | sin->sin6_flowinfo = 0; | 375 | sin->sin6_flowinfo = 0; |
@@ -394,8 +394,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | |||
394 | memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); | 394 | memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); |
395 | sin = &errhdr.offender; | 395 | sin = &errhdr.offender; |
396 | memset(sin, 0, sizeof(*sin)); | 396 | memset(sin, 0, sizeof(*sin)); |
397 | 397 | if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL && skb->len) { | |
398 | if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) { | ||
399 | sin->sin6_family = AF_INET6; | 398 | sin->sin6_family = AF_INET6; |
400 | if (np->rxopt.all) { | 399 | if (np->rxopt.all) { |
401 | if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP && | 400 | if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP && |
diff --git a/net/rxrpc/ar-error.c b/net/rxrpc/ar-error.c index 74c0fcd36838..5394b6be46ec 100644 --- a/net/rxrpc/ar-error.c +++ b/net/rxrpc/ar-error.c | |||
@@ -42,6 +42,11 @@ void rxrpc_UDP_error_report(struct sock *sk) | |||
42 | _leave("UDP socket errqueue empty"); | 42 | _leave("UDP socket errqueue empty"); |
43 | return; | 43 | return; |
44 | } | 44 | } |
45 | if (!skb->len) { | ||
46 | _leave("UDP empty message"); | ||
47 | kfree_skb(skb); | ||
48 | return; | ||
49 | } | ||
45 | 50 | ||
46 | rxrpc_new_skb(skb); | 51 | rxrpc_new_skb(skb); |
47 | 52 | ||