Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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 <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Herbert Xu and committed by
David S. Miller
2ca7b0ac af1e1cf0

+45 -117
+3 -10
net/bridge/netfilter/ebt_dnat.c
··· 8 8 * 9 9 */ 10 10 11 + #include <linux/netfilter.h> 11 12 #include <linux/netfilter_bridge/ebtables.h> 12 13 #include <linux/netfilter_bridge/ebt_nat.h> 13 14 #include <linux/module.h> ··· 20 19 { 21 20 struct ebt_nat_info *info = (struct ebt_nat_info *)data; 22 21 23 - if (skb_shared(*pskb) || skb_cloned(*pskb)) { 24 - struct sk_buff *nskb; 22 + if (skb_make_writable(*pskb, 0)) 23 + return NF_DROP; 25 24 26 - nskb = skb_copy(*pskb, GFP_ATOMIC); 27 - if (!nskb) 28 - return NF_DROP; 29 - if ((*pskb)->sk) 30 - skb_set_owner_w(nskb, (*pskb)->sk); 31 - kfree_skb(*pskb); 32 - *pskb = nskb; 33 - } 34 25 memcpy(eth_hdr(*pskb)->h_dest, info->mac, ETH_ALEN); 35 26 return info->target; 36 27 }
+3 -10
net/bridge/netfilter/ebt_redirect.c
··· 8 8 * 9 9 */ 10 10 11 + #include <linux/netfilter.h> 11 12 #include <linux/netfilter_bridge/ebtables.h> 12 13 #include <linux/netfilter_bridge/ebt_redirect.h> 13 14 #include <linux/module.h> ··· 21 20 { 22 21 struct ebt_redirect_info *info = (struct ebt_redirect_info *)data; 23 22 24 - if (skb_shared(*pskb) || skb_cloned(*pskb)) { 25 - struct sk_buff *nskb; 23 + if (skb_make_writable(*pskb, 0)) 24 + return NF_DROP; 26 25 27 - nskb = skb_copy(*pskb, GFP_ATOMIC); 28 - if (!nskb) 29 - return NF_DROP; 30 - if ((*pskb)->sk) 31 - skb_set_owner_w(nskb, (*pskb)->sk); 32 - kfree_skb(*pskb); 33 - *pskb = nskb; 34 - } 35 26 if (hooknr != NF_BR_BROUTING) 36 27 memcpy(eth_hdr(*pskb)->h_dest, 37 28 in->br_port->br->dev->dev_addr, ETH_ALEN);
+3 -10
net/bridge/netfilter/ebt_snat.c
··· 8 8 * 9 9 */ 10 10 11 + #include <linux/netfilter.h> 11 12 #include <linux/netfilter_bridge/ebtables.h> 12 13 #include <linux/netfilter_bridge/ebt_nat.h> 13 14 #include <linux/module.h> ··· 22 21 { 23 22 struct ebt_nat_info *info = (struct ebt_nat_info *) data; 24 23 25 - if (skb_shared(*pskb) || skb_cloned(*pskb)) { 26 - struct sk_buff *nskb; 24 + if (skb_make_writable(*pskb, 0)) 25 + return NF_DROP; 27 26 28 - nskb = skb_copy(*pskb, GFP_ATOMIC); 29 - if (!nskb) 30 - return NF_DROP; 31 - if ((*pskb)->sk) 32 - skb_set_owner_w(nskb, (*pskb)->sk); 33 - kfree_skb(*pskb); 34 - *pskb = nskb; 35 - } 36 27 memcpy(eth_hdr(*pskb)->h_source, info->mac, ETH_ALEN); 37 28 if (!(info->target & NAT_ARP_BIT) && 38 29 eth_hdr(*pskb)->h_proto == htons(ETH_P_ARP)) {
+9 -22
net/ipv4/netfilter.c
··· 3 3 #include <linux/netfilter.h> 4 4 #include <linux/netfilter_ipv4.h> 5 5 #include <linux/ip.h> 6 + #include <linux/skbuff.h> 6 7 #include <net/route.h> 7 8 #include <net/xfrm.h> 8 9 #include <net/ip.h> ··· 67 66 68 67 /* Change in oif may mean change in hh_len. */ 69 68 hh_len = (*pskb)->dst->dev->hard_header_len; 70 - if (skb_headroom(*pskb) < hh_len) { 71 - struct sk_buff *nskb; 72 - 73 - nskb = skb_realloc_headroom(*pskb, hh_len); 74 - if (!nskb) 75 - return -1; 76 - if ((*pskb)->sk) 77 - skb_set_owner_w(nskb, (*pskb)->sk); 78 - kfree_skb(*pskb); 79 - *pskb = nskb; 80 - } 69 + if (skb_headroom(*pskb) < hh_len && 70 + pskb_expand_head(*pskb, hh_len - skb_headroom(*pskb), 0, 71 + GFP_ATOMIC)) 72 + return -1; 81 73 82 74 return 0; 83 75 } ··· 101 107 102 108 /* Change in oif may mean change in hh_len. */ 103 109 hh_len = (*pskb)->dst->dev->hard_header_len; 104 - if (skb_headroom(*pskb) < hh_len) { 105 - struct sk_buff *nskb; 106 - 107 - nskb = skb_realloc_headroom(*pskb, hh_len); 108 - if (!nskb) 109 - return -1; 110 - if ((*pskb)->sk) 111 - skb_set_owner_w(nskb, (*pskb)->sk); 112 - kfree_skb(*pskb); 113 - *pskb = nskb; 114 - } 110 + if (skb_headroom(*pskb) < hh_len && 111 + pskb_expand_head(*pskb, hh_len - skb_headroom(*pskb), 0, 112 + GFP_ATOMIC)) 113 + return -1; 115 114 return 0; 116 115 } 117 116 EXPORT_SYMBOL(ip_xfrm_me_harder);
+3 -11
net/ipv4/netfilter/arpt_mangle.c
··· 1 1 /* module that allows mangling of the arp payload */ 2 2 #include <linux/module.h> 3 + #include <linux/netfilter.h> 3 4 #include <linux/netfilter_arp/arpt_mangle.h> 4 5 #include <net/sock.h> 5 6 ··· 19 18 unsigned char *arpptr; 20 19 int pln, hln; 21 20 22 - if (skb_shared(*pskb) || skb_cloned(*pskb)) { 23 - struct sk_buff *nskb; 24 - 25 - nskb = skb_copy(*pskb, GFP_ATOMIC); 26 - if (!nskb) 27 - return NF_DROP; 28 - if ((*pskb)->sk) 29 - skb_set_owner_w(nskb, (*pskb)->sk); 30 - kfree_skb(*pskb); 31 - *pskb = nskb; 32 - } 21 + if (skb_make_writable(*pskb, (*pskb)->len)) 22 + return NF_DROP; 33 23 34 24 arp = arp_hdr(*pskb); 35 25 arpptr = skb_network_header(*pskb) + sizeof(*arp);
+8 -14
net/ipv4/netfilter/ip_queue.c
··· 335 335 ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) 336 336 { 337 337 int diff; 338 + int err; 338 339 struct iphdr *user_iph = (struct iphdr *)v->payload; 339 340 340 341 if (v->data_len < sizeof(*user_iph)) ··· 348 347 if (v->data_len > 0xFFFF) 349 348 return -EINVAL; 350 349 if (diff > skb_tailroom(e->skb)) { 351 - struct sk_buff *newskb; 352 - 353 - newskb = skb_copy_expand(e->skb, 354 - skb_headroom(e->skb), 355 - diff, 356 - GFP_ATOMIC); 357 - if (newskb == NULL) { 358 - printk(KERN_WARNING "ip_queue: OOM " 359 - "in mangle, dropping packet\n"); 360 - return -ENOMEM; 350 + err = pskb_expand_head(e->skb, 0, 351 + diff - skb_tailroom(e->skb), 352 + GFP_ATOMIC); 353 + if (err) { 354 + printk(KERN_WARNING "ip_queue: error " 355 + "in mangle, dropping packet: %d\n", -err); 356 + return err; 361 357 } 362 - if (e->skb->sk) 363 - skb_set_owner_w(newskb, e->skb->sk); 364 - kfree_skb(e->skb); 365 - e->skb = newskb; 366 358 } 367 359 skb_put(e->skb, diff); 368 360 }
+1 -9
net/ipv4/netfilter/nf_nat_helper.c
··· 113 113 /* Unusual, but possible case. */ 114 114 static int enlarge_skb(struct sk_buff **pskb, unsigned int extra) 115 115 { 116 - struct sk_buff *nskb; 117 - 118 116 if ((*pskb)->len + extra > 65535) 119 117 return 0; 120 118 121 - nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC); 122 - if (!nskb) 119 + if (pskb_expand_head(*pskb, 0, extra - skb_tailroom(*pskb), GFP_ATOMIC)) 123 120 return 0; 124 121 125 - /* Transfer socket to new skb. */ 126 - if ((*pskb)->sk) 127 - skb_set_owner_w(nskb, (*pskb)->sk); 128 - kfree_skb(*pskb); 129 - *pskb = nskb; 130 122 return 1; 131 123 } 132 124
+6 -12
net/ipv6/netfilter/ip6_queue.c
··· 332 332 ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) 333 333 { 334 334 int diff; 335 + int err; 335 336 struct ipv6hdr *user_iph = (struct ipv6hdr *)v->payload; 336 337 337 338 if (v->data_len < sizeof(*user_iph)) ··· 345 344 if (v->data_len > 0xFFFF) 346 345 return -EINVAL; 347 346 if (diff > skb_tailroom(e->skb)) { 348 - struct sk_buff *newskb; 349 - 350 - newskb = skb_copy_expand(e->skb, 351 - skb_headroom(e->skb), 352 - diff, 353 - GFP_ATOMIC); 354 - if (newskb == NULL) { 347 + err = pskb_expand_head(e->skb, 0, 348 + diff - skb_tailroom(e->skb), 349 + GFP_ATOMIC); 350 + if (err) { 355 351 printk(KERN_WARNING "ip6_queue: OOM " 356 352 "in mangle, dropping packet\n"); 357 - return -ENOMEM; 353 + return err; 358 354 } 359 - if (e->skb->sk) 360 - skb_set_owner_w(newskb, e->skb->sk); 361 - kfree_skb(e->skb); 362 - e->skb = newskb; 363 355 } 364 356 skb_put(e->skb, diff); 365 357 }
+3 -7
net/netfilter/xt_TCPMSS.c
··· 105 105 * MSS Option not found ?! add it.. 106 106 */ 107 107 if (skb_tailroom((*pskb)) < TCPOLEN_MSS) { 108 - struct sk_buff *newskb; 109 - 110 - newskb = skb_copy_expand(*pskb, skb_headroom(*pskb), 111 - TCPOLEN_MSS, GFP_ATOMIC); 112 - if (!newskb) 108 + if (pskb_expand_head(*pskb, 0, 109 + TCPOLEN_MSS - skb_tailroom(*pskb), 110 + GFP_ATOMIC)) 113 111 return -1; 114 - kfree_skb(*pskb); 115 - *pskb = newskb; 116 112 tcph = (struct tcphdr *)(skb_network_header(*pskb) + tcphoff); 117 113 } 118 114