Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 314519
b: refs/heads/master
c: 41063e9
h: refs/heads/master
i:
  314517: 7a5562d
  314515: 11d1b5f
  314511: 8e3a9a5
v: v3
  • Loading branch information
David S. Miller committed Jun 20, 2012
1 parent fcc6153 commit 7f9b2d9
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 25 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f9242b6b28d61295f2bf7e8adfb1060b382e5381
refs/heads/master: 41063e9dd11956f2d285e12e4342e1d232ba0ea2
4 changes: 2 additions & 2 deletions trunk/include/net/inet_hashtables.h
Original file line number Diff line number Diff line change
Expand Up @@ -379,10 +379,10 @@ static inline struct sock *__inet_lookup_skb(struct inet_hashinfo *hashinfo,
const __be16 sport,
const __be16 dport)
{
struct sock *sk;
struct sock *sk = skb_steal_sock(skb);
const struct iphdr *iph = ip_hdr(skb);

if (unlikely(sk = skb_steal_sock(skb)))
if (sk)
return sk;
else
return __inet_lookup(dev_net(skb_dst(skb)->dev), hashinfo,
Expand Down
1 change: 1 addition & 0 deletions trunk/include/net/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

/* This is used to register protocols. */
struct net_protocol {
int (*early_demux)(struct sk_buff *skb);
int (*handler)(struct sk_buff *skb);
void (*err_handler)(struct sk_buff *skb, u32 info);
int (*gso_send_check)(struct sk_buff *skb);
Expand Down
2 changes: 2 additions & 0 deletions trunk/include/net/sock.h
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ struct sock {
unsigned long sk_flags;
struct dst_entry *sk_dst_cache;
spinlock_t sk_dst_lock;
struct dst_entry *sk_rx_dst;
atomic_t sk_wmem_alloc;
atomic_t sk_omem_alloc;
int sk_sndbuf;
Expand Down Expand Up @@ -1426,6 +1427,7 @@ extern struct sk_buff *sock_rmalloc(struct sock *sk,
gfp_t priority);
extern void sock_wfree(struct sk_buff *skb);
extern void sock_rfree(struct sk_buff *skb);
extern void sock_edemux(struct sk_buff *skb);

extern int sock_setsockopt(struct socket *sock, int level,
int op, char __user *optval,
Expand Down
1 change: 1 addition & 0 deletions trunk/include/net/tcp.h
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ extern void tcp_v4_err(struct sk_buff *skb, u32);

extern void tcp_shutdown (struct sock *sk, int how);

extern int tcp_v4_early_demux(struct sk_buff *skb);
extern int tcp_v4_rcv(struct sk_buff *skb);

extern struct inet_peer *tcp_v4_get_peer(struct sock *sk);
Expand Down
5 changes: 5 additions & 0 deletions trunk/net/core/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -1465,6 +1465,11 @@ void sock_rfree(struct sk_buff *skb)
}
EXPORT_SYMBOL(sock_rfree);

void sock_edemux(struct sk_buff *skb)
{
sock_put(skb->sk);
}
EXPORT_SYMBOL(sock_edemux);

int sock_i_uid(struct sock *sk)
{
Expand Down
18 changes: 10 additions & 8 deletions trunk/net/ipv4/af_inet.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ void inet_sock_destruct(struct sock *sk)

kfree(rcu_dereference_protected(inet->inet_opt, 1));
dst_release(rcu_dereference_check(sk->sk_dst_cache, 1));
dst_release(sk->sk_rx_dst);
sk_refcnt_debug_dec(sk);
}
EXPORT_SYMBOL(inet_sock_destruct);
Expand Down Expand Up @@ -1518,14 +1519,15 @@ static const struct net_protocol igmp_protocol = {
#endif

static const struct net_protocol tcp_protocol = {
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
.gso_send_check = tcp_v4_gso_send_check,
.gso_segment = tcp_tso_segment,
.gro_receive = tcp4_gro_receive,
.gro_complete = tcp4_gro_complete,
.no_policy = 1,
.netns_ok = 1,
.early_demux = tcp_v4_early_demux,
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
.gso_send_check = tcp_v4_gso_send_check,
.gso_segment = tcp_tso_segment,
.gro_receive = tcp4_gro_receive,
.gro_complete = tcp4_gro_complete,
.no_policy = 1,
.netns_ok = 1,
};

static const struct net_protocol udp_protocol = {
Expand Down
39 changes: 26 additions & 13 deletions trunk/net/ipv4/ip_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,19 +323,32 @@ static int ip_rcv_finish(struct sk_buff *skb)
* how the packet travels inside Linux networking.
*/
if (skb_dst(skb) == NULL) {
int err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
iph->tos, skb->dev);
if (unlikely(err)) {
if (err == -EHOSTUNREACH)
IP_INC_STATS_BH(dev_net(skb->dev),
IPSTATS_MIB_INADDRERRORS);
else if (err == -ENETUNREACH)
IP_INC_STATS_BH(dev_net(skb->dev),
IPSTATS_MIB_INNOROUTES);
else if (err == -EXDEV)
NET_INC_STATS_BH(dev_net(skb->dev),
LINUX_MIB_IPRPFILTER);
goto drop;
const struct net_protocol *ipprot;
int protocol = iph->protocol;
int err;

rcu_read_lock();
ipprot = rcu_dereference(inet_protos[protocol]);
err = -ENOENT;
if (ipprot && ipprot->early_demux)
err = ipprot->early_demux(skb);
rcu_read_unlock();

if (err) {
err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
iph->tos, skb->dev);
if (unlikely(err)) {
if (err == -EHOSTUNREACH)
IP_INC_STATS_BH(dev_net(skb->dev),
IPSTATS_MIB_INADDRERRORS);
else if (err == -ENETUNREACH)
IP_INC_STATS_BH(dev_net(skb->dev),
IPSTATS_MIB_INNOROUTES);
else if (err == -EXDEV)
NET_INC_STATS_BH(dev_net(skb->dev),
LINUX_MIB_IPRPFILTER);
goto drop;
}
}
}

Expand Down
16 changes: 15 additions & 1 deletion trunk/net/ipv4/tcp_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -5518,6 +5518,18 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
struct tcp_sock *tp = tcp_sk(sk);
int res;

if (sk->sk_rx_dst) {
struct dst_entry *dst = sk->sk_rx_dst;
if (unlikely(dst->obsolete)) {
if (dst->ops->check(dst, 0) == NULL) {
dst_release(dst);
sk->sk_rx_dst = NULL;
}
}
}
if (unlikely(sk->sk_rx_dst == NULL))
sk->sk_rx_dst = dst_clone(skb_dst(skb));

/*
* Header prediction.
* The code loosely follows the one in the famous
Expand Down Expand Up @@ -5729,8 +5741,10 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)

tcp_set_state(sk, TCP_ESTABLISHED);

if (skb != NULL)
if (skb != NULL) {
sk->sk_rx_dst = dst_clone(skb_dst(skb));
security_inet_conn_established(sk, skb);
}

/* Make sure socket is routed, for correct metrics. */
icsk->icsk_af_ops->rebuild_header(sk);
Expand Down
46 changes: 46 additions & 0 deletions trunk/net/ipv4/tcp_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -1671,6 +1671,52 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
}
EXPORT_SYMBOL(tcp_v4_do_rcv);

int tcp_v4_early_demux(struct sk_buff *skb)
{
struct net *net = dev_net(skb->dev);
const struct iphdr *iph;
const struct tcphdr *th;
struct sock *sk;
int err;

err = -ENOENT;
if (skb->pkt_type != PACKET_HOST)
goto out_err;

if (!pskb_may_pull(skb, ip_hdrlen(skb) + sizeof(struct tcphdr)))
goto out_err;

iph = ip_hdr(skb);
th = (struct tcphdr *) ((char *)iph + ip_hdrlen(skb));

if (th->doff < sizeof(struct tcphdr) / 4)
goto out_err;

if (!pskb_may_pull(skb, ip_hdrlen(skb) + th->doff * 4))
goto out_err;

sk = __inet_lookup_established(net, &tcp_hashinfo,
iph->saddr, th->source,
iph->daddr, th->dest,
skb->dev->ifindex);
if (sk) {
skb->sk = sk;
skb->destructor = sock_edemux;
if (sk->sk_state != TCP_TIME_WAIT) {
struct dst_entry *dst = sk->sk_rx_dst;
if (dst)
dst = dst_check(dst, 0);
if (dst) {
skb_dst_set_noref(skb, dst);
err = 0;
}
}
}

out_err:
return err;
}

/*
* From tcp_input.c
*/
Expand Down
2 changes: 2 additions & 0 deletions trunk/net/ipv4/tcp_minisocks.c
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
struct tcp_sock *oldtp = tcp_sk(sk);
struct tcp_cookie_values *oldcvp = oldtp->cookie_values;

newsk->sk_rx_dst = dst_clone(skb_dst(skb));

/* TCP Cookie Transactions require space for the cookie pair,
* as it differs for each connection. There is no need to
* copy any s_data_payload stored at the original socket.
Expand Down

0 comments on commit 7f9b2d9

Please sign in to comment.