Add software rx timestamp for TCP.
Subsystems (4)
v2 cover Add software rx timestamp for TCP.
From: Mike Maloney <[email protected]>
Add software rx timestamps for TCP, and a test to ensure consistency of behavior between IP, UDP, and TCP implementation.
Changes since v1:
-Initialize tss->ts[1] to 0 if caller requested any timestamps. -Fix test case to validate that tss->ts[1] is zero. -Fix tests to actually use a raw socket.
-Fix --tcp flag to work on the test.
Mike Maloney (2):
tcp: Extend SOF_TIMESTAMPING_RX_SOFTWARE to TCP recvmsg selftests/net: Add a test to validate behavior of rx timestamps
include/net/tcp.h | 9 +- net/ipv4/tcp.c | 65 ++++ net/ipv4/tcp_input.c | 35 +- net/ipv4/tcp_ipv4.c | 2 + net/ipv6/tcp_ipv6.c | 2 + .../selftests/networking/timestamping/.gitignore | 1 + .../selftests/networking/timestamping/Makefile | 4 +- .../networking/timestamping/rxtimestamp.c | 389 +++++++++++++++++++++ 8 files changed, 501 insertions(+), 6 deletions(-) create mode 100644 tools/testing/selftests/networking/timestamping/rxtimestamp.c
Signature · 1 line
2.14.1.480.gb18f417b89-goog
PATCH v2 1/2 tcp: Extend SOF_TIMESTAMPING_RX_SOFTWARE to TCP recvmsg
From: Mike Maloney <[email protected]>
When SOF_TIMESTAMPING_RX_SOFTWARE is enabled for tcp sockets, return the timestamp corresponding to the highest sequence number data returned.
Previously the skb->tstamp is overwritten when a TCP packet is placed in the out of order queue. While the packet is in the ooo queue, save the timestamp in the TCB_SKB_CB. This space is shared with the gso_* options which are only used on the tx path, and a previously unused 4 byte hole.
When skbs are coalesced either in the sk_receive_queue or the out_of_order_queue always choose the timestamp of the appended skb to maintain the invariant of returning the timestamp of the last byte in the recvmsg buffer.
--- include/net/tcp.h | 9 +++++++- net/ipv4/tcp.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ net/ipv4/tcp_input.c | 35 ++++++++++++++++++++++++---- net/ipv4/tcp_ipv4.c | 2 ++ net/ipv6/tcp_ipv6.c | 2 ++ 5 files changed, 108 insertions(+), 5 deletions(-)
include/net/tcp.h +8 -1
@@ -774,6 +774,12 @@ struct tcp_skb_cb {u16 tcp_gso_segs;u16 tcp_gso_size; }; + +/* Used to stash the receive timestamp while this skb is in the +* out of order queue, as skb->tstamp is overwritten by the +* rbnode. +*/ +ktime_t swtstamp; };__u8 tcp_flags;/* TCP header flags. (tcp[13]) */
@@ -790,7 +796,8 @@ struct tcp_skb_cb {__u8 ip_dsfield;/* IPv4 tos or IPv6 dsfield */ __u8 txstamp_ack:1, /* Record TX timestamp for ack? */ eor:1, /* Is skb MSG_EOR marked? */ - unused:6; + has_rxtstamp:1, /* SKB has a RX timestamp */ + unused:5;__u32 ack_seq;/* Sequence number ACK'd */ union { struct {
net/ipv4/tcp.c +65 -0
95 lines not on this page · raw message
net/ipv4/tcp_input.c +31 -4
@@ -4246,9 +4246,15 @@ static void tcp_sack_remove(struct tcp_sock *tp) tp->rx_opt.num_sacks = num_sacks; } +enum tcp_queue { +OOO_QUEUE , +RCV_QUEUE , +}; +/** * tcp_try_coalesce - try to merge skb to prior one * @sk: socket +* @dest: destination queue * @to: prior buffer * @from: buffer to add in queue * @fragstolen: pointer to boolean
@@ -4260,6 +4266,7 @@ static void tcp_sack_remove(struct tcp_sock *tp)* Returns true if caller should free @from instead of queueing it */ static bool tcp_try_coalesce (struct sock *sk, +enum tcp_queue dest,struct sk_buff *to,struct sk_buff *from,bool *fragstolen)
@@ -4281,6 +4288,15 @@ static bool tcp_try_coalesce(struct sock *sk,TCP_SKB_CB (to)->end_seq =TCP_SKB_CB (from)->end_seq;TCP_SKB_CB (to)->ack_seq =TCP_SKB_CB (from)->ack_seq;TCP_SKB_CB (to)->tcp_flags |=TCP_SKB_CB (from)->tcp_flags; + +if (TCP_SKB_CB (from)->has_rxtstamp) { +TCP_SKB_CB (to)->has_rxtstamp = true; +if (dest ==OOO_QUEUE ) +TCP_SKB_CB (to)->swtstamp =TCP_SKB_CB (from)->swtstamp; +else + to->tstamp = from->tstamp; + } +return true; }
@@ -4315,6 +4331,9 @@ static void tcp_ofo_queue(struct sock *sk) } p =rb_next (p);rb_erase (&skb->rbnode, &tp->out_of_order_queue); +/* Replace tstamp which was stomped by rbnode */ +if (TCP_SKB_CB (skb)->has_rxtstamp) + skb->tstamp =TCP_SKB_CB (skb)->swtstamp;if (unlikely (!after (TCP_SKB_CB (skb)->end_seq, tp->rcv_nxt))) {SOCK_DEBUG (sk,"ofo packet was already received\n" );
@@ -4326,7 +4345,8 @@ static void tcp_ofo_queue(struct sock *sk) TCP_SKB_CB(skb)->end_seq); tail =skb_peek_tail (&sk->sk_receive_queue); - eaten = tail &&tcp_try_coalesce (sk, tail, skb, &fragstolen); + eaten = tail &&tcp_try_coalesce (sk,RCV_QUEUE , + tail, skb, &fragstolen);tcp_rcv_nxt_update (tp,TCP_SKB_CB (skb)->end_seq); fin =TCP_SKB_CB (skb)->tcp_flags &TCPHDR_FIN ;if (!eaten)
@@ -4380,6 +4400,10 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)return ; } +/* Stash tstamp to avoid being stomped on by rbnode */ +if (TCP_SKB_CB (skb)->has_rxtstamp) +TCP_SKB_CB (skb)->swtstamp = skb->tstamp; +inet_csk_schedule_ack (sk);NET_INC_STATS (sock_net (sk),LINUX_MIB_TCPOFOQUEUE );
@@ -4405,7 +4429,8 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)/* In the typical case, we are adding an skb to the end of the list. * Use of ooo_last_skb avoids the O(Log(N)) rbtree lookup. */ -if (tcp_try_coalesce (sk, tp->ooo_last_skb, skb, &fragstolen)) { +if (tcp_try_coalesce (sk,OOO_QUEUE , tp->ooo_last_skb, + skb, &fragstolen)) { coalesce_done:tcp_grow_window (sk, skb);kfree_skb_partial (skb, fragstolen);
@@ -4455,7 +4480,8 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)__kfree_skb (skb1); goto merge_right; } - }else if (tcp_try_coalesce (sk, skb1, skb, &fragstolen)) { + }else if (tcp_try_coalesce (sk,OOO_QUEUE , skb1, + skb, &fragstolen)) { goto coalesce_done; } p = &parent->rb_right;
@@ -4506,7 +4532,8 @@ static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int__skb_pull (skb, hdrlen); eaten = (tail && -tcp_try_coalesce (sk, tail, skb, fragstolen)) ?1 :0 ; +tcp_try_coalesce (sk,RCV_QUEUE , tail, + skb, fragstolen)) ?1 :0 ;tcp_rcv_nxt_update (tcp_sk (sk),TCP_SKB_CB (skb)->end_seq);if (!eaten) {__skb_queue_tail (&sk->sk_receive_queue, skb);
net/ipv4/tcp_ipv4.c +2 -0
@@ -1637,6 +1637,8 @@ int tcp_v4_rcv(struct sk_buff *skb)TCP_SKB_CB (skb)->tcp_tw_isn =0 ;TCP_SKB_CB (skb)->ip_dsfield =ipv4_get_dsfield (iph);TCP_SKB_CB (skb)->sacked =0 ; +TCP_SKB_CB (skb)->has_rxtstamp = + skb->tstamp ||skb_hwtstamps (skb)->hwtstamp; lookup: sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), th->source,
net/ipv6/tcp_ipv6.c +2 -0
@@ -1394,6 +1394,8 @@ static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr,TCP_SKB_CB (skb)->tcp_tw_isn =0 ;TCP_SKB_CB (skb)->ip_dsfield =ipv6_get_dsfield (hdr);TCP_SKB_CB (skb)->sacked =0 ; +TCP_SKB_CB (skb)->has_rxtstamp = + skb->tstamp ||skb_hwtstamps (skb)->hwtstamp; }static int tcp_v6_rcv (struct sk_buff *skb)
Signature · 1 line
2.14.1.480.gb18f417b89-goog
Re: [PATCH v2 net-next 1/2] tcp: Extend SOF_TIMESTAMPING_RX_SOFTWARE to TCP recvmsg
Quoted 11 lines · Mike Maloney
From: Mike Maloney <[email protected]>
When
SOF_TIMESTAMPING_RX_SOFTWAREis enabled for tcp sockets, return the timestamp corresponding to the highest sequence number data returned.Previously the
skb->tstampis overwritten when a TCP packet is placed in the out of order queue. While the packet is in the ooo queue, save the timestamp in theTCB_SKB_CB. This space is shared with the gso_* options which are only used on the tx path, and a previously unused 4 byte hole.
Quoted 6 lines
When skbs are coalesced either in the
sk_receive_queueor theout_of_order_queuealways choose the timestamp of the appended skb to maintain the invariant of returning the timestamp of the last byte in the recvmsg buffer.Signed-off-by Mike Maloney <[email protected]>
PATCH v2 2/2 selftests/net: Add a test to validate behavior of rx timestamps
In reply to Mike MaloneyFrom: Mike Maloney <[email protected]>
Validate the behavior of the combination of various timestamp socket options, and ensure consistency across ip, udp, and tcp.
--- .../selftests/networking/timestamping/.gitignore | 1 + .../selftests/networking/timestamping/Makefile | 4 +- .../networking/timestamping/rxtimestamp.c | 389 +++++++++++++++++++++ 3 files changed, 393 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/networking/timestamping/rxtimestamp.c
tools/testing/selftests/networking/timestamping/.gitignore +1 -0
@@ -1,3 +1,4 @@ timestamping +rxtimestamp txtimestamp hwtstamp_config
tools/testing/selftests/networking/timestamping/Makefile +3 -1
@@ -1,4 +1,6 @@ -TEST_PROGS := hwtstamp_config timestamping txtimestamp +CFLAGS += -I../../../../../usr/include + +TEST_PROGS := hwtstamp_config rxtimestamp timestamping txtimestamp all: $(TEST_PROGS)
tools/testing/selftests/networking/timestamping/rxtimestamp.c new file +389 -0
389 lines not on this page · raw message
Signature · 1 line
2.14.1.480.gb18f417b89-goog
Re: [PATCH v2 net-next 2/2] selftests/net: Add a test to validate behavior of rx timestamps
Quoted 6 lines · Mike Maloney
From: Mike Maloney <[email protected]>
Validate the behavior of the combination of various timestamp socket options, and ensure consistency across ip, udp, and tcp.
Signed-off-by Mike Maloney <[email protected]>
Thanks for adding these tests.
For tcp, it may be useful to eventually also add packetdrill tests to validate the more subtle semantics, such as that the timestamp is returned only when reading the last byte of the skb.
tools/testing/selftests/networking/timestamping/rxtimestamp.c line 315
Quoted 4 lines
tools/testing/selftests/networking/timestamping/rxtimestamp.c new file +4
-0+do_send (src); + +if (s.type ==SOCK_RAW ) + read_size +=20 ;/* for IP header */
No need to revise just for this, but if submitting a v3:
please use sizeof(struct iphdr). And maybe test PF_INET6, too.
David Miller
maintainerFrom: Mike Maloney <[email protected]>
Date: Tue, 22 Aug 2017 17:08:47 -0400
Quoted 10 lines
From: Mike Maloney <[email protected]>
Add software rx timestamps for TCP, and a test to ensure consistency of behavior between IP, UDP, and TCP implementation.
Changes since v1:
-Initialize tss->ts[1] to 0 if caller requested any timestamps. -Fix test case to validate that tss->ts[1] is zero. -Fix tests to actually use a raw socket.
-Fix --tcp flag to work on the test.
Series applied, thanks.