mirror of https://gitee.com/openkylin/linux.git
[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 <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
7b995651e3
commit
37d4187922
|
@ -287,7 +287,7 @@ extern void nf_invalidate_cache(int pf);
|
||||||
/* Call this before modifying an existing packet: ensures it is
|
/* Call this before modifying an existing packet: ensures it is
|
||||||
modifiable and linear to the point you care about (writable_len).
|
modifiable and linear to the point you care about (writable_len).
|
||||||
Returns true or false. */
|
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)
|
static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
|
||||||
{
|
{
|
||||||
|
|
|
@ -365,7 +365,7 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
|
||||||
}
|
}
|
||||||
skb_put(e->skb, diff);
|
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;
|
return -ENOMEM;
|
||||||
skb_copy_to_linear_data(e->skb, v->payload, v->data_len);
|
skb_copy_to_linear_data(e->skb, v->payload, v->data_len);
|
||||||
e->skb->ip_summed = CHECKSUM_NONE;
|
e->skb->ip_summed = CHECKSUM_NONE;
|
||||||
|
|
|
@ -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)) {
|
if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
|
||||||
__u8 oldtos;
|
__u8 oldtos;
|
||||||
if (!skb_make_writable(pskb, sizeof(struct iphdr)))
|
if (!skb_make_writable(*pskb, sizeof(struct iphdr)))
|
||||||
return false;
|
return false;
|
||||||
iph = ip_hdr(*pskb);
|
iph = ip_hdr(*pskb);
|
||||||
oldtos = iph->tos;
|
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))
|
tcph->cwr == einfo->proto.tcp.cwr))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!skb_make_writable(pskb, ip_hdrlen(*pskb) + sizeof(*tcph)))
|
if (!skb_make_writable(*pskb, ip_hdrlen(*pskb) + sizeof(*tcph)))
|
||||||
return false;
|
return false;
|
||||||
tcph = (void *)ip_hdr(*pskb) + ip_hdrlen(*pskb);
|
tcph = (void *)ip_hdr(*pskb) + ip_hdrlen(*pskb);
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ target(struct sk_buff **pskb,
|
||||||
|
|
||||||
if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
|
if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
|
||||||
__u8 oldtos;
|
__u8 oldtos;
|
||||||
if (!skb_make_writable(pskb, sizeof(struct iphdr)))
|
if (!skb_make_writable(*pskb, sizeof(struct iphdr)))
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
iph = ip_hdr(*pskb);
|
iph = ip_hdr(*pskb);
|
||||||
oldtos = iph->tos;
|
oldtos = iph->tos;
|
||||||
|
|
|
@ -29,7 +29,7 @@ ipt_ttl_target(struct sk_buff **pskb,
|
||||||
const struct ipt_TTL_info *info = targinfo;
|
const struct ipt_TTL_info *info = targinfo;
|
||||||
int new_ttl;
|
int new_ttl;
|
||||||
|
|
||||||
if (!skb_make_writable(pskb, (*pskb)->len))
|
if (!skb_make_writable(*pskb, (*pskb)->len))
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
|
||||||
iph = ip_hdr(*pskb);
|
iph = ip_hdr(*pskb);
|
||||||
|
|
|
@ -357,7 +357,7 @@ manip_pkt(u_int16_t proto,
|
||||||
struct iphdr *iph;
|
struct iphdr *iph;
|
||||||
struct nf_nat_protocol *p;
|
struct nf_nat_protocol *p;
|
||||||
|
|
||||||
if (!skb_make_writable(pskb, iphdroff + sizeof(*iph)))
|
if (!skb_make_writable(*pskb, iphdroff + sizeof(*iph)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
iph = (void *)(*pskb)->data + iphdroff;
|
iph = (void *)(*pskb)->data + iphdroff;
|
||||||
|
@ -431,7 +431,7 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
|
||||||
unsigned long statusbit;
|
unsigned long statusbit;
|
||||||
enum nf_nat_manip_type manip = HOOK2MANIP(hooknum);
|
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;
|
return 0;
|
||||||
|
|
||||||
inside = (void *)(*pskb)->data + ip_hdrlen(*pskb);
|
inside = (void *)(*pskb)->data + ip_hdrlen(*pskb);
|
||||||
|
|
|
@ -152,7 +152,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
|
||||||
struct tcphdr *tcph;
|
struct tcphdr *tcph;
|
||||||
int oldlen, datalen;
|
int oldlen, datalen;
|
||||||
|
|
||||||
if (!skb_make_writable(pskb, (*pskb)->len))
|
if (!skb_make_writable(*pskb, (*pskb)->len))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (rep_len > match_len &&
|
if (rep_len > match_len &&
|
||||||
|
@ -234,7 +234,7 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
|
||||||
match_offset + match_len)
|
match_offset + match_len)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!skb_make_writable(pskb, (*pskb)->len))
|
if (!skb_make_writable(*pskb, (*pskb)->len))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (rep_len > match_len &&
|
if (rep_len > match_len &&
|
||||||
|
@ -341,7 +341,7 @@ nf_nat_sack_adjust(struct sk_buff **pskb,
|
||||||
optoff = ip_hdrlen(*pskb) + sizeof(struct tcphdr);
|
optoff = ip_hdrlen(*pskb) + sizeof(struct tcphdr);
|
||||||
optend = ip_hdrlen(*pskb) + tcph->doff * 4;
|
optend = ip_hdrlen(*pskb) + tcph->doff * 4;
|
||||||
|
|
||||||
if (!skb_make_writable(pskb, optend))
|
if (!skb_make_writable(*pskb, optend))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dir = CTINFO2DIR(ctinfo);
|
dir = CTINFO2DIR(ctinfo);
|
||||||
|
@ -390,7 +390,7 @@ nf_nat_seq_adjust(struct sk_buff **pskb,
|
||||||
this_way = &nat->seq[dir];
|
this_way = &nat->seq[dir];
|
||||||
other_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;
|
return 0;
|
||||||
|
|
||||||
tcph = (void *)(*pskb)->data + ip_hdrlen(*pskb);
|
tcph = (void *)(*pskb)->data + ip_hdrlen(*pskb);
|
||||||
|
|
|
@ -109,7 +109,7 @@ gre_manip_pkt(struct sk_buff **pskb, unsigned int iphdroff,
|
||||||
|
|
||||||
/* pgreh includes two optional 32bit fields which are not required
|
/* pgreh includes two optional 32bit fields which are not required
|
||||||
* to be there. That's where the magic '8' comes from */
|
* 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;
|
return 0;
|
||||||
|
|
||||||
greh = (void *)(*pskb)->data + hdroff;
|
greh = (void *)(*pskb)->data + hdroff;
|
||||||
|
|
|
@ -61,7 +61,7 @@ icmp_manip_pkt(struct sk_buff **pskb,
|
||||||
struct icmphdr *hdr;
|
struct icmphdr *hdr;
|
||||||
unsigned int hdroff = iphdroff + iph->ihl*4;
|
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;
|
return 0;
|
||||||
|
|
||||||
hdr = (struct icmphdr *)((*pskb)->data + hdroff);
|
hdr = (struct icmphdr *)((*pskb)->data + hdroff);
|
||||||
|
|
|
@ -106,7 +106,7 @@ tcp_manip_pkt(struct sk_buff **pskb,
|
||||||
if ((*pskb)->len >= hdroff + sizeof(struct tcphdr))
|
if ((*pskb)->len >= hdroff + sizeof(struct tcphdr))
|
||||||
hdrsize = sizeof(struct tcphdr);
|
hdrsize = sizeof(struct tcphdr);
|
||||||
|
|
||||||
if (!skb_make_writable(pskb, hdroff + hdrsize))
|
if (!skb_make_writable(*pskb, hdroff + hdrsize))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
iph = (struct iphdr *)((*pskb)->data + iphdroff);
|
iph = (struct iphdr *)((*pskb)->data + iphdroff);
|
||||||
|
|
|
@ -97,7 +97,7 @@ udp_manip_pkt(struct sk_buff **pskb,
|
||||||
__be32 oldip, newip;
|
__be32 oldip, newip;
|
||||||
__be16 *portptr, newport;
|
__be16 *portptr, newport;
|
||||||
|
|
||||||
if (!skb_make_writable(pskb, hdroff + sizeof(*hdr)))
|
if (!skb_make_writable(*pskb, hdroff + sizeof(*hdr)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
iph = (struct iphdr *)((*pskb)->data + iphdroff);
|
iph = (struct iphdr *)((*pskb)->data + iphdroff);
|
||||||
|
|
|
@ -1258,7 +1258,7 @@ static int help(struct sk_buff **pskb, unsigned int protoff,
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skb_make_writable(pskb, (*pskb)->len))
|
if (!skb_make_writable(*pskb, (*pskb)->len))
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
|
||||||
spin_lock_bh(&snmp_lock);
|
spin_lock_bh(&snmp_lock);
|
||||||
|
|
|
@ -362,7 +362,7 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
|
||||||
}
|
}
|
||||||
skb_put(e->skb, diff);
|
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;
|
return -ENOMEM;
|
||||||
skb_copy_to_linear_data(e->skb, v->payload, v->data_len);
|
skb_copy_to_linear_data(e->skb, v->payload, v->data_len);
|
||||||
e->skb->ip_summed = CHECKSUM_NONE;
|
e->skb->ip_summed = CHECKSUM_NONE;
|
||||||
|
|
|
@ -29,7 +29,7 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb,
|
||||||
const struct ip6t_HL_info *info = targinfo;
|
const struct ip6t_HL_info *info = targinfo;
|
||||||
int new_hl;
|
int new_hl;
|
||||||
|
|
||||||
if (!skb_make_writable(pskb, (*pskb)->len))
|
if (!skb_make_writable(*pskb, (*pskb)->len))
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
|
||||||
ip6h = ipv6_hdr(*pskb);
|
ip6h = ipv6_hdr(*pskb);
|
||||||
|
|
|
@ -196,34 +196,24 @@ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
|
||||||
EXPORT_SYMBOL(nf_hook_slow);
|
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 > skb->len)
|
||||||
|
|
||||||
if (writable_len > (*pskb)->len)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Not exclusive use of packet? Must copy. */
|
/* Not exclusive use of packet? Must copy. */
|
||||||
if (skb_cloned(*pskb) && !skb_clone_writable(*pskb, writable_len))
|
if (!skb_cloned(skb)) {
|
||||||
goto copy_skb;
|
if (writable_len <= skb_headlen(skb))
|
||||||
if (skb_shared(*pskb))
|
return 1;
|
||||||
goto copy_skb;
|
} else if (skb_clone_writable(skb, writable_len))
|
||||||
|
return 1;
|
||||||
|
|
||||||
return pskb_may_pull(*pskb, writable_len);
|
if (writable_len <= skb_headlen(skb))
|
||||||
|
writable_len = 0;
|
||||||
|
else
|
||||||
|
writable_len -= skb_headlen(skb);
|
||||||
|
|
||||||
copy_skb:
|
return !!__pskb_pull_tail(skb, writable_len);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(skb_make_writable);
|
EXPORT_SYMBOL(skb_make_writable);
|
||||||
|
|
||||||
|
|
|
@ -644,7 +644,7 @@ nfqnl_mangle(void *data, int data_len, struct nfqnl_queue_entry *e)
|
||||||
}
|
}
|
||||||
skb_put(e->skb, diff);
|
skb_put(e->skb, diff);
|
||||||
}
|
}
|
||||||
if (!skb_make_writable(&e->skb, data_len))
|
if (!skb_make_writable(e->skb, data_len))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
skb_copy_to_linear_data(e->skb, data, data_len);
|
skb_copy_to_linear_data(e->skb, data, data_len);
|
||||||
e->skb->ip_summed = CHECKSUM_NONE;
|
e->skb->ip_summed = CHECKSUM_NONE;
|
||||||
|
|
|
@ -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;
|
u_int8_t dscp = ipv4_get_dsfield(ip_hdr(*pskb)) >> XT_DSCP_SHIFT;
|
||||||
|
|
||||||
if (dscp != dinfo->dscp) {
|
if (dscp != dinfo->dscp) {
|
||||||
if (!skb_make_writable(pskb, sizeof(struct iphdr)))
|
if (!skb_make_writable(*pskb, sizeof(struct iphdr)))
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
|
||||||
ipv4_change_dsfield(ip_hdr(*pskb), (__u8)(~XT_DSCP_MASK),
|
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;
|
u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(*pskb)) >> XT_DSCP_SHIFT;
|
||||||
|
|
||||||
if (dscp != dinfo->dscp) {
|
if (dscp != dinfo->dscp) {
|
||||||
if (!skb_make_writable(pskb, sizeof(struct ipv6hdr)))
|
if (!skb_make_writable(*pskb, sizeof(struct ipv6hdr)))
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
|
||||||
ipv6_change_dsfield(ipv6_hdr(*pskb), (__u8)(~XT_DSCP_MASK),
|
ipv6_change_dsfield(ipv6_hdr(*pskb), (__u8)(~XT_DSCP_MASK),
|
||||||
|
|
|
@ -50,7 +50,7 @@ tcpmss_mangle_packet(struct sk_buff **pskb,
|
||||||
u16 newmss;
|
u16 newmss;
|
||||||
u8 *opt;
|
u8 *opt;
|
||||||
|
|
||||||
if (!skb_make_writable(pskb, (*pskb)->len))
|
if (!skb_make_writable(*pskb, (*pskb)->len))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
tcplen = (*pskb)->len - tcphoff;
|
tcplen = (*pskb)->len - tcphoff;
|
||||||
|
|
Loading…
Reference in New Issue