Commit aa51b80e authored by Eric Dumazet's avatar Eric Dumazet Committed by Jakub Kicinski

ipv6: tcp: send consistent autoflowlabel in SYN_RECV state

This is a followup of commit c67b8555 ("ipv6: tcp: send consistent
autoflowlabel in TIME_WAIT state"), but for SYN_RECV state.

In some cases, TCP sends a challenge ACK on behalf of a SYN_RECV request.
WHen this happens, we want to use the flow label that was used when
the prior SYNACK packet was sent, instead of another one.

After his patch, following packetdrill passes:

    0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
   +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
   +0 bind(3, ..., ...) = 0
   +0 listen(3, 1) = 0

  +.2 < S 0:0(0) win 32792 <mss 1000,sackOK,nop,nop,nop,wscale 7>
   +0 > (flowlabel 0x11) S. 0:0(0) ack 1 <...>
// Test if a challenge ack is properly sent (same flowlabel than prior SYNACK)
   +.01 < . 4000000000:4000000000(0) ack 1 win 320
   +0  > (flowlabel 0x11) . 1:1(0) ack 1
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Link: https://lore.kernel.org/r/20220831203729.458000-1-eric.dumazet@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 1ab3d417
...@@ -858,7 +858,7 @@ const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { ...@@ -858,7 +858,7 @@ const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 seq, static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 seq,
u32 ack, u32 win, u32 tsval, u32 tsecr, u32 ack, u32 win, u32 tsval, u32 tsecr,
int oif, struct tcp_md5sig_key *key, int rst, int oif, struct tcp_md5sig_key *key, int rst,
u8 tclass, __be32 label, u32 priority) u8 tclass, __be32 label, u32 priority, u32 txhash)
{ {
const struct tcphdr *th = tcp_hdr(skb); const struct tcphdr *th = tcp_hdr(skb);
struct tcphdr *t1; struct tcphdr *t1;
...@@ -949,16 +949,16 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 ...@@ -949,16 +949,16 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32
} }
if (sk) { if (sk) {
if (sk->sk_state == TCP_TIME_WAIT) { if (sk->sk_state == TCP_TIME_WAIT)
mark = inet_twsk(sk)->tw_mark; mark = inet_twsk(sk)->tw_mark;
/* autoflowlabel relies on buff->hash */ else
skb_set_hash(buff, inet_twsk(sk)->tw_txhash,
PKT_HASH_TYPE_L4);
} else {
mark = sk->sk_mark; mark = sk->sk_mark;
}
skb_set_delivery_time(buff, tcp_transmit_time(sk), true); skb_set_delivery_time(buff, tcp_transmit_time(sk), true);
} }
if (txhash) {
/* autoflowlabel/skb_get_hash_flowi6 rely on buff->hash */
skb_set_hash(buff, txhash, PKT_HASH_TYPE_L4);
}
fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark) ?: mark; fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark) ?: mark;
fl6.fl6_dport = t1->dest; fl6.fl6_dport = t1->dest;
fl6.fl6_sport = t1->source; fl6.fl6_sport = t1->source;
...@@ -1085,7 +1085,7 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) ...@@ -1085,7 +1085,7 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb)
} }
tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1, tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1,
ipv6_get_dsfield(ipv6h), label, priority); ipv6_get_dsfield(ipv6h), label, priority, 0);
#ifdef CONFIG_TCP_MD5SIG #ifdef CONFIG_TCP_MD5SIG
out: out:
...@@ -1096,10 +1096,10 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) ...@@ -1096,10 +1096,10 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb)
static void tcp_v6_send_ack(const struct sock *sk, struct sk_buff *skb, u32 seq, static void tcp_v6_send_ack(const struct sock *sk, struct sk_buff *skb, u32 seq,
u32 ack, u32 win, u32 tsval, u32 tsecr, int oif, u32 ack, u32 win, u32 tsval, u32 tsecr, int oif,
struct tcp_md5sig_key *key, u8 tclass, struct tcp_md5sig_key *key, u8 tclass,
__be32 label, u32 priority) __be32 label, u32 priority, u32 txhash)
{ {
tcp_v6_send_response(sk, skb, seq, ack, win, tsval, tsecr, oif, key, 0, tcp_v6_send_response(sk, skb, seq, ack, win, tsval, tsecr, oif, key, 0,
tclass, label, priority); tclass, label, priority, txhash);
} }
static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
...@@ -1111,7 +1111,8 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) ...@@ -1111,7 +1111,8 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
tcp_time_stamp_raw() + tcptw->tw_ts_offset, tcp_time_stamp_raw() + tcptw->tw_ts_offset,
tcptw->tw_ts_recent, tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw), tcptw->tw_ts_recent, tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw),
tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel), tw->tw_priority); tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel), tw->tw_priority,
tw->tw_txhash);
inet_twsk_put(tw); inet_twsk_put(tw);
} }
...@@ -1138,7 +1139,8 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, ...@@ -1138,7 +1139,8 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
tcp_time_stamp_raw() + tcp_rsk(req)->ts_off, tcp_time_stamp_raw() + tcp_rsk(req)->ts_off,
req->ts_recent, sk->sk_bound_dev_if, req->ts_recent, sk->sk_bound_dev_if,
tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr, l3index), tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr, l3index),
ipv6_get_dsfield(ipv6_hdr(skb)), 0, sk->sk_priority); ipv6_get_dsfield(ipv6_hdr(skb)), 0, sk->sk_priority,
tcp_rsk(req)->txhash);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment