aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2012-07-26 08:18:11 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-26 18:50:39 -0400
commitc7109986db3c945f50ceed884a30e0fd8af3b89b (patch)
treec0852e90a7d06bdc95a54d6adad19d2a9e3d7d5e
parentc6cffba4ffa26a8ffacd0bb9f3144e34f20da7de (diff)
ipv6: Early TCP socket demux
This is the IPv6 missing bits for infrastructure added in commit 41063e9dd1195 (ipv4: Early TCP socket demux.) Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/inet6_hashtables.h13
-rw-r--r--include/net/protocol.h2
-rw-r--r--net/ipv4/ip_input.c1
-rw-r--r--net/ipv6/ip6_input.c13
-rw-r--r--net/ipv6/tcp_ipv6.c38
5 files changed, 59 insertions, 8 deletions
diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h
index 00cbb4384c79..9e34c877a770 100644
--- a/include/net/inet6_hashtables.h
+++ b/include/net/inet6_hashtables.h
@@ -96,14 +96,15 @@ static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo,
96 const __be16 sport, 96 const __be16 sport,
97 const __be16 dport) 97 const __be16 dport)
98{ 98{
99 struct sock *sk; 99 struct sock *sk = skb_steal_sock(skb);
100 100
101 if (unlikely(sk = skb_steal_sock(skb))) 101 if (sk)
102 return sk; 102 return sk;
103 else return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo, 103
104 &ipv6_hdr(skb)->saddr, sport, 104 return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo,
105 &ipv6_hdr(skb)->daddr, ntohs(dport), 105 &ipv6_hdr(skb)->saddr, sport,
106 inet6_iif(skb)); 106 &ipv6_hdr(skb)->daddr, ntohs(dport),
107 inet6_iif(skb));
107} 108}
108 109
109extern struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo, 110extern struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
diff --git a/include/net/protocol.h b/include/net/protocol.h
index 057f2d315567..929528c73fe8 100644
--- a/include/net/protocol.h
+++ b/include/net/protocol.h
@@ -52,6 +52,8 @@ struct net_protocol {
52 52
53#if IS_ENABLED(CONFIG_IPV6) 53#if IS_ENABLED(CONFIG_IPV6)
54struct inet6_protocol { 54struct inet6_protocol {
55 void (*early_demux)(struct sk_buff *skb);
56
55 int (*handler)(struct sk_buff *skb); 57 int (*handler)(struct sk_buff *skb);
56 58
57 void (*err_handler)(struct sk_buff *skb, 59 void (*err_handler)(struct sk_buff *skb,
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index bda8cac2ae91..981ff1eef28c 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -314,6 +314,7 @@ drop:
314} 314}
315 315
316int sysctl_ip_early_demux __read_mostly = 1; 316int sysctl_ip_early_demux __read_mostly = 1;
317EXPORT_SYMBOL(sysctl_ip_early_demux);
317 318
318static int ip_rcv_finish(struct sk_buff *skb) 319static int ip_rcv_finish(struct sk_buff *skb)
319{ 320{
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 5ab923e51af3..47975e363fcd 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -47,9 +47,18 @@
47 47
48 48
49 49
50inline int ip6_rcv_finish( struct sk_buff *skb) 50int ip6_rcv_finish(struct sk_buff *skb)
51{ 51{
52 if (skb_dst(skb) == NULL) 52 if (sysctl_ip_early_demux && !skb_dst(skb)) {
53 const struct inet6_protocol *ipprot;
54
55 rcu_read_lock();
56 ipprot = rcu_dereference(inet6_protos[ipv6_hdr(skb)->nexthdr]);
57 if (ipprot && ipprot->early_demux)
58 ipprot->early_demux(skb);
59 rcu_read_unlock();
60 }
61 if (!skb_dst(skb))
53 ip6_route_input(skb); 62 ip6_route_input(skb);
54 63
55 return dst_input(skb); 64 return dst_input(skb);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index f49476e2d884..221224e72507 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1674,6 +1674,43 @@ do_time_wait:
1674 goto discard_it; 1674 goto discard_it;
1675} 1675}
1676 1676
1677static void tcp_v6_early_demux(struct sk_buff *skb)
1678{
1679 const struct ipv6hdr *hdr;
1680 const struct tcphdr *th;
1681 struct sock *sk;
1682
1683 if (skb->pkt_type != PACKET_HOST)
1684 return;
1685
1686 if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct tcphdr)))
1687 return;
1688
1689 hdr = ipv6_hdr(skb);
1690 th = tcp_hdr(skb);
1691
1692 if (th->doff < sizeof(struct tcphdr) / 4)
1693 return;
1694
1695 sk = __inet6_lookup_established(dev_net(skb->dev), &tcp_hashinfo,
1696 &hdr->saddr, th->source,
1697 &hdr->daddr, ntohs(th->dest),
1698 inet6_iif(skb));
1699 if (sk) {
1700 skb->sk = sk;
1701 skb->destructor = sock_edemux;
1702 if (sk->sk_state != TCP_TIME_WAIT) {
1703 struct dst_entry *dst = sk->sk_rx_dst;
1704 struct inet_sock *icsk = inet_sk(sk);
1705 if (dst)
1706 dst = dst_check(dst, 0);
1707 if (dst &&
1708 icsk->rx_dst_ifindex == inet6_iif(skb))
1709 skb_dst_set_noref(skb, dst);
1710 }
1711 }
1712}
1713
1677static struct timewait_sock_ops tcp6_timewait_sock_ops = { 1714static struct timewait_sock_ops tcp6_timewait_sock_ops = {
1678 .twsk_obj_size = sizeof(struct tcp6_timewait_sock), 1715 .twsk_obj_size = sizeof(struct tcp6_timewait_sock),
1679 .twsk_unique = tcp_twsk_unique, 1716 .twsk_unique = tcp_twsk_unique,
@@ -1984,6 +2021,7 @@ struct proto tcpv6_prot = {
1984}; 2021};
1985 2022
1986static const struct inet6_protocol tcpv6_protocol = { 2023static const struct inet6_protocol tcpv6_protocol = {
2024 .early_demux = tcp_v6_early_demux,
1987 .handler = tcp_v6_rcv, 2025 .handler = tcp_v6_rcv,
1988 .err_handler = tcp_v6_err, 2026 .err_handler = tcp_v6_err,
1989 .gso_send_check = tcp_v6_gso_send_check, 2027 .gso_send_check = tcp_v6_gso_send_check,