diff options
author | David S. Miller <davem@davemloft.net> | 2012-06-20 00:22:05 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-06-20 00:22:05 -0400 |
commit | 41063e9dd11956f2d285e12e4342e1d232ba0ea2 (patch) | |
tree | d4df2f51044b4724a4767f0498c3df2f606b5ad7 /include | |
parent | f9242b6b28d61295f2bf7e8adfb1060b382e5381 (diff) |
ipv4: Early TCP socket demux.
Input packet processing for local sockets involves two major demuxes.
One for the route and one for the socket.
But we can optimize this down to one demux for certain kinds of local
sockets.
Currently we only do this for established TCP sockets, but it could
at least in theory be expanded to other kinds of connections.
If a TCP socket is established then it's identity is fully specified.
This means that whatever input route was used during the three-way
handshake must work equally well for the rest of the connection since
the keys will not change.
Once we move to established state, we cache the receive packet's input
route to use later.
Like the existing cached route in sk->sk_dst_cache used for output
packets, we have to check for route invalidations using dst->obsolete
and dst->ops->check().
Early demux occurs outside of a socket locked section, so when a route
invalidation occurs we defer the fixup of sk->sk_rx_dst until we are
actually inside of established state packet processing and thus have
the socket locked.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include')
-rw-r--r-- | include/net/inet_hashtables.h | 4 | ||||
-rw-r--r-- | include/net/protocol.h | 1 | ||||
-rw-r--r-- | include/net/sock.h | 2 | ||||
-rw-r--r-- | include/net/tcp.h | 1 |
4 files changed, 6 insertions, 2 deletions
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 808fc5f76b03..54be0287eb98 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h | |||
@@ -379,10 +379,10 @@ static inline struct sock *__inet_lookup_skb(struct inet_hashinfo *hashinfo, | |||
379 | const __be16 sport, | 379 | const __be16 sport, |
380 | const __be16 dport) | 380 | const __be16 dport) |
381 | { | 381 | { |
382 | struct sock *sk; | 382 | struct sock *sk = skb_steal_sock(skb); |
383 | const struct iphdr *iph = ip_hdr(skb); | 383 | const struct iphdr *iph = ip_hdr(skb); |
384 | 384 | ||
385 | if (unlikely(sk = skb_steal_sock(skb))) | 385 | if (sk) |
386 | return sk; | 386 | return sk; |
387 | else | 387 | else |
388 | return __inet_lookup(dev_net(skb_dst(skb)->dev), hashinfo, | 388 | return __inet_lookup(dev_net(skb_dst(skb)->dev), hashinfo, |
diff --git a/include/net/protocol.h b/include/net/protocol.h index a1b1b530c338..967b926cbfb1 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h | |||
@@ -37,6 +37,7 @@ | |||
37 | 37 | ||
38 | /* This is used to register protocols. */ | 38 | /* This is used to register protocols. */ |
39 | struct net_protocol { | 39 | struct net_protocol { |
40 | int (*early_demux)(struct sk_buff *skb); | ||
40 | int (*handler)(struct sk_buff *skb); | 41 | int (*handler)(struct sk_buff *skb); |
41 | void (*err_handler)(struct sk_buff *skb, u32 info); | 42 | void (*err_handler)(struct sk_buff *skb, u32 info); |
42 | int (*gso_send_check)(struct sk_buff *skb); | 43 | int (*gso_send_check)(struct sk_buff *skb); |
diff --git a/include/net/sock.h b/include/net/sock.h index 4a4521699563..87b424ae750a 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
@@ -319,6 +319,7 @@ struct sock { | |||
319 | unsigned long sk_flags; | 319 | unsigned long sk_flags; |
320 | struct dst_entry *sk_dst_cache; | 320 | struct dst_entry *sk_dst_cache; |
321 | spinlock_t sk_dst_lock; | 321 | spinlock_t sk_dst_lock; |
322 | struct dst_entry *sk_rx_dst; | ||
322 | atomic_t sk_wmem_alloc; | 323 | atomic_t sk_wmem_alloc; |
323 | atomic_t sk_omem_alloc; | 324 | atomic_t sk_omem_alloc; |
324 | int sk_sndbuf; | 325 | int sk_sndbuf; |
@@ -1426,6 +1427,7 @@ extern struct sk_buff *sock_rmalloc(struct sock *sk, | |||
1426 | gfp_t priority); | 1427 | gfp_t priority); |
1427 | extern void sock_wfree(struct sk_buff *skb); | 1428 | extern void sock_wfree(struct sk_buff *skb); |
1428 | extern void sock_rfree(struct sk_buff *skb); | 1429 | extern void sock_rfree(struct sk_buff *skb); |
1430 | extern void sock_edemux(struct sk_buff *skb); | ||
1429 | 1431 | ||
1430 | extern int sock_setsockopt(struct socket *sock, int level, | 1432 | extern int sock_setsockopt(struct socket *sock, int level, |
1431 | int op, char __user *optval, | 1433 | int op, char __user *optval, |
diff --git a/include/net/tcp.h b/include/net/tcp.h index 9332f342259a..6660ffc4963d 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -325,6 +325,7 @@ extern void tcp_v4_err(struct sk_buff *skb, u32); | |||
325 | 325 | ||
326 | extern void tcp_shutdown (struct sock *sk, int how); | 326 | extern void tcp_shutdown (struct sock *sk, int how); |
327 | 327 | ||
328 | extern int tcp_v4_early_demux(struct sk_buff *skb); | ||
328 | extern int tcp_v4_rcv(struct sk_buff *skb); | 329 | extern int tcp_v4_rcv(struct sk_buff *skb); |
329 | 330 | ||
330 | extern struct inet_peer *tcp_v4_get_peer(struct sock *sk); | 331 | extern struct inet_peer *tcp_v4_get_peer(struct sock *sk); |