aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWillem de Bruijn <willemb@google.com>2014-08-04 22:11:47 -0400
committerDavid S. Miller <davem@davemloft.net>2014-08-05 19:35:54 -0400
commit09c2d251b70723650ba47e83571ff49281320f7c (patch)
treeb40d8ab4ed6533a357b885ca6184ab7e86537c22
parentb9f40e21ef4298650ab33e35740fa85bd57706d5 (diff)
net-timestamp: add key to disambiguate concurrent datagrams
Datagrams timestamped on transmission can coexist in the kernel stack and be reordered in packet scheduling. When reading looped datagrams from the socket error queue it is not always possible to unique correlate looped data with original send() call (for application level retransmits). Even if possible, it may be expensive and complex, requiring packet inspection. Introduce a data-independent ID mechanism to associate timestamps with send calls. Pass an ID alongside the timestamp in field ee_data of sock_extended_err. The ID is a simple 32 bit unsigned int that is associated with the socket and incremented on each send() call for which software tx timestamp generation is enabled. The feature is enabled only if SOF_TIMESTAMPING_OPT_ID is set, to avoid changing ee_data for existing applications that expect it 0. The counter is reset each time the flag is reenabled. Reenabling does not change the ID of already submitted data. It is possible to receive out of order IDs if the timestamp stream is not quiesced first. Signed-off-by: Willem de Bruijn <willemb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/skbuff.h1
-rw-r--r--include/net/sock.h2
-rw-r--r--include/uapi/linux/net_tstamp.h8
-rw-r--r--net/core/skbuff.c2
-rw-r--r--net/core/sock.c3
-rw-r--r--net/ipv4/ip_output.c6
-rw-r--r--net/ipv6/ip6_output.c9
7 files changed, 27 insertions, 4 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 477f0f60db45..0e35b3af7317 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -278,6 +278,7 @@ struct skb_shared_info {
278 unsigned short gso_type; 278 unsigned short gso_type;
279 struct sk_buff *frag_list; 279 struct sk_buff *frag_list;
280 struct skb_shared_hwtstamps hwtstamps; 280 struct skb_shared_hwtstamps hwtstamps;
281 u32 tskey;
281 __be32 ip6_frag_id; 282 __be32 ip6_frag_id;
282 283
283 /* 284 /*
diff --git a/include/net/sock.h b/include/net/sock.h
index a21129716aae..52fe0bc5598a 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -280,6 +280,7 @@ struct cg_proto;
280 * @sk_timer: sock cleanup timer 280 * @sk_timer: sock cleanup timer
281 * @sk_stamp: time stamp of last packet received 281 * @sk_stamp: time stamp of last packet received
282 * @sk_tsflags: SO_TIMESTAMPING socket options 282 * @sk_tsflags: SO_TIMESTAMPING socket options
283 * @sk_tskey: counter to disambiguate concurrent tstamp requests
283 * @sk_socket: Identd and reporting IO signals 284 * @sk_socket: Identd and reporting IO signals
284 * @sk_user_data: RPC layer private data 285 * @sk_user_data: RPC layer private data
285 * @sk_frag: cached page frag 286 * @sk_frag: cached page frag
@@ -414,6 +415,7 @@ struct sock {
414 struct timer_list sk_timer; 415 struct timer_list sk_timer;
415 ktime_t sk_stamp; 416 ktime_t sk_stamp;
416 u16 sk_tsflags; 417 u16 sk_tsflags;
418 u32 sk_tskey;
417 struct socket *sk_socket; 419 struct socket *sk_socket;
418 void *sk_user_data; 420 void *sk_user_data;
419 struct page_frag sk_frag; 421 struct page_frag sk_frag;
diff --git a/include/uapi/linux/net_tstamp.h b/include/uapi/linux/net_tstamp.h
index f53879c0f590..1e861d2e1a31 100644
--- a/include/uapi/linux/net_tstamp.h
+++ b/include/uapi/linux/net_tstamp.h
@@ -20,9 +20,11 @@ enum {
20 SOF_TIMESTAMPING_SOFTWARE = (1<<4), 20 SOF_TIMESTAMPING_SOFTWARE = (1<<4),
21 SOF_TIMESTAMPING_SYS_HARDWARE = (1<<5), 21 SOF_TIMESTAMPING_SYS_HARDWARE = (1<<5),
22 SOF_TIMESTAMPING_RAW_HARDWARE = (1<<6), 22 SOF_TIMESTAMPING_RAW_HARDWARE = (1<<6),
23 SOF_TIMESTAMPING_MASK = 23 SOF_TIMESTAMPING_OPT_ID = (1<<7),
24 (SOF_TIMESTAMPING_RAW_HARDWARE - 1) | 24
25 SOF_TIMESTAMPING_RAW_HARDWARE 25 SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_ID,
26 SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) |
27 SOF_TIMESTAMPING_LAST
26}; 28};
27 29
28/** 30/**
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index c9f68802e992..0df4f1d14c5a 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3522,6 +3522,8 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,
3522 serr->ee.ee_errno = ENOMSG; 3522 serr->ee.ee_errno = ENOMSG;
3523 serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; 3523 serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
3524 serr->ee.ee_info = SCM_TSTAMP_SND; 3524 serr->ee.ee_info = SCM_TSTAMP_SND;
3525 if (sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)
3526 serr->ee.ee_data = skb_shinfo(skb)->tskey;
3525 3527
3526 err = sock_queue_err_skb(sk, skb); 3528 err = sock_queue_err_skb(sk, skb);
3527 3529
diff --git a/net/core/sock.c b/net/core/sock.c
index 47c9377e14b9..1e0f1c63ad6b 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -848,6 +848,9 @@ set_rcvbuf:
848 ret = -EINVAL; 848 ret = -EINVAL;
849 break; 849 break;
850 } 850 }
851 if (val & SOF_TIMESTAMPING_OPT_ID &&
852 !(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID))
853 sk->sk_tskey = 0;
851 sk->sk_tsflags = val; 854 sk->sk_tsflags = val;
852 if (val & SOF_TIMESTAMPING_RX_SOFTWARE) 855 if (val & SOF_TIMESTAMPING_RX_SOFTWARE)
853 sock_enable_timestamp(sk, 856 sock_enable_timestamp(sk,
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index b16556836d66..215af2b155cb 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -855,11 +855,15 @@ static int __ip_append_data(struct sock *sk,
855 unsigned int maxfraglen, fragheaderlen, maxnonfragsize; 855 unsigned int maxfraglen, fragheaderlen, maxnonfragsize;
856 int csummode = CHECKSUM_NONE; 856 int csummode = CHECKSUM_NONE;
857 struct rtable *rt = (struct rtable *)cork->dst; 857 struct rtable *rt = (struct rtable *)cork->dst;
858 u32 tskey = 0;
858 859
859 skb = skb_peek_tail(queue); 860 skb = skb_peek_tail(queue);
860 861
861 exthdrlen = !skb ? rt->dst.header_len : 0; 862 exthdrlen = !skb ? rt->dst.header_len : 0;
862 mtu = cork->fragsize; 863 mtu = cork->fragsize;
864 if (cork->tx_flags & SKBTX_ANY_SW_TSTAMP &&
865 sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)
866 tskey = sk->sk_tskey++;
863 867
864 hh_len = LL_RESERVED_SPACE(rt->dst.dev); 868 hh_len = LL_RESERVED_SPACE(rt->dst.dev);
865 869
@@ -976,6 +980,8 @@ alloc_new_skb:
976 /* only the initial fragment is time stamped */ 980 /* only the initial fragment is time stamped */
977 skb_shinfo(skb)->tx_flags = cork->tx_flags; 981 skb_shinfo(skb)->tx_flags = cork->tx_flags;
978 cork->tx_flags = 0; 982 cork->tx_flags = 0;
983 skb_shinfo(skb)->tskey = tskey;
984 tskey = 0;
979 985
980 /* 986 /*
981 * Find where to start putting bytes. 987 * Find where to start putting bytes.
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index f5dafe609f8b..315a55d66079 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1157,6 +1157,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1157 int err; 1157 int err;
1158 int offset = 0; 1158 int offset = 0;
1159 __u8 tx_flags = 0; 1159 __u8 tx_flags = 0;
1160 u32 tskey = 0;
1160 1161
1161 if (flags&MSG_PROBE) 1162 if (flags&MSG_PROBE)
1162 return 0; 1163 return 0;
@@ -1272,8 +1273,12 @@ emsgsize:
1272 } 1273 }
1273 } 1274 }
1274 1275
1275 if (sk->sk_type == SOCK_DGRAM || sk->sk_type == SOCK_RAW) 1276 if (sk->sk_type == SOCK_DGRAM || sk->sk_type == SOCK_RAW) {
1276 sock_tx_timestamp(sk, &tx_flags); 1277 sock_tx_timestamp(sk, &tx_flags);
1278 if (tx_flags & SKBTX_ANY_SW_TSTAMP &&
1279 sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)
1280 tskey = sk->sk_tskey++;
1281 }
1277 1282
1278 /* 1283 /*
1279 * Let's try using as much space as possible. 1284 * Let's try using as much space as possible.
@@ -1397,6 +1402,8 @@ alloc_new_skb:
1397 /* Only the initial fragment is time stamped */ 1402 /* Only the initial fragment is time stamped */
1398 skb_shinfo(skb)->tx_flags = tx_flags; 1403 skb_shinfo(skb)->tx_flags = tx_flags;
1399 tx_flags = 0; 1404 tx_flags = 0;
1405 skb_shinfo(skb)->tskey = tskey;
1406 tskey = 0;
1400 1407
1401 /* 1408 /*
1402 * Find where to start putting bytes 1409 * Find where to start putting bytes