diff options
author | Andrey Vagin <avagin@openvz.org> | 2013-02-11 00:50:19 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-02-13 13:22:16 -0500 |
commit | ee684b6f2830047d19877e5547989740f18b1a5d (patch) | |
tree | 0fc416746eeca68bbba228958636dd919fc3785f /net/ipv4 | |
parent | 93be6ce0e91b6a94783e012b1857a347a5e6e9f2 (diff) |
tcp: send packets with a socket timestamp
A socket timestamp is a sum of the global tcp_time_stamp and
a per-socket offset.
A socket offset is added in places where externally visible
tcp timestamp option is parsed/initialized.
Connections in the SYN_RECV state are not supported, global
tcp_time_stamp is used for them, because repair mode doesn't support
this state. In a future it can be implemented by the similar way
as for TIME_WAIT sockets.
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Cc: James Morris <jmorris@namei.org>
Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Cc: Patrick McHardy <kaber@trash.net>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Andrey Vagin <avagin@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/tcp_input.c | 8 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 12 | ||||
-rw-r--r-- | net/ipv4/tcp_minisocks.c | 1 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 4 |
4 files changed, 17 insertions, 8 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index ea678b62e94f..d9bfaea34322 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -3860,7 +3860,7 @@ static bool tcp_parse_aligned_timestamp(struct tcp_sock *tp, const struct tcphdr | |||
3860 | ++ptr; | 3860 | ++ptr; |
3861 | tp->rx_opt.rcv_tsval = ntohl(*ptr); | 3861 | tp->rx_opt.rcv_tsval = ntohl(*ptr); |
3862 | ++ptr; | 3862 | ++ptr; |
3863 | tp->rx_opt.rcv_tsecr = ntohl(*ptr); | 3863 | tp->rx_opt.rcv_tsecr = ntohl(*ptr) - tp->tsoffset; |
3864 | return true; | 3864 | return true; |
3865 | } | 3865 | } |
3866 | return false; | 3866 | return false; |
@@ -3884,7 +3884,11 @@ static bool tcp_fast_parse_options(const struct sk_buff *skb, | |||
3884 | if (tcp_parse_aligned_timestamp(tp, th)) | 3884 | if (tcp_parse_aligned_timestamp(tp, th)) |
3885 | return true; | 3885 | return true; |
3886 | } | 3886 | } |
3887 | |||
3887 | tcp_parse_options(skb, &tp->rx_opt, hvpp, 1, NULL); | 3888 | tcp_parse_options(skb, &tp->rx_opt, hvpp, 1, NULL); |
3889 | if (tp->rx_opt.saw_tstamp) | ||
3890 | tp->rx_opt.rcv_tsecr -= tp->tsoffset; | ||
3891 | |||
3888 | return true; | 3892 | return true; |
3889 | } | 3893 | } |
3890 | 3894 | ||
@@ -5665,6 +5669,8 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, | |||
5665 | int saved_clamp = tp->rx_opt.mss_clamp; | 5669 | int saved_clamp = tp->rx_opt.mss_clamp; |
5666 | 5670 | ||
5667 | tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0, &foc); | 5671 | tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0, &foc); |
5672 | if (tp->rx_opt.saw_tstamp) | ||
5673 | tp->rx_opt.rcv_tsecr -= tp->tsoffset; | ||
5668 | 5674 | ||
5669 | if (th->ack) { | 5675 | if (th->ack) { |
5670 | /* rfc793: | 5676 | /* rfc793: |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0eaf685bddc9..77f5050efc8d 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -726,7 +726,7 @@ release_sk1: | |||
726 | */ | 726 | */ |
727 | 727 | ||
728 | static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, | 728 | static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, |
729 | u32 win, u32 ts, int oif, | 729 | u32 win, u32 tsval, u32 tsecr, int oif, |
730 | struct tcp_md5sig_key *key, | 730 | struct tcp_md5sig_key *key, |
731 | int reply_flags, u8 tos) | 731 | int reply_flags, u8 tos) |
732 | { | 732 | { |
@@ -747,12 +747,12 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, | |||
747 | 747 | ||
748 | arg.iov[0].iov_base = (unsigned char *)&rep; | 748 | arg.iov[0].iov_base = (unsigned char *)&rep; |
749 | arg.iov[0].iov_len = sizeof(rep.th); | 749 | arg.iov[0].iov_len = sizeof(rep.th); |
750 | if (ts) { | 750 | if (tsecr) { |
751 | rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | | 751 | rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | |
752 | (TCPOPT_TIMESTAMP << 8) | | 752 | (TCPOPT_TIMESTAMP << 8) | |
753 | TCPOLEN_TIMESTAMP); | 753 | TCPOLEN_TIMESTAMP); |
754 | rep.opt[1] = htonl(tcp_time_stamp); | 754 | rep.opt[1] = htonl(tsval); |
755 | rep.opt[2] = htonl(ts); | 755 | rep.opt[2] = htonl(tsecr); |
756 | arg.iov[0].iov_len += TCPOLEN_TSTAMP_ALIGNED; | 756 | arg.iov[0].iov_len += TCPOLEN_TSTAMP_ALIGNED; |
757 | } | 757 | } |
758 | 758 | ||
@@ -767,7 +767,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, | |||
767 | 767 | ||
768 | #ifdef CONFIG_TCP_MD5SIG | 768 | #ifdef CONFIG_TCP_MD5SIG |
769 | if (key) { | 769 | if (key) { |
770 | int offset = (ts) ? 3 : 0; | 770 | int offset = (tsecr) ? 3 : 0; |
771 | 771 | ||
772 | rep.opt[offset++] = htonl((TCPOPT_NOP << 24) | | 772 | rep.opt[offset++] = htonl((TCPOPT_NOP << 24) | |
773 | (TCPOPT_NOP << 16) | | 773 | (TCPOPT_NOP << 16) | |
@@ -802,6 +802,7 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) | |||
802 | 802 | ||
803 | tcp_v4_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, | 803 | tcp_v4_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, |
804 | tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, | 804 | tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, |
805 | tcp_time_stamp + tcptw->tw_ts_offset, | ||
805 | tcptw->tw_ts_recent, | 806 | tcptw->tw_ts_recent, |
806 | tw->tw_bound_dev_if, | 807 | tw->tw_bound_dev_if, |
807 | tcp_twsk_md5_key(tcptw), | 808 | tcp_twsk_md5_key(tcptw), |
@@ -821,6 +822,7 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, | |||
821 | tcp_v4_send_ack(skb, (sk->sk_state == TCP_LISTEN) ? | 822 | tcp_v4_send_ack(skb, (sk->sk_state == TCP_LISTEN) ? |
822 | tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt, | 823 | tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt, |
823 | tcp_rsk(req)->rcv_nxt, req->rcv_wnd, | 824 | tcp_rsk(req)->rcv_nxt, req->rcv_wnd, |
825 | tcp_time_stamp, | ||
824 | req->ts_recent, | 826 | req->ts_recent, |
825 | 0, | 827 | 0, |
826 | tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr, | 828 | tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr, |
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 4dfc99f54f67..b83a49cc3816 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c | |||
@@ -102,6 +102,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb, | |||
102 | tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL); | 102 | tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL); |
103 | 103 | ||
104 | if (tmp_opt.saw_tstamp) { | 104 | if (tmp_opt.saw_tstamp) { |
105 | tmp_opt.rcv_tsecr -= tcptw->tw_ts_offset; | ||
105 | tmp_opt.ts_recent = tcptw->tw_ts_recent; | 106 | tmp_opt.ts_recent = tcptw->tw_ts_recent; |
106 | tmp_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp; | 107 | tmp_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp; |
107 | paws_reject = tcp_paws_reject(&tmp_opt, th->rst); | 108 | paws_reject = tcp_paws_reject(&tmp_opt, th->rst); |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 367e2ec01da1..564bf89d9fd3 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -622,7 +622,7 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb, | |||
622 | 622 | ||
623 | if (likely(sysctl_tcp_timestamps && *md5 == NULL)) { | 623 | if (likely(sysctl_tcp_timestamps && *md5 == NULL)) { |
624 | opts->options |= OPTION_TS; | 624 | opts->options |= OPTION_TS; |
625 | opts->tsval = TCP_SKB_CB(skb)->when; | 625 | opts->tsval = TCP_SKB_CB(skb)->when + tp->tsoffset; |
626 | opts->tsecr = tp->rx_opt.ts_recent; | 626 | opts->tsecr = tp->rx_opt.ts_recent; |
627 | remaining -= TCPOLEN_TSTAMP_ALIGNED; | 627 | remaining -= TCPOLEN_TSTAMP_ALIGNED; |
628 | } | 628 | } |
@@ -806,7 +806,7 @@ static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb | |||
806 | 806 | ||
807 | if (likely(tp->rx_opt.tstamp_ok)) { | 807 | if (likely(tp->rx_opt.tstamp_ok)) { |
808 | opts->options |= OPTION_TS; | 808 | opts->options |= OPTION_TS; |
809 | opts->tsval = tcb ? tcb->when : 0; | 809 | opts->tsval = tcb ? tcb->when + tp->tsoffset : 0; |
810 | opts->tsecr = tp->rx_opt.ts_recent; | 810 | opts->tsecr = tp->rx_opt.ts_recent; |
811 | size += TCPOLEN_TSTAMP_ALIGNED; | 811 | size += TCPOLEN_TSTAMP_ALIGNED; |
812 | } | 812 | } |