[NETFILTER]: Do not copy skb in skb_make_writable
authorHerbert Xu <herbert@gondor.apana.org.au>
Sun, 14 Oct 2007 07:39:18 +0000 (00:39 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Mon, 15 Oct 2007 19:26:27 +0000 (12:26 -0700)
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 <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
18 files changed:
include/linux/netfilter.h
net/ipv4/netfilter/ip_queue.c
net/ipv4/netfilter/ipt_ECN.c
net/ipv4/netfilter/ipt_TOS.c
net/ipv4/netfilter/ipt_TTL.c
net/ipv4/netfilter/nf_nat_core.c
net/ipv4/netfilter/nf_nat_helper.c
net/ipv4/netfilter/nf_nat_proto_gre.c
net/ipv4/netfilter/nf_nat_proto_icmp.c
net/ipv4/netfilter/nf_nat_proto_tcp.c
net/ipv4/netfilter/nf_nat_proto_udp.c
net/ipv4/netfilter/nf_nat_snmp_basic.c
net/ipv6/netfilter/ip6_queue.c
net/ipv6/netfilter/ip6t_HL.c
net/netfilter/core.c
net/netfilter/nfnetlink_queue.c
net/netfilter/xt_DSCP.c
net/netfilter/xt_TCPMSS.c

index 1dd075eda595a86efe4ca15e8c6d146d63a7ef73..2505348c98b36e0581bf07a3ed9c56fcaee78641 100644 (file)
@@ -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)
 {
index 23cbfc7c80fd982f7b1f57a51d7cc2125342432a..62d8867ca7d01068297400bc733916e21b622f8b 100644 (file)
@@ -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;
index f1253bd3837f11d78c530351068dc514a3ecfcc1..92744be1c55e36b1b5df50221ab11e8f9614d346 100644 (file)
@@ -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);
 
index 25f5d0b3906523b9a0e0fc2fd4f0758ce69fb95f..87b689ac09a5419e1694ecfa8885b4defc8b42e7 100644 (file)
@@ -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;
index 2b54e7b0cfe84f707b3ee2cbded965d5457b7d44..3dd467611e11f3f065e490f7014a79965b705077 100644 (file)
@@ -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);
index 7221aa20e6ff61175a12c3815aaab3186bc1d8c3..3b5eb7c1a13c4d72d6c80666e58c241ce94e483c 100644 (file)
@@ -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);
index 93d8a0a8f03562894b2840032f438dd67c4cf39e..6e81f7612b71c37e36c7f2cbf36f087ce97ce4ac 100644 (file)
@@ -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);
index d562290b182049ea66ee9cb385547fba737e0ffa..e7a2aafcce5beeac623f40f81b3e99ce9442de69 100644 (file)
@@ -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;
index 898d737711552e64b7f39a2022f3b845d5953d79..4087f4f42c34b6e1c3591f7ae28a0365ed8c3542 100644 (file)
@@ -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);
index 5bbbb2acdc70a0d2a58ac34dc275b5ba546d314d..e544125dc0373155962c24202b4162cb6249d2bf 100644 (file)
@@ -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);
index a0af4fd95584f0c67bc834833aad79ddb168e6d7..ebe9b42a8e943a16db4a5d1b040ccedb96a779d8 100644 (file)
@@ -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);
index 6bfcd3a90f08d2d60fe76e32dd6173c36c614f2b..87011fe806ca13399004c957162d065ca72fa7f5 100644 (file)
@@ -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);
index 0473145ac534fd98dc60997418a94b1c68e37d91..d7080dd475ac4acf8af10eadaf2d96829144bd73 100644 (file)
@@ -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;
index ad4d94310b8734ab145ef79e443acaa3550e719f..f76197fc4dccb5c3ae6d6401957467af1304857b 100644 (file)
@@ -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);
index a523fa4136ed53a7f13e227c0ee6bb8a38ae95f4..2c9e8e3652d06fc4b8124bcf6fbec65134e639d5 100644 (file)
@@ -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);
 
index 49f0480afe099ac4643bf895eb05d68256b563a6..6ba98acdd7a225eb9be401040b0dd3c570fcdac2 100644 (file)
@@ -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;
index 798ab731009d8e97ceb3a2caf4d479abf26dd7db..17066167438898c8c593a378d9e39b0b5d56c6f8 100644 (file)
@@ -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),
index d40f7e4b1289362f142afaa17a15f424bae30499..31b6f9d0982277826393248e28f1265ae5476c7a 100644 (file)
@@ -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;