@@ -1324,6 +1324,18 @@ static inline void sk_change_net(struct sock *sk, struct net *net)
sock_net_set(sk, hold_net(net));
}
+static inline struct sock *sock_skb_steal(struct sk_buff *skb)
+{
+ if (unlikely(skb->sk)) {
+ struct sock *sk = skb->sk;
+
+ skb->destructor = NULL;
+ skb->sk = NULL;
+ return sk;
+ }
+ return NULL;
+}
+
extern void sock_enable_timestamp(struct sock *sk);
extern int sock_get_timestamp(struct sock *, struct timeval __user *);
extern int sock_get_timestampns(struct sock *, struct timespec __user *);
@@ -811,9 +811,10 @@ static int dccp_v4_rcv(struct sk_buff *skb)
/* Step 2:
* Look up flow ID in table and get corresponding socket */
- sk = __inet_lookup(dev_net(skb->dst->dev), &dccp_hashinfo,
- iph->saddr, dh->dccph_sport,
- iph->daddr, dh->dccph_dport, inet_iif(skb));
+ if (likely((sk = sock_skb_steal(skb)) == NULL))
+ sk = __inet_lookup(dev_net(skb->dst->dev), &dccp_hashinfo,
+ iph->saddr, dh->dccph_sport,
+ iph->daddr, dh->dccph_dport, inet_iif(skb));
/*
* Step 2:
* If no socket ...
@@ -805,10 +805,11 @@ static int dccp_v6_rcv(struct sk_buff *skb)
/* Step 2:
* Look up flow ID in table and get corresponding socket */
- sk = __inet6_lookup(dev_net(skb->dst->dev), &dccp_hashinfo,
- &ipv6_hdr(skb)->saddr, dh->dccph_sport,
- &ipv6_hdr(skb)->daddr, ntohs(dh->dccph_dport),
- inet6_iif(skb));
+ if (likely((sk = sock_skb_steal(skb)) == NULL))
+ sk = __inet6_lookup(dev_net(skb->dst->dev), &dccp_hashinfo,
+ &ipv6_hdr(skb)->saddr, dh->dccph_sport,
+ &ipv6_hdr(skb)->daddr, ntohs(dh->dccph_dport),
+ inet6_iif(skb));
/*
* Step 2:
* If no socket ...
@@ -1577,8 +1577,10 @@ int tcp_v4_rcv(struct sk_buff *skb)
TCP_SKB_CB(skb)->flags = iph->tos;
TCP_SKB_CB(skb)->sacked = 0;
- sk = __inet_lookup(net, &tcp_hashinfo, iph->saddr,
- th->source, iph->daddr, th->dest, inet_iif(skb));
+ if (likely((sk = sock_skb_steal(skb)) == NULL))
+ sk = __inet_lookup(net, &tcp_hashinfo, iph->saddr,
+ th->source, iph->daddr, th->dest, inet_iif(skb));
+
if (!sk)
goto no_tcp_socket;
@@ -1198,8 +1198,9 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
return __udp4_lib_mcast_deliver(net, skb, uh,
saddr, daddr, udptable);
- sk = __udp4_lib_lookup(net, saddr, uh->source, daddr,
- uh->dest, inet_iif(skb), udptable);
+ if (likely((sk = sock_skb_steal(skb)) == NULL))
+ sk = __udp4_lib_lookup(net, saddr, uh->source, daddr,
+ uh->dest, inet_iif(skb), udptable);
if (sk != NULL) {
int ret = 0;
@@ -1681,10 +1681,11 @@ static int tcp_v6_rcv(struct sk_buff *skb)
TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb));
TCP_SKB_CB(skb)->sacked = 0;
- sk = __inet6_lookup(net, &tcp_hashinfo,
- &ipv6_hdr(skb)->saddr, th->source,
- &ipv6_hdr(skb)->daddr, ntohs(th->dest),
- inet6_iif(skb));
+ if (likely((sk = sock_skb_steal(skb)) == NULL))
+ sk = __inet6_lookup(net, &tcp_hashinfo,
+ &ipv6_hdr(skb)->saddr, th->source,
+ &ipv6_hdr(skb)->daddr, ntohs(th->dest),
+ inet6_iif(skb));
if (!sk)
goto no_tcp_socket;
@@ -488,8 +488,9 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
* check socket cache ... must talk to Alan about his plans
* for sock caches... i'll skip this for now.
*/
- sk = __udp6_lib_lookup(net, saddr, uh->source,
- daddr, uh->dest, inet6_iif(skb), udptable);
+ if (likely((sk = sock_skb_steal(skb)) == NULL))
+ sk = __udp6_lib_lookup(net, saddr, uh->source,
+ daddr, uh->dest, inet6_iif(skb), udptable);
if (sk == NULL) {
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))