Skip to content

Commit 5d299f3

Browse files
edumazetdavem330
authored andcommitted
net: ipv6: fix TCP early demux
IPv6 needs a cookie in dst_check() call. We need to add rx_dst_cookie and provide a family independent sk_rx_dst_set(sk, skb) method to properly support IPv6 TCP early demux. Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent b5497ee commit 5d299f3

File tree

7 files changed

+41
-16
lines changed

7 files changed

+41
-16
lines changed

include/linux/ipv6.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,7 @@ struct ipv6_pinfo {
369369
__u8 rcv_tclass;
370370

371371
__u32 dst_cookie;
372+
__u32 rx_dst_cookie;
372373

373374
struct ipv6_mc_socklist __rcu *ipv6_mc_list;
374375
struct ipv6_ac_socklist *ipv6_ac_list;

include/net/inet_connection_sock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct inet_connection_sock_af_ops {
3939
int (*queue_xmit)(struct sk_buff *skb, struct flowi *fl);
4040
void (*send_check)(struct sock *sk, struct sk_buff *skb);
4141
int (*rebuild_header)(struct sock *sk);
42+
void (*sk_rx_dst_set)(struct sock *sk, const struct sk_buff *skb);
4243
int (*conn_request)(struct sock *sk, struct sk_buff *skb);
4344
struct sock *(*syn_recv_sock)(struct sock *sk, struct sk_buff *skb,
4445
struct request_sock *req,

include/net/inet_sock.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -249,13 +249,4 @@ static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
249249
return flags;
250250
}
251251

252-
static inline void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
253-
{
254-
struct dst_entry *dst = skb_dst(skb);
255-
256-
dst_hold(dst);
257-
sk->sk_rx_dst = dst;
258-
inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
259-
}
260-
261252
#endif /* _INET_SOCK_H */

net/ipv4/tcp_input.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5392,6 +5392,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
53925392
{
53935393
struct tcp_sock *tp = tcp_sk(sk);
53945394

5395+
if (unlikely(sk->sk_rx_dst == NULL))
5396+
inet_csk(sk)->icsk_af_ops->sk_rx_dst_set(sk, skb);
53955397
/*
53965398
* Header prediction.
53975399
* The code loosely follows the one in the famous
@@ -5605,7 +5607,7 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)
56055607
tcp_set_state(sk, TCP_ESTABLISHED);
56065608

56075609
if (skb != NULL) {
5608-
inet_sk_rx_dst_set(sk, skb);
5610+
icsk->icsk_af_ops->sk_rx_dst_set(sk, skb);
56095611
security_inet_conn_established(sk, skb);
56105612
}
56115613

net/ipv4/tcp_ipv4.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,9 +1627,6 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
16271627
sk->sk_rx_dst = NULL;
16281628
}
16291629
}
1630-
if (unlikely(sk->sk_rx_dst == NULL))
1631-
inet_sk_rx_dst_set(sk, skb);
1632-
16331630
if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {
16341631
rsk = sk;
16351632
goto reset;
@@ -1872,10 +1869,20 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = {
18721869
.twsk_destructor= tcp_twsk_destructor,
18731870
};
18741871

1872+
static void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
1873+
{
1874+
struct dst_entry *dst = skb_dst(skb);
1875+
1876+
dst_hold(dst);
1877+
sk->sk_rx_dst = dst;
1878+
inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
1879+
}
1880+
18751881
const struct inet_connection_sock_af_ops ipv4_specific = {
18761882
.queue_xmit = ip_queue_xmit,
18771883
.send_check = tcp_v4_send_check,
18781884
.rebuild_header = inet_sk_rebuild_header,
1885+
.sk_rx_dst_set = inet_sk_rx_dst_set,
18791886
.conn_request = tcp_v4_conn_request,
18801887
.syn_recv_sock = tcp_v4_syn_recv_sock,
18811888
.net_header_len = sizeof(struct iphdr),

net/ipv4/tcp_minisocks.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
387387
struct tcp_sock *oldtp = tcp_sk(sk);
388388
struct tcp_cookie_values *oldcvp = oldtp->cookie_values;
389389

390-
inet_sk_rx_dst_set(newsk, skb);
390+
newicsk->icsk_af_ops->sk_rx_dst_set(newsk, skb);
391391

392392
/* TCP Cookie Transactions require space for the cookie pair,
393393
* as it differs for each connection. There is no need to

net/ipv6/tcp_ipv6.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,7 +1447,17 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
14471447
opt_skb = skb_clone(skb, sk_gfp_atomic(sk, GFP_ATOMIC));
14481448

14491449
if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
1450+
struct dst_entry *dst = sk->sk_rx_dst;
1451+
14501452
sock_rps_save_rxhash(sk, skb);
1453+
if (dst) {
1454+
if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif ||
1455+
dst->ops->check(dst, np->rx_dst_cookie) == NULL) {
1456+
dst_release(dst);
1457+
sk->sk_rx_dst = NULL;
1458+
}
1459+
}
1460+
14511461
if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
14521462
goto reset;
14531463
if (opt_skb)
@@ -1705,9 +1715,9 @@ static void tcp_v6_early_demux(struct sk_buff *skb)
17051715
struct dst_entry *dst = sk->sk_rx_dst;
17061716
struct inet_sock *icsk = inet_sk(sk);
17071717
if (dst)
1708-
dst = dst_check(dst, 0);
1718+
dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie);
17091719
if (dst &&
1710-
icsk->rx_dst_ifindex == inet6_iif(skb))
1720+
icsk->rx_dst_ifindex == skb->skb_iif)
17111721
skb_dst_set_noref(skb, dst);
17121722
}
17131723
}
@@ -1719,10 +1729,23 @@ static struct timewait_sock_ops tcp6_timewait_sock_ops = {
17191729
.twsk_destructor= tcp_twsk_destructor,
17201730
};
17211731

1732+
static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
1733+
{
1734+
struct dst_entry *dst = skb_dst(skb);
1735+
const struct rt6_info *rt = (const struct rt6_info *)dst;
1736+
1737+
dst_hold(dst);
1738+
sk->sk_rx_dst = dst;
1739+
inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
1740+
if (rt->rt6i_node)
1741+
inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum;
1742+
}
1743+
17221744
static const struct inet_connection_sock_af_ops ipv6_specific = {
17231745
.queue_xmit = inet6_csk_xmit,
17241746
.send_check = tcp_v6_send_check,
17251747
.rebuild_header = inet6_sk_rebuild_header,
1748+
.sk_rx_dst_set = inet6_sk_rx_dst_set,
17261749
.conn_request = tcp_v6_conn_request,
17271750
.syn_recv_sock = tcp_v6_syn_recv_sock,
17281751
.net_header_len = sizeof(struct ipv6hdr),

0 commit comments

Comments
 (0)