diff options
author | Eric Dumazet <edumazet@google.com> | 2012-08-06 01:09:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-08-06 16:33:21 -0400 |
commit | 5d299f3d3c8a2fbc732b1bf03af36333ccec3130 (patch) | |
tree | 119701591725281d99ecad6f459166da3e6034a2 /net | |
parent | b5497eeb37d7d4a5a61b91f64efedc90d1ad6fa3 (diff) |
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>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/tcp_input.c | 4 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 13 | ||||
-rw-r--r-- | net/ipv4/tcp_minisocks.c | 2 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 27 |
4 files changed, 39 insertions, 7 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 2fd2bc9e3c64..85308b90df80 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -5392,6 +5392,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, | |||
5392 | { | 5392 | { |
5393 | struct tcp_sock *tp = tcp_sk(sk); | 5393 | struct tcp_sock *tp = tcp_sk(sk); |
5394 | 5394 | ||
5395 | if (unlikely(sk->sk_rx_dst == NULL)) | ||
5396 | inet_csk(sk)->icsk_af_ops->sk_rx_dst_set(sk, skb); | ||
5395 | /* | 5397 | /* |
5396 | * Header prediction. | 5398 | * Header prediction. |
5397 | * The code loosely follows the one in the famous | 5399 | * 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 | tcp_set_state(sk, TCP_ESTABLISHED); | 5607 | tcp_set_state(sk, TCP_ESTABLISHED); |
5606 | 5608 | ||
5607 | if (skb != NULL) { | 5609 | if (skb != NULL) { |
5608 | inet_sk_rx_dst_set(sk, skb); | 5610 | icsk->icsk_af_ops->sk_rx_dst_set(sk, skb); |
5609 | security_inet_conn_established(sk, skb); | 5611 | security_inet_conn_established(sk, skb); |
5610 | } | 5612 | } |
5611 | 5613 | ||
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 42b2a6a73092..272241f16fcb 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1627,9 +1627,6 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
1627 | sk->sk_rx_dst = NULL; | 1627 | sk->sk_rx_dst = NULL; |
1628 | } | 1628 | } |
1629 | } | 1629 | } |
1630 | if (unlikely(sk->sk_rx_dst == NULL)) | ||
1631 | inet_sk_rx_dst_set(sk, skb); | ||
1632 | |||
1633 | if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) { | 1630 | if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) { |
1634 | rsk = sk; | 1631 | rsk = sk; |
1635 | goto reset; | 1632 | goto reset; |
@@ -1872,10 +1869,20 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = { | |||
1872 | .twsk_destructor= tcp_twsk_destructor, | 1869 | .twsk_destructor= tcp_twsk_destructor, |
1873 | }; | 1870 | }; |
1874 | 1871 | ||
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 | |||
1875 | const struct inet_connection_sock_af_ops ipv4_specific = { | 1881 | const struct inet_connection_sock_af_ops ipv4_specific = { |
1876 | .queue_xmit = ip_queue_xmit, | 1882 | .queue_xmit = ip_queue_xmit, |
1877 | .send_check = tcp_v4_send_check, | 1883 | .send_check = tcp_v4_send_check, |
1878 | .rebuild_header = inet_sk_rebuild_header, | 1884 | .rebuild_header = inet_sk_rebuild_header, |
1885 | .sk_rx_dst_set = inet_sk_rx_dst_set, | ||
1879 | .conn_request = tcp_v4_conn_request, | 1886 | .conn_request = tcp_v4_conn_request, |
1880 | .syn_recv_sock = tcp_v4_syn_recv_sock, | 1887 | .syn_recv_sock = tcp_v4_syn_recv_sock, |
1881 | .net_header_len = sizeof(struct iphdr), | 1888 | .net_header_len = sizeof(struct iphdr), |
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 232a90c3ec86..d9c9dcef2de3 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c | |||
@@ -387,7 +387,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, | |||
387 | struct tcp_sock *oldtp = tcp_sk(sk); | 387 | struct tcp_sock *oldtp = tcp_sk(sk); |
388 | struct tcp_cookie_values *oldcvp = oldtp->cookie_values; | 388 | struct tcp_cookie_values *oldcvp = oldtp->cookie_values; |
389 | 389 | ||
390 | inet_sk_rx_dst_set(newsk, skb); | 390 | newicsk->icsk_af_ops->sk_rx_dst_set(newsk, skb); |
391 | 391 | ||
392 | /* TCP Cookie Transactions require space for the cookie pair, | 392 | /* TCP Cookie Transactions require space for the cookie pair, |
393 | * as it differs for each connection. There is no need to | 393 | * as it differs for each connection. There is no need to |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index c66b90f71c9b..5a439e9a4c01 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -1447,7 +1447,17 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) | |||
1447 | opt_skb = skb_clone(skb, sk_gfp_atomic(sk, GFP_ATOMIC)); | 1447 | opt_skb = skb_clone(skb, sk_gfp_atomic(sk, GFP_ATOMIC)); |
1448 | 1448 | ||
1449 | if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ | 1449 | if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ |
1450 | struct dst_entry *dst = sk->sk_rx_dst; | ||
1451 | |||
1450 | sock_rps_save_rxhash(sk, skb); | 1452 | 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 | |||
1451 | if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) | 1461 | if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) |
1452 | goto reset; | 1462 | goto reset; |
1453 | if (opt_skb) | 1463 | if (opt_skb) |
@@ -1705,9 +1715,9 @@ static void tcp_v6_early_demux(struct sk_buff *skb) | |||
1705 | struct dst_entry *dst = sk->sk_rx_dst; | 1715 | struct dst_entry *dst = sk->sk_rx_dst; |
1706 | struct inet_sock *icsk = inet_sk(sk); | 1716 | struct inet_sock *icsk = inet_sk(sk); |
1707 | if (dst) | 1717 | if (dst) |
1708 | dst = dst_check(dst, 0); | 1718 | dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie); |
1709 | if (dst && | 1719 | if (dst && |
1710 | icsk->rx_dst_ifindex == inet6_iif(skb)) | 1720 | icsk->rx_dst_ifindex == skb->skb_iif) |
1711 | skb_dst_set_noref(skb, dst); | 1721 | skb_dst_set_noref(skb, dst); |
1712 | } | 1722 | } |
1713 | } | 1723 | } |
@@ -1719,10 +1729,23 @@ static struct timewait_sock_ops tcp6_timewait_sock_ops = { | |||
1719 | .twsk_destructor= tcp_twsk_destructor, | 1729 | .twsk_destructor= tcp_twsk_destructor, |
1720 | }; | 1730 | }; |
1721 | 1731 | ||
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 | |||
1722 | static const struct inet_connection_sock_af_ops ipv6_specific = { | 1744 | static const struct inet_connection_sock_af_ops ipv6_specific = { |
1723 | .queue_xmit = inet6_csk_xmit, | 1745 | .queue_xmit = inet6_csk_xmit, |
1724 | .send_check = tcp_v6_send_check, | 1746 | .send_check = tcp_v6_send_check, |
1725 | .rebuild_header = inet6_sk_rebuild_header, | 1747 | .rebuild_header = inet6_sk_rebuild_header, |
1748 | .sk_rx_dst_set = inet6_sk_rx_dst_set, | ||
1726 | .conn_request = tcp_v6_conn_request, | 1749 | .conn_request = tcp_v6_conn_request, |
1727 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1750 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
1728 | .net_header_len = sizeof(struct ipv6hdr), | 1751 | .net_header_len = sizeof(struct ipv6hdr), |