From dec18810c52ed564c1aedc7f93dbf278b7fdf6d5 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 14 Oct 2007 00:37:30 -0700 Subject: [SKBUFF]: Merge common code between copy_skb_header and skb_clone This patch creates a new function __copy_skb_header to merge the common code between copy_skb_header and skb_clone. Having two functions which are largely the same is a source of wasted labour as well as confusion. In fact the tc_verd stuff is almost certainly a bug since it's treated differently in skb_clone compared to the callers of copy_skb_header (skb_copy/pskb_copy/skb_copy_expand). I've kept that difference in tact with a comment added asking for clarification. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/core/skbuff.c | 116 +++++++++++++++++++++--------------------------------- 1 file changed, 45 insertions(+), 71 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 944189d9632..758bbef506d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -362,6 +362,44 @@ void kfree_skb(struct sk_buff *skb) __kfree_skb(skb); } +static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) +{ + new->tstamp = old->tstamp; + new->dev = old->dev; + new->transport_header = old->transport_header; + new->network_header = old->network_header; + new->mac_header = old->mac_header; + new->dst = dst_clone(old->dst); +#ifdef CONFIG_INET + new->sp = secpath_get(old->sp); +#endif + memcpy(new->cb, old->cb, sizeof(old->cb)); + new->csum_start = old->csum_start; + new->csum_offset = old->csum_offset; + new->local_df = old->local_df; + new->pkt_type = old->pkt_type; + new->ip_summed = old->ip_summed; + skb_copy_queue_mapping(new, old); + new->priority = old->priority; +#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) + new->ipvs_property = old->ipvs_property; +#endif + new->protocol = old->protocol; + new->mark = old->mark; + __nf_copy(new, old); +#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ + defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) + new->nf_trace = old->nf_trace; +#endif +#ifdef CONFIG_NET_SCHED + new->tc_index = old->tc_index; +#ifdef CONFIG_NET_CLS_ACT + new->tc_verd = old->tc_verd; +#endif +#endif + skb_copy_secmark(new, old); +} + /** * skb_clone - duplicate an sk_buff * @skb: buffer to clone @@ -397,51 +435,22 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) n->next = n->prev = NULL; n->sk = NULL; - C(tstamp); - C(dev); - C(transport_header); - C(network_header); - C(mac_header); - C(dst); - dst_clone(skb->dst); - C(sp); -#ifdef CONFIG_INET - secpath_get(skb->sp); -#endif - memcpy(n->cb, skb->cb, sizeof(skb->cb)); + __copy_skb_header(n, skb); + C(len); C(data_len); C(mac_len); - C(csum); - C(local_df); n->cloned = 1; n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len; n->nohdr = 0; - C(pkt_type); - C(ip_summed); - skb_copy_queue_mapping(n, skb); - C(priority); -#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) - C(ipvs_property); -#endif - C(protocol); n->destructor = NULL; - C(mark); - __nf_copy(n, skb); -#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ - defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) - C(nf_trace); -#endif -#ifdef CONFIG_NET_SCHED - C(tc_index); #ifdef CONFIG_NET_CLS_ACT - n->tc_verd = SET_TC_VERD(skb->tc_verd,0); + /* FIXME What is this and why don't we do it in copy_skb_header? */ + n->tc_verd = SET_TC_VERD(n->tc_verd,0); n->tc_verd = CLR_TC_OK2MUNGE(n->tc_verd); n->tc_verd = CLR_TC_MUNGED(n->tc_verd); C(iif); #endif -#endif - skb_copy_secmark(n, skb); C(truesize); atomic_set(&n->users, 1); C(head); @@ -463,50 +472,15 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) */ unsigned long offset = new->data - old->data; #endif - new->sk = NULL; - new->dev = old->dev; - skb_copy_queue_mapping(new, old); - new->priority = old->priority; - new->protocol = old->protocol; - new->dst = dst_clone(old->dst); -#ifdef CONFIG_INET - new->sp = secpath_get(old->sp); -#endif - new->csum_start = old->csum_start; - new->csum_offset = old->csum_offset; - new->ip_summed = old->ip_summed; - new->transport_header = old->transport_header; - new->network_header = old->network_header; - new->mac_header = old->mac_header; + + __copy_skb_header(new, old); + #ifndef NET_SKBUFF_DATA_USES_OFFSET /* {transport,network,mac}_header are relative to skb->head */ new->transport_header += offset; new->network_header += offset; new->mac_header += offset; #endif - memcpy(new->cb, old->cb, sizeof(old->cb)); - new->local_df = old->local_df; - new->fclone = SKB_FCLONE_UNAVAILABLE; - new->pkt_type = old->pkt_type; - new->tstamp = old->tstamp; - new->destructor = NULL; - new->mark = old->mark; - __nf_copy(new, old); -#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \ - defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) - new->nf_trace = old->nf_trace; -#endif -#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE) - new->ipvs_property = old->ipvs_property; -#endif -#ifdef CONFIG_NET_SCHED -#ifdef CONFIG_NET_CLS_ACT - new->tc_verd = old->tc_verd; -#endif - new->tc_index = old->tc_index; -#endif - skb_copy_secmark(new, old); - atomic_set(&new->users, 1); skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size; skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs; skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type; -- cgit v1.2.3-18-g5258 From e0053ec07e32ec94535c47b10af3377255f00836 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 14 Oct 2007 00:37:52 -0700 Subject: [SKBUFF]: Add skb_morph This patch creates a new function skb_morph that's just like skb_clone except that it lets user provide the spare skb that will be overwritten by the one that's to be cloned. This will be used by IP fragment reassembly so that we get back the same skb that went in last (rather than the head skb that we get now which requires us to carry around double pointers all over the place). Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/skbuff.h | 1 + net/core/skbuff.c | 83 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 54 insertions(+), 30 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index a656cecd373..be5bf0b4151 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -357,6 +357,7 @@ static inline struct sk_buff *alloc_skb_fclone(unsigned int size, } extern void kfree_skbmem(struct sk_buff *skb); +extern struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src); extern struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t priority); extern struct sk_buff *skb_copy(const struct sk_buff *skb, diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 758bbef506d..c3aa68ceed6 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -400,37 +400,8 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) skb_copy_secmark(new, old); } -/** - * skb_clone - duplicate an sk_buff - * @skb: buffer to clone - * @gfp_mask: allocation priority - * - * Duplicate an &sk_buff. The new one is not owned by a socket. Both - * copies share the same packet data but not structure. The new - * buffer has a reference count of 1. If the allocation fails the - * function returns %NULL otherwise the new buffer is returned. - * - * If this function is called from an interrupt gfp_mask() must be - * %GFP_ATOMIC. - */ - -struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) +static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb) { - struct sk_buff *n; - - n = skb + 1; - if (skb->fclone == SKB_FCLONE_ORIG && - n->fclone == SKB_FCLONE_UNAVAILABLE) { - atomic_t *fclone_ref = (atomic_t *) (n + 1); - n->fclone = SKB_FCLONE_CLONE; - atomic_inc(fclone_ref); - } else { - n = kmem_cache_alloc(skbuff_head_cache, gfp_mask); - if (!n) - return NULL; - n->fclone = SKB_FCLONE_UNAVAILABLE; - } - #define C(x) n->x = skb->x n->next = n->prev = NULL; @@ -462,6 +433,58 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) skb->cloned = 1; return n; +#undef C +} + +/** + * skb_morph - morph one skb into another + * @dst: the skb to receive the contents + * @src: the skb to supply the contents + * + * This is identical to skb_clone except that the target skb is + * supplied by the user. + * + * The target skb is returned upon exit. + */ +struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src) +{ + skb_release_data(dst); + return __skb_clone(dst, src); +} +EXPORT_SYMBOL_GPL(skb_morph); + +/** + * skb_clone - duplicate an sk_buff + * @skb: buffer to clone + * @gfp_mask: allocation priority + * + * Duplicate an &sk_buff. The new one is not owned by a socket. Both + * copies share the same packet data but not structure. The new + * buffer has a reference count of 1. If the allocation fails the + * function returns %NULL otherwise the new buffer is returned. + * + * If this function is called from an interrupt gfp_mask() must be + * %GFP_ATOMIC. + */ + +struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) +{ + struct sk_buff *n; + + n = skb + 1; + if (skb->fclone == SKB_FCLONE_ORIG && + n->fclone == SKB_FCLONE_UNAVAILABLE) { + atomic_t *fclone_ref = (atomic_t *) (n + 1); + n->fclone = SKB_FCLONE_CLONE; + atomic_inc(fclone_ref); + } else { + n = kmem_cache_alloc(skbuff_head_cache, gfp_mask); + if (!n) + return NULL; + n->fclone = SKB_FCLONE_UNAVAILABLE; + } + + return __skb_clone(n, skb); } static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) -- cgit v1.2.3-18-g5258 From 1706d58763c36133d7fce6cc78b1444fd40db28c Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 14 Oct 2007 00:38:15 -0700 Subject: [IPV4]: Make ip_defrag return the same packet This patch is a bit of a hack. However it is worth it if you consider that this is the only reason why we have to carry around the struct sk_buff ** pointers in netfilter. It makes ip_defrag always return the packet that was given to it on input. It does this by cloning the packet and replacing its original contents with the head fragment if necessary. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/ip_fragment.c | 76 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 21 deletions(-) diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index fabb86db763..d7fa2bf3a0c 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -109,6 +109,9 @@ static u32 ipfrag_hash_rnd; static LIST_HEAD(ipq_lru_list); int ip_frag_nqueues = 0; +static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, + struct net_device *dev); + static __inline__ void __ipq_unlink(struct ipq *qp) { hlist_del(&qp->list); @@ -464,17 +467,20 @@ static int ip_frag_reinit(struct ipq *qp) } /* Add new segment to existing queue. */ -static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb) +static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) { struct sk_buff *prev, *next; + struct net_device *dev; int flags, offset; int ihl, end; + int err = -ENOENT; if (qp->last_in & COMPLETE) goto err; if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) && - unlikely(ip_frag_too_far(qp)) && unlikely(ip_frag_reinit(qp))) { + unlikely(ip_frag_too_far(qp)) && + unlikely(err = ip_frag_reinit(qp))) { ipq_kill(qp); goto err; } @@ -487,6 +493,7 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb) /* Determine the position of this fragment. */ end = offset + skb->len - ihl; + err = -EINVAL; /* Is this the final fragment? */ if ((flags & IP_MF) == 0) { @@ -514,9 +521,12 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb) if (end == offset) goto err; + err = -ENOMEM; if (pskb_pull(skb, ihl) == NULL) goto err; - if (pskb_trim_rcsum(skb, end-offset)) + + err = pskb_trim_rcsum(skb, end - offset); + if (err) goto err; /* Find out which fragments are in front and at the back of us @@ -539,8 +549,10 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb) if (i > 0) { offset += i; + err = -EINVAL; if (end <= offset) goto err; + err = -ENOMEM; if (!pskb_pull(skb, i)) goto err; if (skb->ip_summed != CHECKSUM_UNNECESSARY) @@ -548,6 +560,8 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb) } } + err = -ENOMEM; + while (next && FRAG_CB(next)->offset < end) { int i = end - FRAG_CB(next)->offset; /* overlap is 'i' bytes */ @@ -589,37 +603,62 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb) else qp->fragments = skb; - if (skb->dev) - qp->iif = skb->dev->ifindex; - skb->dev = NULL; + dev = skb->dev; + if (dev) { + qp->iif = dev->ifindex; + skb->dev = NULL; + } qp->stamp = skb->tstamp; qp->meat += skb->len; atomic_add(skb->truesize, &ip_frag_mem); if (offset == 0) qp->last_in |= FIRST_IN; + if (qp->last_in == (FIRST_IN | LAST_IN) && qp->meat == qp->len) + return ip_frag_reasm(qp, prev, dev); + write_lock(&ipfrag_lock); list_move_tail(&qp->lru_list, &ipq_lru_list); write_unlock(&ipfrag_lock); - - return; + return -EINPROGRESS; err: kfree_skb(skb); + return err; } /* Build a new IP datagram from all its fragments. */ -static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev) +static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, + struct net_device *dev) { struct iphdr *iph; struct sk_buff *fp, *head = qp->fragments; int len; int ihlen; + int err; ipq_kill(qp); + /* Make the one we just received the head. */ + if (prev) { + head = prev->next; + fp = skb_clone(head, GFP_ATOMIC); + + if (!fp) + goto out_nomem; + + fp->next = head->next; + prev->next = fp; + + skb_morph(head, qp->fragments); + head->next = qp->fragments->next; + + kfree_skb(qp->fragments); + qp->fragments = head; + } + BUG_TRAP(head != NULL); BUG_TRAP(FRAG_CB(head)->offset == 0); @@ -627,10 +666,12 @@ static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev) ihlen = ip_hdrlen(head); len = ihlen + qp->len; + err = -E2BIG; if (len > 65535) goto out_oversize; /* Head of list must not be cloned. */ + err = -ENOMEM; if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) goto out_nomem; @@ -681,7 +722,7 @@ static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev) iph->tot_len = htons(len); IP_INC_STATS_BH(IPSTATS_MIB_REASMOKS); qp->fragments = NULL; - return head; + return 0; out_nomem: LIMIT_NETDEBUG(KERN_ERR "IP: queue_glue: no memory for gluing " @@ -694,14 +735,13 @@ out_oversize: NIPQUAD(qp->saddr)); out_fail: IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); - return NULL; + return err; } /* Process an incoming IP datagram fragment. */ struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user) { struct ipq *qp; - struct net_device *dev; IP_INC_STATS_BH(IPSTATS_MIB_REASMREQDS); @@ -709,23 +749,17 @@ struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user) if (atomic_read(&ip_frag_mem) > sysctl_ipfrag_high_thresh) ip_evictor(); - dev = skb->dev; - /* Lookup (or create) queue header */ if ((qp = ip_find(ip_hdr(skb), user)) != NULL) { - struct sk_buff *ret = NULL; + int ret; spin_lock(&qp->lock); - ip_frag_queue(qp, skb); - - if (qp->last_in == (FIRST_IN|LAST_IN) && - qp->meat == qp->len) - ret = ip_frag_reasm(qp, dev); + ret = ip_frag_queue(qp, skb); spin_unlock(&qp->lock); ipq_put(qp, NULL); - return ret; + return ret ? NULL : skb; } IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); -- cgit v1.2.3-18-g5258 From 776c729e8d91b2740583a2169678f2d3f383458b Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 14 Oct 2007 00:38:32 -0700 Subject: [IPV4]: Change ip_defrag to return an integer Now that ip_frag always returns the packet given to it on input, we can change it to return an integer indicating error instead. This patch does that and updates all its callers accordingly. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/ip.h | 2 +- net/ipv4/ip_fragment.c | 6 +++--- net/ipv4/ip_input.c | 6 ++---- net/ipv4/ipvs/ip_vs_core.c | 26 ++++++++++---------------- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 20 ++++++++++---------- 5 files changed, 26 insertions(+), 34 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index 3af3ed9d320..875c5ed5334 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -332,7 +332,7 @@ enum ip_defrag_users IP_DEFRAG_VS_FWD }; -struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user); +int ip_defrag(struct sk_buff *skb, u32 user); extern int ip_frag_nqueues; extern atomic_t ip_frag_mem; diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index d7fa2bf3a0c..32108cf2a78 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -739,7 +739,7 @@ out_fail: } /* Process an incoming IP datagram fragment. */ -struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user) +int ip_defrag(struct sk_buff *skb, u32 user) { struct ipq *qp; @@ -759,12 +759,12 @@ struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user) spin_unlock(&qp->lock); ipq_put(qp, NULL); - return ret ? NULL : skb; + return ret; } IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); kfree_skb(skb); - return NULL; + return -ENOMEM; } void __init ipfrag_init(void) diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 41d8964591e..8f75e43ad3b 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -172,8 +172,7 @@ int ip_call_ra_chain(struct sk_buff *skb) (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == skb->dev->ifindex)) { if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { - skb = ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN); - if (skb == NULL) { + if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN)) { read_unlock(&ip_ra_lock); return 1; } @@ -265,8 +264,7 @@ int ip_local_deliver(struct sk_buff *skb) */ if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { - skb = ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER); - if (!skb) + if (ip_defrag(skb, IP_DEFRAG_LOCAL_DELIVER)) return 0; } diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index fbca2a2ff29..3487337192c 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c @@ -541,13 +541,14 @@ __sum16 ip_vs_checksum_complete(struct sk_buff *skb, int offset) return csum_fold(skb_checksum(skb, offset, skb->len - offset, 0)); } -static inline struct sk_buff * -ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user) +static inline int ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user) { - skb = ip_defrag(skb, user); - if (skb) + int err = ip_defrag(skb, user); + + if (!err) ip_send_check(ip_hdr(skb)); - return skb; + + return err; } /* @@ -619,10 +620,8 @@ static int ip_vs_out_icmp(struct sk_buff **pskb, int *related) /* reassemble IP fragments */ if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { - skb = ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT); - if (!skb) + if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT)) return NF_STOLEN; - *pskb = skb; } iph = ip_hdr(skb); @@ -756,11 +755,9 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb, /* reassemble IP fragments */ if (unlikely(iph->frag_off & htons(IP_MF|IP_OFFSET) && !pp->dont_defrag)) { - skb = ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT); - if (!skb) + if (ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT)) return NF_STOLEN; iph = ip_hdr(skb); - *pskb = skb; } ihl = iph->ihl << 2; @@ -861,12 +858,9 @@ ip_vs_in_icmp(struct sk_buff **pskb, int *related, unsigned int hooknum) /* reassemble IP fragments */ if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { - skb = ip_vs_gather_frags(skb, - hooknum == NF_IP_LOCAL_IN ? - IP_DEFRAG_VS_IN : IP_DEFRAG_VS_FWD); - if (!skb) + if (ip_vs_gather_frags(skb, hooknum == NF_IP_LOCAL_IN ? + IP_DEFRAG_VS_IN : IP_DEFRAG_VS_FWD)) return NF_STOLEN; - *pskb = skb; } iph = ip_hdr(skb); diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 2fcb9249a8d..48fdd9eb1c7 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -63,19 +63,20 @@ static int ipv4_print_conntrack(struct seq_file *s, } /* Returns new sk_buff, or NULL */ -static struct sk_buff * -nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user) +static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user) { + int err; + skb_orphan(skb); local_bh_disable(); - skb = ip_defrag(skb, user); + err = ip_defrag(skb, user); local_bh_enable(); - if (skb) + if (!err) ip_send_check(ip_hdr(skb)); - return skb; + return err; } static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff, @@ -148,11 +149,10 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, /* Gather fragments. */ if (ip_hdr(*pskb)->frag_off & htons(IP_MF | IP_OFFSET)) { - *pskb = nf_ct_ipv4_gather_frags(*pskb, - hooknum == NF_IP_PRE_ROUTING ? - IP_DEFRAG_CONNTRACK_IN : - IP_DEFRAG_CONNTRACK_OUT); - if (!*pskb) + if (nf_ct_ipv4_gather_frags(*pskb, + hooknum == NF_IP_PRE_ROUTING ? + IP_DEFRAG_CONNTRACK_IN : + IP_DEFRAG_CONNTRACK_OUT)) return NF_STOLEN; } return NF_ACCEPT; -- cgit v1.2.3-18-g5258 From f697c3e8b35c18b2698d64137c0fa84b0cdb3d10 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 14 Oct 2007 00:38:47 -0700 Subject: [NET]: Avoid unnecessary cloning for ingress filtering As it is we always invoke pt_prev before ing_filter, even if there are no ingress filters attached. This can cause unnecessary cloning in pt_prev. This patch changes it so that we only invoke pt_prev if there are ingress filters attached. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/core/dev.c | 68 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 99b7bda37d1..39aba4862f2 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1949,27 +1949,51 @@ static int ing_filter(struct sk_buff *skb) struct Qdisc *q; struct net_device *dev = skb->dev; int result = TC_ACT_OK; + u32 ttl = G_TC_RTTL(skb->tc_verd); - if (dev->qdisc_ingress) { - __u32 ttl = (__u32) G_TC_RTTL(skb->tc_verd); - if (MAX_RED_LOOP < ttl++) { - printk(KERN_WARNING "Redir loop detected Dropping packet (%d->%d)\n", - skb->iif, skb->dev->ifindex); - return TC_ACT_SHOT; - } + if (MAX_RED_LOOP < ttl++) { + printk(KERN_WARNING + "Redir loop detected Dropping packet (%d->%d)\n", + skb->iif, dev->ifindex); + return TC_ACT_SHOT; + } - skb->tc_verd = SET_TC_RTTL(skb->tc_verd,ttl); + skb->tc_verd = SET_TC_RTTL(skb->tc_verd, ttl); + skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS); - skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_INGRESS); + spin_lock(&dev->ingress_lock); + if ((q = dev->qdisc_ingress) != NULL) + result = q->enqueue(skb, q); + spin_unlock(&dev->ingress_lock); + + return result; +} - spin_lock(&dev->ingress_lock); - if ((q = dev->qdisc_ingress) != NULL) - result = q->enqueue(skb, q); - spin_unlock(&dev->ingress_lock); +static inline struct sk_buff *handle_ing(struct sk_buff *skb, + struct packet_type **pt_prev, + int *ret, struct net_device *orig_dev) +{ + if (!skb->dev->qdisc_ingress) + goto out; + if (*pt_prev) { + *ret = deliver_skb(skb, *pt_prev, orig_dev); + *pt_prev = NULL; + } else { + /* Huh? Why does turning on AF_PACKET affect this? */ + skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd); } - return result; + switch (ing_filter(skb)) { + case TC_ACT_SHOT: + case TC_ACT_STOLEN: + kfree_skb(skb); + return NULL; + } + +out: + skb->tc_verd = 0; + return skb; } #endif @@ -2021,21 +2045,9 @@ int netif_receive_skb(struct sk_buff *skb) } #ifdef CONFIG_NET_CLS_ACT - if (pt_prev) { - ret = deliver_skb(skb, pt_prev, orig_dev); - pt_prev = NULL; /* noone else should process this after*/ - } else { - skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd); - } - - ret = ing_filter(skb); - - if (ret == TC_ACT_SHOT || (ret == TC_ACT_STOLEN)) { - kfree_skb(skb); + skb = handle_ing(skb, &pt_prev, &ret, orig_dev); + if (!skb) goto out; - } - - skb->tc_verd = 0; ncls: #endif -- cgit v1.2.3-18-g5258 From 7b995651e373d6424f81db23f2ec503306dfd7f0 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 14 Oct 2007 00:39:01 -0700 Subject: [BRIDGE]: Unshare skb upon entry Due to the special location of the bridging hook, it should never see a shared packet anyway (certainly not with any in-kernel code). So it makes sense to unshare the skb there if necessary as that will greatly simplify the code below it (in particular, netfilter). Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/bridge/br_input.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 3a8a015c92e..f8e0a2fa796 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -126,6 +126,10 @@ struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb) if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) goto drop; + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + return NULL; + if (unlikely(is_link_local(dest))) { /* Pause frames shouldn't be passed up by driver anyway */ if (skb->protocol == htons(ETH_P_PAUSE)) -- cgit v1.2.3-18-g5258 From 37d41879224108d6c24578ba6a3eeafce106ce84 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 14 Oct 2007 00:39:18 -0700 Subject: [NETFILTER]: Do not copy skb in skb_make_writable Now that all callers of netfilter can guarantee that the skb is not shared, we no longer have to copy the skb in skb_make_writable. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/netfilter.h | 2 +- net/ipv4/netfilter/ip_queue.c | 2 +- net/ipv4/netfilter/ipt_ECN.c | 4 ++-- net/ipv4/netfilter/ipt_TOS.c | 2 +- net/ipv4/netfilter/ipt_TTL.c | 2 +- net/ipv4/netfilter/nf_nat_core.c | 4 ++-- net/ipv4/netfilter/nf_nat_helper.c | 8 +++---- net/ipv4/netfilter/nf_nat_proto_gre.c | 2 +- net/ipv4/netfilter/nf_nat_proto_icmp.c | 2 +- net/ipv4/netfilter/nf_nat_proto_tcp.c | 2 +- net/ipv4/netfilter/nf_nat_proto_udp.c | 2 +- net/ipv4/netfilter/nf_nat_snmp_basic.c | 2 +- net/ipv6/netfilter/ip6_queue.c | 2 +- net/ipv6/netfilter/ip6t_HL.c | 2 +- net/netfilter/core.c | 38 +++++++++++++--------------------- net/netfilter/nfnetlink_queue.c | 2 +- net/netfilter/xt_DSCP.c | 4 ++-- net/netfilter/xt_TCPMSS.c | 2 +- 18 files changed, 37 insertions(+), 47 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 1dd075eda59..2505348c98b 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -287,7 +287,7 @@ extern void nf_invalidate_cache(int pf); /* Call this before modifying an existing packet: ensures it is modifiable and linear to the point you care about (writable_len). Returns true or false. */ -extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len); +extern int skb_make_writable(struct sk_buff *skb, unsigned int writable_len); static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to) { diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 23cbfc7c80f..62d8867ca7d 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -365,7 +365,7 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) } skb_put(e->skb, diff); } - if (!skb_make_writable(&e->skb, v->data_len)) + if (!skb_make_writable(e->skb, v->data_len)) return -ENOMEM; skb_copy_to_linear_data(e->skb, v->payload, v->data_len); e->skb->ip_summed = CHECKSUM_NONE; diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index f1253bd3837..92744be1c55 100644 --- a/net/ipv4/netfilter/ipt_ECN.c +++ b/net/ipv4/netfilter/ipt_ECN.c @@ -32,7 +32,7 @@ set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) { __u8 oldtos; - if (!skb_make_writable(pskb, sizeof(struct iphdr))) + if (!skb_make_writable(*pskb, sizeof(struct iphdr))) return false; iph = ip_hdr(*pskb); oldtos = iph->tos; @@ -62,7 +62,7 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo) tcph->cwr == einfo->proto.tcp.cwr)) return true; - if (!skb_make_writable(pskb, ip_hdrlen(*pskb) + sizeof(*tcph))) + if (!skb_make_writable(*pskb, ip_hdrlen(*pskb) + sizeof(*tcph))) return false; tcph = (void *)ip_hdr(*pskb) + ip_hdrlen(*pskb); diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c index 25f5d0b3906..87b689ac09a 100644 --- a/net/ipv4/netfilter/ipt_TOS.c +++ b/net/ipv4/netfilter/ipt_TOS.c @@ -33,7 +33,7 @@ target(struct sk_buff **pskb, if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) { __u8 oldtos; - if (!skb_make_writable(pskb, sizeof(struct iphdr))) + if (!skb_make_writable(*pskb, sizeof(struct iphdr))) return NF_DROP; iph = ip_hdr(*pskb); oldtos = iph->tos; diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c index 2b54e7b0cfe..3dd467611e1 100644 --- a/net/ipv4/netfilter/ipt_TTL.c +++ b/net/ipv4/netfilter/ipt_TTL.c @@ -29,7 +29,7 @@ ipt_ttl_target(struct sk_buff **pskb, const struct ipt_TTL_info *info = targinfo; int new_ttl; - if (!skb_make_writable(pskb, (*pskb)->len)) + if (!skb_make_writable(*pskb, (*pskb)->len)) return NF_DROP; iph = ip_hdr(*pskb); diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index 7221aa20e6f..3b5eb7c1a13 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -357,7 +357,7 @@ manip_pkt(u_int16_t proto, struct iphdr *iph; struct nf_nat_protocol *p; - if (!skb_make_writable(pskb, iphdroff + sizeof(*iph))) + if (!skb_make_writable(*pskb, iphdroff + sizeof(*iph))) return 0; iph = (void *)(*pskb)->data + iphdroff; @@ -431,7 +431,7 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct, unsigned long statusbit; enum nf_nat_manip_type manip = HOOK2MANIP(hooknum); - if (!skb_make_writable(pskb, hdrlen + sizeof(*inside))) + if (!skb_make_writable(*pskb, hdrlen + sizeof(*inside))) return 0; inside = (void *)(*pskb)->data + ip_hdrlen(*pskb); diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index 93d8a0a8f03..6e81f7612b7 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -152,7 +152,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb, struct tcphdr *tcph; int oldlen, datalen; - if (!skb_make_writable(pskb, (*pskb)->len)) + if (!skb_make_writable(*pskb, (*pskb)->len)) return 0; if (rep_len > match_len && @@ -234,7 +234,7 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb, match_offset + match_len) return 0; - if (!skb_make_writable(pskb, (*pskb)->len)) + if (!skb_make_writable(*pskb, (*pskb)->len)) return 0; if (rep_len > match_len && @@ -341,7 +341,7 @@ nf_nat_sack_adjust(struct sk_buff **pskb, optoff = ip_hdrlen(*pskb) + sizeof(struct tcphdr); optend = ip_hdrlen(*pskb) + tcph->doff * 4; - if (!skb_make_writable(pskb, optend)) + if (!skb_make_writable(*pskb, optend)) return 0; dir = CTINFO2DIR(ctinfo); @@ -390,7 +390,7 @@ nf_nat_seq_adjust(struct sk_buff **pskb, this_way = &nat->seq[dir]; other_way = &nat->seq[!dir]; - if (!skb_make_writable(pskb, ip_hdrlen(*pskb) + sizeof(*tcph))) + if (!skb_make_writable(*pskb, ip_hdrlen(*pskb) + sizeof(*tcph))) return 0; tcph = (void *)(*pskb)->data + ip_hdrlen(*pskb); diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c index d562290b182..e7a2aafcce5 100644 --- a/net/ipv4/netfilter/nf_nat_proto_gre.c +++ b/net/ipv4/netfilter/nf_nat_proto_gre.c @@ -109,7 +109,7 @@ gre_manip_pkt(struct sk_buff **pskb, unsigned int iphdroff, /* pgreh includes two optional 32bit fields which are not required * to be there. That's where the magic '8' comes from */ - if (!skb_make_writable(pskb, hdroff + sizeof(*pgreh) - 8)) + if (!skb_make_writable(*pskb, hdroff + sizeof(*pgreh) - 8)) return 0; greh = (void *)(*pskb)->data + hdroff; diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c index 898d7377115..4087f4f42c3 100644 --- a/net/ipv4/netfilter/nf_nat_proto_icmp.c +++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c @@ -61,7 +61,7 @@ icmp_manip_pkt(struct sk_buff **pskb, struct icmphdr *hdr; unsigned int hdroff = iphdroff + iph->ihl*4; - if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) + if (!skb_make_writable(*pskb, hdroff + sizeof(*hdr))) return 0; hdr = (struct icmphdr *)((*pskb)->data + hdroff); diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c index 5bbbb2acdc7..e544125dc03 100644 --- a/net/ipv4/netfilter/nf_nat_proto_tcp.c +++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c @@ -106,7 +106,7 @@ tcp_manip_pkt(struct sk_buff **pskb, if ((*pskb)->len >= hdroff + sizeof(struct tcphdr)) hdrsize = sizeof(struct tcphdr); - if (!skb_make_writable(pskb, hdroff + hdrsize)) + if (!skb_make_writable(*pskb, hdroff + hdrsize)) return 0; iph = (struct iphdr *)((*pskb)->data + iphdroff); diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c index a0af4fd9558..ebe9b42a8e9 100644 --- a/net/ipv4/netfilter/nf_nat_proto_udp.c +++ b/net/ipv4/netfilter/nf_nat_proto_udp.c @@ -97,7 +97,7 @@ udp_manip_pkt(struct sk_buff **pskb, __be32 oldip, newip; __be16 *portptr, newport; - if (!skb_make_writable(pskb, hdroff + sizeof(*hdr))) + if (!skb_make_writable(*pskb, hdroff + sizeof(*hdr))) return 0; iph = (struct iphdr *)((*pskb)->data + iphdroff); diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c index 6bfcd3a90f0..87011fe806c 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c @@ -1258,7 +1258,7 @@ static int help(struct sk_buff **pskb, unsigned int protoff, return NF_DROP; } - if (!skb_make_writable(pskb, (*pskb)->len)) + if (!skb_make_writable(*pskb, (*pskb)->len)) return NF_DROP; spin_lock_bh(&snmp_lock); diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 0473145ac53..d7080dd475a 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -362,7 +362,7 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) } skb_put(e->skb, diff); } - if (!skb_make_writable(&e->skb, v->data_len)) + if (!skb_make_writable(e->skb, v->data_len)) return -ENOMEM; skb_copy_to_linear_data(e->skb, v->payload, v->data_len); e->skb->ip_summed = CHECKSUM_NONE; diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c index ad4d94310b8..f76197fc4dc 100644 --- a/net/ipv6/netfilter/ip6t_HL.c +++ b/net/ipv6/netfilter/ip6t_HL.c @@ -29,7 +29,7 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb, const struct ip6t_HL_info *info = targinfo; int new_hl; - if (!skb_make_writable(pskb, (*pskb)->len)) + if (!skb_make_writable(*pskb, (*pskb)->len)) return NF_DROP; ip6h = ipv6_hdr(*pskb); diff --git a/net/netfilter/core.c b/net/netfilter/core.c index a523fa4136e..2c9e8e3652d 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -196,34 +196,24 @@ unlock: EXPORT_SYMBOL(nf_hook_slow); -int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len) +int skb_make_writable(struct sk_buff *skb, unsigned int writable_len) { - struct sk_buff *nskb; - - if (writable_len > (*pskb)->len) + if (writable_len > skb->len) return 0; /* Not exclusive use of packet? Must copy. */ - if (skb_cloned(*pskb) && !skb_clone_writable(*pskb, writable_len)) - goto copy_skb; - if (skb_shared(*pskb)) - goto copy_skb; - - return pskb_may_pull(*pskb, writable_len); - -copy_skb: - nskb = skb_copy(*pskb, GFP_ATOMIC); - if (!nskb) - return 0; - BUG_ON(skb_is_nonlinear(nskb)); - - /* Rest of kernel will get very unhappy if we pass it a - suddenly-orphaned skbuff */ - if ((*pskb)->sk) - skb_set_owner_w(nskb, (*pskb)->sk); - kfree_skb(*pskb); - *pskb = nskb; - return 1; + if (!skb_cloned(skb)) { + if (writable_len <= skb_headlen(skb)) + return 1; + } else if (skb_clone_writable(skb, writable_len)) + return 1; + + if (writable_len <= skb_headlen(skb)) + writable_len = 0; + else + writable_len -= skb_headlen(skb); + + return !!__pskb_pull_tail(skb, writable_len); } EXPORT_SYMBOL(skb_make_writable); diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 49f0480afe0..6ba98acdd7a 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -644,7 +644,7 @@ nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e) } skb_put(e->skb, diff); } - if (!skb_make_writable(&e->skb, data_len)) + if (!skb_make_writable(e->skb, data_len)) return -ENOMEM; skb_copy_to_linear_data(e->skb, data, data_len); e->skb->ip_summed = CHECKSUM_NONE; diff --git a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c index 798ab731009..17066167438 100644 --- a/net/netfilter/xt_DSCP.c +++ b/net/netfilter/xt_DSCP.c @@ -36,7 +36,7 @@ static unsigned int target(struct sk_buff **pskb, u_int8_t dscp = ipv4_get_dsfield(ip_hdr(*pskb)) >> XT_DSCP_SHIFT; if (dscp != dinfo->dscp) { - if (!skb_make_writable(pskb, sizeof(struct iphdr))) + if (!skb_make_writable(*pskb, sizeof(struct iphdr))) return NF_DROP; ipv4_change_dsfield(ip_hdr(*pskb), (__u8)(~XT_DSCP_MASK), @@ -57,7 +57,7 @@ static unsigned int target6(struct sk_buff **pskb, u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(*pskb)) >> XT_DSCP_SHIFT; if (dscp != dinfo->dscp) { - if (!skb_make_writable(pskb, sizeof(struct ipv6hdr))) + if (!skb_make_writable(*pskb, sizeof(struct ipv6hdr))) return NF_DROP; ipv6_change_dsfield(ipv6_hdr(*pskb), (__u8)(~XT_DSCP_MASK), diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index d40f7e4b128..31b6f9d0982 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c @@ -50,7 +50,7 @@ tcpmss_mangle_packet(struct sk_buff **pskb, u16 newmss; u8 *opt; - if (!skb_make_writable(pskb, (*pskb)->len)) + if (!skb_make_writable(*pskb, (*pskb)->len)) return -1; tcplen = (*pskb)->len - tcphoff; -- cgit v1.2.3-18-g5258 From af1e1cf073e3d038b7aac417a20585ecdcab7de6 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 14 Oct 2007 00:39:33 -0700 Subject: [IPVS]: Replace local version of skb_make_writable This patch removes the IPVS-specific version of skb_make_writable and replaces it with the netfilter one. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/net/ip_vs.h | 1 - net/ipv4/ipvs/ip_vs_app.c | 5 +++-- net/ipv4/ipvs/ip_vs_core.c | 42 ++--------------------------------------- net/ipv4/ipvs/ip_vs_ftp.c | 5 +++-- net/ipv4/ipvs/ip_vs_proto_tcp.c | 5 +++-- net/ipv4/ipvs/ip_vs_proto_udp.c | 5 +++-- net/ipv4/ipvs/ip_vs_xmit.c | 4 ++-- 7 files changed, 16 insertions(+), 51 deletions(-) diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 672564e5a81..5da3b4a40aa 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -984,7 +984,6 @@ static inline char ip_vs_fwd_tag(struct ip_vs_conn *cp) return fwd; } -extern int ip_vs_make_skb_writable(struct sk_buff **pskb, int len); extern void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp, struct ip_vs_conn *cp, int dir); diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c index 341474eefa5..8ca5f4806a6 100644 --- a/net/ipv4/ipvs/ip_vs_app.c +++ b/net/ipv4/ipvs/ip_vs_app.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -336,7 +337,7 @@ static inline int app_tcp_pkt_out(struct ip_vs_conn *cp, struct sk_buff **pskb, struct tcphdr *th; __u32 seq; - if (!ip_vs_make_skb_writable(pskb, tcp_offset + sizeof(*th))) + if (!skb_make_writable(*pskb, tcp_offset + sizeof(*th))) return 0; th = (struct tcphdr *)(skb_network_header(*pskb) + tcp_offset); @@ -411,7 +412,7 @@ static inline int app_tcp_pkt_in(struct ip_vs_conn *cp, struct sk_buff **pskb, struct tcphdr *th; __u32 seq; - if (!ip_vs_make_skb_writable(pskb, tcp_offset + sizeof(*th))) + if (!skb_make_writable(*pskb, tcp_offset + sizeof(*th))) return 0; th = (struct tcphdr *)(skb_network_header(*pskb) + tcp_offset); diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index 3487337192c..09cac38580f 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c @@ -58,7 +58,6 @@ EXPORT_SYMBOL(ip_vs_conn_put); #ifdef CONFIG_IP_VS_DEBUG EXPORT_SYMBOL(ip_vs_get_debug_level); #endif -EXPORT_SYMBOL(ip_vs_make_skb_writable); /* ID used in ICMP lookups */ @@ -163,42 +162,6 @@ ip_vs_set_state(struct ip_vs_conn *cp, int direction, } -int ip_vs_make_skb_writable(struct sk_buff **pskb, int writable_len) -{ - struct sk_buff *skb = *pskb; - - /* skb is already used, better copy skb and its payload */ - if (unlikely(skb_shared(skb) || skb->sk)) - goto copy_skb; - - /* skb data is already used, copy it */ - if (unlikely(skb_cloned(skb))) - goto copy_data; - - return pskb_may_pull(skb, writable_len); - - copy_data: - if (unlikely(writable_len > skb->len)) - return 0; - return !pskb_expand_head(skb, 0, 0, GFP_ATOMIC); - - copy_skb: - if (unlikely(writable_len > skb->len)) - return 0; - skb = skb_copy(skb, GFP_ATOMIC); - if (!skb) - return 0; - BUG_ON(skb_is_nonlinear(skb)); - - /* Rest of kernel will get very unhappy if we pass it a - suddenly-orphaned skbuff */ - if ((*pskb)->sk) - skb_set_owner_w(skb, (*pskb)->sk); - kfree_skb(*pskb); - *pskb = skb; - return 1; -} - /* * IPVS persistent scheduling function * It creates a connection entry according to its template if exists, @@ -689,9 +652,8 @@ static int ip_vs_out_icmp(struct sk_buff **pskb, int *related) if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol) offset += 2 * sizeof(__u16); - if (!ip_vs_make_skb_writable(pskb, offset)) + if (!skb_make_writable(skb, offset)) goto out; - skb = *pskb; ip_vs_nat_icmp(skb, pp, cp, 1); @@ -799,7 +761,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb, IP_VS_DBG_PKT(11, pp, skb, 0, "Outgoing packet"); - if (!ip_vs_make_skb_writable(pskb, ihl)) + if (!skb_make_writable(skb, ihl)) goto drop; /* mangle the packet */ diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c index 344ddbbdc75..4167d419b66 100644 --- a/net/ipv4/ipvs/ip_vs_ftp.c +++ b/net/ipv4/ipvs/ip_vs_ftp.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -155,7 +156,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, return 1; /* Linear packets are much easier to deal with. */ - if (!ip_vs_make_skb_writable(pskb, (*pskb)->len)) + if (!skb_make_writable(*pskb, (*pskb)->len)) return 0; if (cp->app_data == &ip_vs_ftp_pasv) { @@ -256,7 +257,7 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp, return 1; /* Linear packets are much easier to deal with. */ - if (!ip_vs_make_skb_writable(pskb, (*pskb)->len)) + if (!skb_make_writable(*pskb, (*pskb)->len)) return 0; /* diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c index e65577a7700..b65b1a352ba 100644 --- a/net/ipv4/ipvs/ip_vs_proto_tcp.c +++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c @@ -20,6 +20,7 @@ #include /* for tcphdr */ #include #include /* for csum_tcpudp_magic */ +#include #include #include @@ -129,7 +130,7 @@ tcp_snat_handler(struct sk_buff **pskb, const unsigned int tcphoff = ip_hdrlen(*pskb); /* csum_check requires unshared skb */ - if (!ip_vs_make_skb_writable(pskb, tcphoff+sizeof(*tcph))) + if (!skb_make_writable(*pskb, tcphoff+sizeof(*tcph))) return 0; if (unlikely(cp->app != NULL)) { @@ -177,7 +178,7 @@ tcp_dnat_handler(struct sk_buff **pskb, const unsigned int tcphoff = ip_hdrlen(*pskb); /* csum_check requires unshared skb */ - if (!ip_vs_make_skb_writable(pskb, tcphoff+sizeof(*tcph))) + if (!skb_make_writable(*pskb, tcphoff+sizeof(*tcph))) return 0; if (unlikely(cp->app != NULL)) { diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c index 8ee5fe6a101..c70aa40e2c9 100644 --- a/net/ipv4/ipvs/ip_vs_proto_udp.c +++ b/net/ipv4/ipvs/ip_vs_proto_udp.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -136,7 +137,7 @@ udp_snat_handler(struct sk_buff **pskb, const unsigned int udphoff = ip_hdrlen(*pskb); /* csum_check requires unshared skb */ - if (!ip_vs_make_skb_writable(pskb, udphoff+sizeof(*udph))) + if (!skb_make_writable(*pskb, udphoff+sizeof(*udph))) return 0; if (unlikely(cp->app != NULL)) { @@ -190,7 +191,7 @@ udp_dnat_handler(struct sk_buff **pskb, unsigned int udphoff = ip_hdrlen(*pskb); /* csum_check requires unshared skb */ - if (!ip_vs_make_skb_writable(pskb, udphoff+sizeof(*udph))) + if (!skb_make_writable(*pskb, udphoff+sizeof(*udph))) return 0; if (unlikely(cp->app != NULL)) { diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c index 666e080a74a..afd90d4d739 100644 --- a/net/ipv4/ipvs/ip_vs_xmit.c +++ b/net/ipv4/ipvs/ip_vs_xmit.c @@ -253,7 +253,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, } /* copy-on-write the packet before mangling it */ - if (!ip_vs_make_skb_writable(&skb, sizeof(struct iphdr))) + if (!skb_make_writable(skb, sizeof(struct iphdr))) goto tx_error_put; if (skb_cow(skb, rt->u.dst.dev->hard_header_len)) @@ -529,7 +529,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, } /* copy-on-write the packet before mangling it */ - if (!ip_vs_make_skb_writable(&skb, offset)) + if (!skb_make_writable(skb, offset)) goto tx_error_put; if (skb_cow(skb, rt->u.dst.dev->hard_header_len)) -- cgit v1.2.3-18-g5258 From 2ca7b0ac022aa0158599178fe1056b1ba9ec8b97 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 14 Oct 2007 00:39:55 -0700 Subject: [NETFILTER]: Avoid skb_copy/pskb_copy/skb_realloc_headroom This patch replaces unnecessary uses of skb_copy, pskb_copy and skb_realloc_headroom by functions such as skb_make_writable and pskb_expand_head. This allows us to remove the double pointers later. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/bridge/netfilter/ebt_dnat.c | 13 +++---------- net/bridge/netfilter/ebt_redirect.c | 13 +++---------- net/bridge/netfilter/ebt_snat.c | 13 +++---------- net/ipv4/netfilter.c | 31 +++++++++---------------------- net/ipv4/netfilter/arpt_mangle.c | 14 +++----------- net/ipv4/netfilter/ip_queue.c | 22 ++++++++-------------- net/ipv4/netfilter/nf_nat_helper.c | 10 +--------- net/ipv6/netfilter/ip6_queue.c | 18 ++++++------------ net/netfilter/nfnetlink_queue.c | 18 ++++++------------ net/netfilter/xt_TCPMSS.c | 10 +++------- 10 files changed, 45 insertions(+), 117 deletions(-) diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c index 4582659dff0..9d74dee20ab 100644 --- a/net/bridge/netfilter/ebt_dnat.c +++ b/net/bridge/netfilter/ebt_dnat.c @@ -8,6 +8,7 @@ * */ +#include #include #include #include @@ -19,17 +20,9 @@ static int ebt_target_dnat(struct sk_buff **pskb, unsigned int hooknr, { struct ebt_nat_info *info = (struct ebt_nat_info *)data; - if (skb_shared(*pskb) || skb_cloned(*pskb)) { - struct sk_buff *nskb; + if (skb_make_writable(*pskb, 0)) + return NF_DROP; - nskb = skb_copy(*pskb, GFP_ATOMIC); - if (!nskb) - return NF_DROP; - if ((*pskb)->sk) - skb_set_owner_w(nskb, (*pskb)->sk); - kfree_skb(*pskb); - *pskb = nskb; - } memcpy(eth_hdr(*pskb)->h_dest, info->mac, ETH_ALEN); return info->target; } diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c index 9f378eab72d..81371cd01bd 100644 --- a/net/bridge/netfilter/ebt_redirect.c +++ b/net/bridge/netfilter/ebt_redirect.c @@ -8,6 +8,7 @@ * */ +#include #include #include #include @@ -20,17 +21,9 @@ static int ebt_target_redirect(struct sk_buff **pskb, unsigned int hooknr, { struct ebt_redirect_info *info = (struct ebt_redirect_info *)data; - if (skb_shared(*pskb) || skb_cloned(*pskb)) { - struct sk_buff *nskb; + if (skb_make_writable(*pskb, 0)) + return NF_DROP; - nskb = skb_copy(*pskb, GFP_ATOMIC); - if (!nskb) - return NF_DROP; - if ((*pskb)->sk) - skb_set_owner_w(nskb, (*pskb)->sk); - kfree_skb(*pskb); - *pskb = nskb; - } if (hooknr != NF_BR_BROUTING) memcpy(eth_hdr(*pskb)->h_dest, in->br_port->br->dev->dev_addr, ETH_ALEN); diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c index a50722182bf..b0c63684e2f 100644 --- a/net/bridge/netfilter/ebt_snat.c +++ b/net/bridge/netfilter/ebt_snat.c @@ -8,6 +8,7 @@ * */ +#include #include #include #include @@ -21,17 +22,9 @@ static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr, { struct ebt_nat_info *info = (struct ebt_nat_info *) data; - if (skb_shared(*pskb) || skb_cloned(*pskb)) { - struct sk_buff *nskb; + if (skb_make_writable(*pskb, 0)) + return NF_DROP; - nskb = skb_copy(*pskb, GFP_ATOMIC); - if (!nskb) - return NF_DROP; - if ((*pskb)->sk) - skb_set_owner_w(nskb, (*pskb)->sk); - kfree_skb(*pskb); - *pskb = nskb; - } memcpy(eth_hdr(*pskb)->h_source, info->mac, ETH_ALEN); if (!(info->target & NAT_ARP_BIT) && eth_hdr(*pskb)->h_proto == htons(ETH_P_ARP)) { diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index b44192924f9..d1e3012d891 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -66,17 +67,10 @@ int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type) /* Change in oif may mean change in hh_len. */ hh_len = (*pskb)->dst->dev->hard_header_len; - if (skb_headroom(*pskb) < hh_len) { - struct sk_buff *nskb; - - nskb = skb_realloc_headroom(*pskb, hh_len); - if (!nskb) - return -1; - if ((*pskb)->sk) - skb_set_owner_w(nskb, (*pskb)->sk); - kfree_skb(*pskb); - *pskb = nskb; - } + if (skb_headroom(*pskb) < hh_len && + pskb_expand_head(*pskb, hh_len - skb_headroom(*pskb), 0, + GFP_ATOMIC)) + return -1; return 0; } @@ -107,17 +101,10 @@ int ip_xfrm_me_harder(struct sk_buff **pskb) /* Change in oif may mean change in hh_len. */ hh_len = (*pskb)->dst->dev->hard_header_len; - if (skb_headroom(*pskb) < hh_len) { - struct sk_buff *nskb; - - nskb = skb_realloc_headroom(*pskb, hh_len); - if (!nskb) - return -1; - if ((*pskb)->sk) - skb_set_owner_w(nskb, (*pskb)->sk); - kfree_skb(*pskb); - *pskb = nskb; - } + if (skb_headroom(*pskb) < hh_len && + pskb_expand_head(*pskb, hh_len - skb_headroom(*pskb), 0, + GFP_ATOMIC)) + return -1; return 0; } EXPORT_SYMBOL(ip_xfrm_me_harder); diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c index c4bdab47597..0181f919a79 100644 --- a/net/ipv4/netfilter/arpt_mangle.c +++ b/net/ipv4/netfilter/arpt_mangle.c @@ -1,5 +1,6 @@ /* module that allows mangling of the arp payload */ #include +#include #include #include @@ -18,17 +19,8 @@ target(struct sk_buff **pskb, unsigned char *arpptr; int pln, hln; - if (skb_shared(*pskb) || skb_cloned(*pskb)) { - struct sk_buff *nskb; - - nskb = skb_copy(*pskb, GFP_ATOMIC); - if (!nskb) - return NF_DROP; - if ((*pskb)->sk) - skb_set_owner_w(nskb, (*pskb)->sk); - kfree_skb(*pskb); - *pskb = nskb; - } + if (skb_make_writable(*pskb, (*pskb)->len)) + return NF_DROP; arp = arp_hdr(*pskb); arpptr = skb_network_header(*pskb) + sizeof(*arp); diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 62d8867ca7d..10a2ce09fd8 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -335,6 +335,7 @@ static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) { int diff; + int err; struct iphdr *user_iph = (struct iphdr *)v->payload; if (v->data_len < sizeof(*user_iph)) @@ -347,21 +348,14 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) if (v->data_len > 0xFFFF) return -EINVAL; if (diff > skb_tailroom(e->skb)) { - struct sk_buff *newskb; - - newskb = skb_copy_expand(e->skb, - skb_headroom(e->skb), - diff, - GFP_ATOMIC); - if (newskb == NULL) { - printk(KERN_WARNING "ip_queue: OOM " - "in mangle, dropping packet\n"); - return -ENOMEM; + err = pskb_expand_head(e->skb, 0, + diff - skb_tailroom(e->skb), + GFP_ATOMIC); + if (err) { + printk(KERN_WARNING "ip_queue: error " + "in mangle, dropping packet: %d\n", -err); + return err; } - if (e->skb->sk) - skb_set_owner_w(newskb, e->skb->sk); - kfree_skb(e->skb); - e->skb = newskb; } skb_put(e->skb, diff); } diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index 6e81f7612b7..40b429e4540 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -113,20 +113,12 @@ static void mangle_contents(struct sk_buff *skb, /* Unusual, but possible case. */ static int enlarge_skb(struct sk_buff **pskb, unsigned int extra) { - struct sk_buff *nskb; - if ((*pskb)->len + extra > 65535) return 0; - nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC); - if (!nskb) + if (pskb_expand_head(*pskb, 0, extra - skb_tailroom(*pskb), GFP_ATOMIC)) return 0; - /* Transfer socket to new skb. */ - if ((*pskb)->sk) - skb_set_owner_w(nskb, (*pskb)->sk); - kfree_skb(*pskb); - *pskb = nskb; return 1; } diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index d7080dd475a..6413a30d9f6 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -332,6 +332,7 @@ static int ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) { int diff; + int err; struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload; if (v->data_len < sizeof(*user_iph)) @@ -344,21 +345,14 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) if (v->data_len > 0xFFFF) return -EINVAL; if (diff > skb_tailroom(e->skb)) { - struct sk_buff *newskb; - - newskb = skb_copy_expand(e->skb, - skb_headroom(e->skb), - diff, - GFP_ATOMIC); - if (newskb == NULL) { + err = pskb_expand_head(e->skb, 0, + diff - skb_tailroom(e->skb), + GFP_ATOMIC); + if (err) { printk(KERN_WARNING "ip6_queue: OOM " "in mangle, dropping packet\n"); - return -ENOMEM; + return err; } - if (e->skb->sk) - skb_set_owner_w(newskb, e->skb->sk); - kfree_skb(e->skb); - e->skb = newskb; } skb_put(e->skb, diff); } diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 6ba98acdd7a..3ceeffcf6f9 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -617,6 +617,7 @@ static int nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e) { int diff; + int err; diff = data_len - e->skb->len; if (diff < 0) { @@ -626,21 +627,14 @@ nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e) if (data_len > 0xFFFF) return -EINVAL; if (diff > skb_tailroom(e->skb)) { - struct sk_buff *newskb; - - newskb = skb_copy_expand(e->skb, - skb_headroom(e->skb), - diff, - GFP_ATOMIC); - if (newskb == NULL) { + err = pskb_expand_head(e->skb, 0, + diff - skb_tailroom(e->skb), + GFP_ATOMIC); + if (err) { printk(KERN_WARNING "nf_queue: OOM " "in mangle, dropping packet\n"); - return -ENOMEM; + return err; } - if (e->skb->sk) - skb_set_owner_w(newskb, e->skb->sk); - kfree_skb(e->skb); - e->skb = newskb; } skb_put(e->skb, diff); } diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index 31b6f9d0982..f111edf5f77 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c @@ -105,14 +105,10 @@ tcpmss_mangle_packet(struct sk_buff **pskb, * MSS Option not found ?! add it.. */ if (skb_tailroom((*pskb)) < TCPOLEN_MSS) { - struct sk_buff *newskb; - - newskb = skb_copy_expand(*pskb, skb_headroom(*pskb), - TCPOLEN_MSS, GFP_ATOMIC); - if (!newskb) + if (pskb_expand_head(*pskb, 0, + TCPOLEN_MSS - skb_tailroom(*pskb), + GFP_ATOMIC)) return -1; - kfree_skb(*pskb); - *pskb = newskb; tcph = (struct tcphdr *)(skb_network_header(*pskb) + tcphoff); } -- cgit v1.2.3-18-g5258 From 3db05fea51cdb162cfa8f69e9cfb9e228919d2a9 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 15 Oct 2007 00:53:15 -0700 Subject: [NETFILTER]: Replace sk_buff ** with sk_buff * With all the users of the double pointers removed, this patch mops up by finally replacing all occurances of sk_buff ** in the netfilter API by sk_buff *. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- include/linux/if_bridge.h | 2 +- include/linux/netfilter.h | 24 +-- include/linux/netfilter/nf_conntrack_amanda.h | 2 +- include/linux/netfilter/nf_conntrack_ftp.h | 2 +- include/linux/netfilter/nf_conntrack_h323.h | 18 +- include/linux/netfilter/nf_conntrack_irc.h | 2 +- include/linux/netfilter/nf_conntrack_pptp.h | 4 +- include/linux/netfilter/nf_conntrack_sip.h | 4 +- include/linux/netfilter/nf_conntrack_tftp.h | 2 +- include/linux/netfilter/x_tables.h | 2 +- include/linux/netfilter_arp/arp_tables.h | 2 +- include/linux/netfilter_bridge/ebtables.h | 4 +- include/linux/netfilter_ipv4.h | 4 +- include/linux/netfilter_ipv4/ip_tables.h | 2 +- include/linux/netfilter_ipv6/ip6_tables.h | 2 +- include/net/ip_vs.h | 12 +- include/net/netfilter/nf_conntrack_core.h | 10 +- include/net/netfilter/nf_conntrack_helper.h | 2 +- include/net/netfilter/nf_nat_core.h | 4 +- include/net/netfilter/nf_nat_helper.h | 6 +- include/net/netfilter/nf_nat_protocol.h | 2 +- include/net/netfilter/nf_nat_rule.h | 2 +- net/bridge/br.c | 2 +- net/bridge/br_input.c | 2 +- net/bridge/br_netfilter.c | 33 ++-- net/bridge/netfilter/ebt_arpreply.c | 3 +- net/bridge/netfilter/ebt_dnat.c | 6 +- net/bridge/netfilter/ebt_mark.c | 10 +- net/bridge/netfilter/ebt_redirect.c | 10 +- net/bridge/netfilter/ebt_snat.c | 12 +- net/bridge/netfilter/ebtable_broute.c | 4 +- net/bridge/netfilter/ebtable_filter.c | 4 +- net/bridge/netfilter/ebtable_nat.c | 8 +- net/bridge/netfilter/ebtables.c | 12 +- net/decnet/netfilter/dn_rtmsg.c | 4 +- net/ipv4/ipvs/ip_vs_app.c | 32 ++-- net/ipv4/ipvs/ip_vs_core.c | 36 ++-- net/ipv4/ipvs/ip_vs_ftp.c | 18 +- net/ipv4/ipvs/ip_vs_proto_tcp.c | 50 +++--- net/ipv4/ipvs/ip_vs_proto_udp.c | 50 +++--- net/ipv4/ipvs/ip_vs_xmit.c | 2 +- net/ipv4/netfilter.c | 58 +++--- net/ipv4/netfilter/arp_tables.c | 20 +-- net/ipv4/netfilter/arpt_mangle.c | 16 +- net/ipv4/netfilter/arptable_filter.c | 4 +- net/ipv4/netfilter/ip_tables.c | 20 +-- net/ipv4/netfilter/ipt_CLUSTERIP.c | 14 +- net/ipv4/netfilter/ipt_ECN.c | 27 ++- net/ipv4/netfilter/ipt_LOG.c | 4 +- net/ipv4/netfilter/ipt_MASQUERADE.c | 6 +- net/ipv4/netfilter/ipt_NETMAP.c | 8 +- net/ipv4/netfilter/ipt_REDIRECT.c | 6 +- net/ipv4/netfilter/ipt_REJECT.c | 22 +-- net/ipv4/netfilter/ipt_SAME.c | 4 +- net/ipv4/netfilter/ipt_TOS.c | 8 +- net/ipv4/netfilter/ipt_TTL.c | 6 +- net/ipv4/netfilter/ipt_ULOG.c | 4 +- net/ipv4/netfilter/iptable_filter.c | 12 +- net/ipv4/netfilter/iptable_mangle.c | 22 +-- net/ipv4/netfilter/iptable_raw.c | 12 +- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 30 ++-- net/ipv4/netfilter/nf_nat_amanda.c | 4 +- net/ipv4/netfilter/nf_nat_core.c | 50 +++--- net/ipv4/netfilter/nf_nat_ftp.c | 18 +- net/ipv4/netfilter/nf_nat_h323.c | 58 +++--- net/ipv4/netfilter/nf_nat_helper.c | 110 ++++++------ net/ipv4/netfilter/nf_nat_irc.c | 4 +- net/ipv4/netfilter/nf_nat_pptp.c | 8 +- net/ipv4/netfilter/nf_nat_proto_gre.c | 8 +- net/ipv4/netfilter/nf_nat_proto_icmp.c | 10 +- net/ipv4/netfilter/nf_nat_proto_tcp.c | 16 +- net/ipv4/netfilter/nf_nat_proto_udp.c | 16 +- net/ipv4/netfilter/nf_nat_proto_unknown.c | 2 +- net/ipv4/netfilter/nf_nat_rule.c | 14 +- net/ipv4/netfilter/nf_nat_sip.c | 56 +++--- net/ipv4/netfilter/nf_nat_snmp_basic.c | 14 +- net/ipv4/netfilter/nf_nat_standalone.c | 62 +++---- net/ipv4/netfilter/nf_nat_tftp.c | 2 +- net/ipv4/xfrm4_output.c | 4 +- net/ipv6/netfilter.c | 6 +- net/ipv6/netfilter/ip6_tables.c | 16 +- net/ipv6/netfilter/ip6t_HL.c | 6 +- net/ipv6/netfilter/ip6t_LOG.c | 5 +- net/ipv6/netfilter/ip6t_REJECT.c | 14 +- net/ipv6/netfilter/ip6table_filter.c | 12 +- net/ipv6/netfilter/ip6table_mangle.c | 32 ++-- net/ipv6/netfilter/ip6table_raw.c | 4 +- net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 44 ++--- net/ipv6/xfrm6_output.c | 4 +- net/netfilter/core.c | 10 +- net/netfilter/nf_conntrack_amanda.c | 20 +-- net/netfilter/nf_conntrack_core.c | 30 ++-- net/netfilter/nf_conntrack_ftp.c | 18 +- net/netfilter/nf_conntrack_h323_main.c | 236 ++++++++++++------------- net/netfilter/nf_conntrack_irc.c