aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWillem de Bruijn <willemb@google.com>2015-01-30 13:29:31 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-02 21:46:51 -0500
commit49ca0d8bfaf3bc46d5eef60ce67b00eb195bd392 (patch)
treed2f55a32923f6d91fcb2e0d0e0b6d2d4eb6f9abd
parent9766e97af1b901ffbb36fcc648e50626d926bb24 (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.txt21
-rw-r--r--include/uapi/linux/net_tstamp.h3
-rw-r--r--net/core/skbuff.c19
-rw-r--r--net/ipv4/ip_sockglue.c7
-rw-r--r--net/ipv6/datagram.c5
-rw-r--r--net/rxrpc/ar-error.c5
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
165SOF_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
175New applications are encouraged to pass SOF_TIMESTAMPING_OPT_ID to
176disambiguate timestamps and SOF_TIMESTAMPING_OPT_TSONLY to operate
177regardless of the setting of sysctl net.core.tstamp_allow_data.
178
179An exception is when a process needs additional cmsg data, for
180instance SOL_IP/IP_PKTINFO to detect the egress network interface.
181Then pass option SOF_TIMESTAMPING_OPT_CMSG. This option depends on
182having access to the contents of the original packet, so cannot be
183combined with SOF_TIMESTAMPING_OPT_TSONLY.
184
185
1651.4 Bytestream Timestamps 1861.4 Bytestream Timestamps
166 187
167The SO_TIMESTAMPING interface supports timestamping of bytes in a 188The 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}
3728EXPORT_SYMBOL_GPL(__skb_tstamp_tx); 3737EXPORT_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