Commit 5d299f3d authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

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: default avatarEric Dumazet <[email protected]>
Signed-off-by: default avatarDavid S. Miller <[email protected]>
parent b5497eeb
...@@ -369,6 +369,7 @@ struct ipv6_pinfo { ...@@ -369,6 +369,7 @@ struct ipv6_pinfo {
__u8 rcv_tclass; __u8 rcv_tclass;
__u32 dst_cookie; __u32 dst_cookie;
__u32 rx_dst_cookie;
struct ipv6_mc_socklist __rcu *ipv6_mc_list; struct ipv6_mc_socklist __rcu *ipv6_mc_list;
struct ipv6_ac_socklist *ipv6_ac_list; struct ipv6_ac_socklist *ipv6_ac_list;
......
...@@ -39,6 +39,7 @@ struct inet_connection_sock_af_ops { ...@@ -39,6 +39,7 @@ struct inet_connection_sock_af_ops {
int (*queue_xmit)(struct sk_buff *skb, struct flowi *fl); int (*queue_xmit)(struct sk_buff *skb, struct flowi *fl);
void (*send_check)(struct sock *sk, struct sk_buff *skb); void (*send_check)(struct sock *sk, struct sk_buff *skb);
int (*rebuild_header)(struct sock *sk); int (*rebuild_header)(struct sock *sk);
void (*sk_rx_dst_set)(struct sock *sk, const struct sk_buff *skb);
int (*conn_request)(struct sock *sk, struct sk_buff *skb); int (*conn_request)(struct sock *sk, struct sk_buff *skb);
struct sock *(*syn_recv_sock)(struct sock *sk, struct sk_buff *skb, struct sock *(*syn_recv_sock)(struct sock *sk, struct sk_buff *skb,
struct request_sock *req, struct request_sock *req,
......
...@@ -249,13 +249,4 @@ static inline __u8 inet_sk_flowi_flags(const struct sock *sk) ...@@ -249,13 +249,4 @@ static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
return flags; return flags;
} }
static inline void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
dst_hold(dst);
sk->sk_rx_dst = dst;
inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
}
#endif /* _INET_SOCK_H */ #endif /* _INET_SOCK_H */
...@@ -5392,6 +5392,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, ...@@ -5392,6 +5392,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
{ {
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
if (unlikely(sk->sk_rx_dst == NULL))
inet_csk(sk)->icsk_af_ops->sk_rx_dst_set(sk, skb);
/* /*
* Header prediction. * Header prediction.
* The code loosely follows the one in the famous * The code loosely follows the one in the famous
...@@ -5605,7 +5607,7 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb) ...@@ -5605,7 +5607,7 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)
tcp_set_state(sk, TCP_ESTABLISHED); tcp_set_state(sk, TCP_ESTABLISHED);
if (skb != NULL) { if (skb != NULL) {
inet_sk_rx_dst_set(sk, skb); icsk->icsk_af_ops->sk_rx_dst_set(sk, skb);
security_inet_conn_established(sk, skb); security_inet_conn_established(sk, skb);
} }
......
...@@ -1627,9 +1627,6 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -1627,9 +1627,6 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
sk->sk_rx_dst = NULL; sk->sk_rx_dst = NULL;
} }
} }
if (unlikely(sk->sk_rx_dst == NULL))
inet_sk_rx_dst_set(sk, skb);
if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) { if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {
rsk = sk; rsk = sk;
goto reset; goto reset;
...@@ -1872,10 +1869,20 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = { ...@@ -1872,10 +1869,20 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = {
.twsk_destructor= tcp_twsk_destructor, .twsk_destructor= tcp_twsk_destructor,
}; };
static void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
dst_hold(dst);
sk->sk_rx_dst = dst;
inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
}
const struct inet_connection_sock_af_ops ipv4_specific = { const struct inet_connection_sock_af_ops ipv4_specific = {
.queue_xmit = ip_queue_xmit, .queue_xmit = ip_queue_xmit,
.send_check = tcp_v4_send_check, .send_check = tcp_v4_send_check,
.rebuild_header = inet_sk_rebuild_header, .rebuild_header = inet_sk_rebuild_header,
.sk_rx_dst_set = inet_sk_rx_dst_set,
.conn_request = tcp_v4_conn_request, .conn_request = tcp_v4_conn_request,
.syn_recv_sock = tcp_v4_syn_recv_sock, .syn_recv_sock = tcp_v4_syn_recv_sock,
.net_header_len = sizeof(struct iphdr), .net_header_len = sizeof(struct iphdr),
......
...@@ -387,7 +387,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, ...@@ -387,7 +387,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
struct tcp_sock *oldtp = tcp_sk(sk); struct tcp_sock *oldtp = tcp_sk(sk);
struct tcp_cookie_values *oldcvp = oldtp->cookie_values; struct tcp_cookie_values *oldcvp = oldtp->cookie_values;
inet_sk_rx_dst_set(newsk, skb); newicsk->icsk_af_ops->sk_rx_dst_set(newsk, skb);
/* TCP Cookie Transactions require space for the cookie pair, /* TCP Cookie Transactions require space for the cookie pair,
* as it differs for each connection. There is no need to * as it differs for each connection. There is no need to
......
...@@ -1447,7 +1447,17 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -1447,7 +1447,17 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
opt_skb = skb_clone(skb, sk_gfp_atomic(sk, GFP_ATOMIC)); opt_skb = skb_clone(skb, sk_gfp_atomic(sk, GFP_ATOMIC));
if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
struct dst_entry *dst = sk->sk_rx_dst;
sock_rps_save_rxhash(sk, skb); sock_rps_save_rxhash(sk, skb);
if (dst) {
if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif ||
dst->ops->check(dst, np->rx_dst_cookie) == NULL) {
dst_release(dst);
sk->sk_rx_dst = NULL;
}
}
if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
goto reset; goto reset;
if (opt_skb) if (opt_skb)
...@@ -1705,9 +1715,9 @@ static void tcp_v6_early_demux(struct sk_buff *skb) ...@@ -1705,9 +1715,9 @@ static void tcp_v6_early_demux(struct sk_buff *skb)
struct dst_entry *dst = sk->sk_rx_dst; struct dst_entry *dst = sk->sk_rx_dst;
struct inet_sock *icsk = inet_sk(sk); struct inet_sock *icsk = inet_sk(sk);
if (dst) if (dst)
dst = dst_check(dst, 0); dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie);
if (dst && if (dst &&
icsk->rx_dst_ifindex == inet6_iif(skb)) icsk->rx_dst_ifindex == skb->skb_iif)
skb_dst_set_noref(skb, dst); skb_dst_set_noref(skb, dst);
} }
} }
...@@ -1719,10 +1729,23 @@ static struct timewait_sock_ops tcp6_timewait_sock_ops = { ...@@ -1719,10 +1729,23 @@ static struct timewait_sock_ops tcp6_timewait_sock_ops = {
.twsk_destructor= tcp_twsk_destructor, .twsk_destructor= tcp_twsk_destructor,
}; };
static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
const struct rt6_info *rt = (const struct rt6_info *)dst;
dst_hold(dst);
sk->sk_rx_dst = dst;
inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
if (rt->rt6i_node)
inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum;
}
static const struct inet_connection_sock_af_ops ipv6_specific = { static const struct inet_connection_sock_af_ops ipv6_specific = {
.queue_xmit = inet6_csk_xmit, .queue_xmit = inet6_csk_xmit,
.send_check = tcp_v6_send_check, .send_check = tcp_v6_send_check,
.rebuild_header = inet6_sk_rebuild_header, .rebuild_header = inet6_sk_rebuild_header,
.sk_rx_dst_set = inet6_sk_rx_dst_set,
.conn_request = tcp_v6_conn_request, .conn_request = tcp_v6_conn_request,
.syn_recv_sock = tcp_v6_syn_recv_sock, .syn_recv_sock = tcp_v6_syn_recv_sock,
.net_header_len = sizeof(struct ipv6hdr), .net_header_len = sizeof(struct ipv6hdr),
......
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