[IPV6]: Add ip6_local_out
Most callers of the LOCAL_OUT chain will set the IP packet length before doing so. They also share the same output function dst_output. This patch creates a new function called ip6_local_out which does all of that and converts the appropriate users over to it. Apart from removing duplicate code, it will also help in merging the IPsec output path. 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
c439cb2e4b
commit
ef76bc23ef
|
@ -509,6 +509,9 @@ extern int ip6_forward(struct sk_buff *skb);
|
||||||
extern int ip6_input(struct sk_buff *skb);
|
extern int ip6_input(struct sk_buff *skb);
|
||||||
extern int ip6_mc_input(struct sk_buff *skb);
|
extern int ip6_mc_input(struct sk_buff *skb);
|
||||||
|
|
||||||
|
extern int __ip6_local_out(struct sk_buff *skb);
|
||||||
|
extern int ip6_local_out(struct sk_buff *skb);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extension header (options) processing
|
* Extension header (options) processing
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/types.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/socket.h>
|
#include <linux/socket.h>
|
||||||
#include <linux/net.h>
|
#include <linux/net.h>
|
||||||
|
@ -70,6 +70,31 @@ static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *f
|
||||||
spin_unlock_bh(&ip6_id_lock);
|
spin_unlock_bh(&ip6_id_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int __ip6_local_out(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = skb->len - sizeof(struct ipv6hdr);
|
||||||
|
if (len > IPV6_MAXPLEN)
|
||||||
|
len = 0;
|
||||||
|
ipv6_hdr(skb)->payload_len = htons(len);
|
||||||
|
|
||||||
|
return nf_hook(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev,
|
||||||
|
dst_output);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ip6_local_out(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = __ip6_local_out(skb);
|
||||||
|
if (likely(err == 1))
|
||||||
|
err = dst_output(skb);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(ip6_local_out);
|
||||||
|
|
||||||
static int ip6_output_finish(struct sk_buff *skb)
|
static int ip6_output_finish(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct dst_entry *dst = skb->dst;
|
struct dst_entry *dst = skb->dst;
|
||||||
|
@ -1403,10 +1428,6 @@ int ip6_push_pending_frames(struct sock *sk)
|
||||||
*(__be32*)hdr = fl->fl6_flowlabel |
|
*(__be32*)hdr = fl->fl6_flowlabel |
|
||||||
htonl(0x60000000 | ((int)np->cork.tclass << 20));
|
htonl(0x60000000 | ((int)np->cork.tclass << 20));
|
||||||
|
|
||||||
if (skb->len <= sizeof(struct ipv6hdr) + IPV6_MAXPLEN)
|
|
||||||
hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
|
|
||||||
else
|
|
||||||
hdr->payload_len = 0;
|
|
||||||
hdr->hop_limit = np->cork.hop_limit;
|
hdr->hop_limit = np->cork.hop_limit;
|
||||||
hdr->nexthdr = proto;
|
hdr->nexthdr = proto;
|
||||||
ipv6_addr_copy(&hdr->saddr, &fl->fl6_src);
|
ipv6_addr_copy(&hdr->saddr, &fl->fl6_src);
|
||||||
|
@ -1423,7 +1444,7 @@ int ip6_push_pending_frames(struct sock *sk)
|
||||||
ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS);
|
ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output);
|
err = ip6_local_out(skb);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (err > 0)
|
if (err > 0)
|
||||||
err = np->recverr ? net_xmit_errno(err) : 0;
|
err = np->recverr ? net_xmit_errno(err) : 0;
|
||||||
|
|
|
@ -910,15 +910,13 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
|
||||||
*(__be32*)ipv6h = fl->fl6_flowlabel | htonl(0x60000000);
|
*(__be32*)ipv6h = fl->fl6_flowlabel | htonl(0x60000000);
|
||||||
dsfield = INET_ECN_encapsulate(0, dsfield);
|
dsfield = INET_ECN_encapsulate(0, dsfield);
|
||||||
ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield);
|
ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield);
|
||||||
ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
|
|
||||||
ipv6h->hop_limit = t->parms.hop_limit;
|
ipv6h->hop_limit = t->parms.hop_limit;
|
||||||
ipv6h->nexthdr = proto;
|
ipv6h->nexthdr = proto;
|
||||||
ipv6_addr_copy(&ipv6h->saddr, &fl->fl6_src);
|
ipv6_addr_copy(&ipv6h->saddr, &fl->fl6_src);
|
||||||
ipv6_addr_copy(&ipv6h->daddr, &fl->fl6_dst);
|
ipv6_addr_copy(&ipv6h->daddr, &fl->fl6_dst);
|
||||||
nf_reset(skb);
|
nf_reset(skb);
|
||||||
pkt_len = skb->len;
|
pkt_len = skb->len;
|
||||||
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL,
|
err = ip6_local_out(skb);
|
||||||
skb->dst->dev, dst_output);
|
|
||||||
|
|
||||||
if (net_xmit_eval(err) == 0) {
|
if (net_xmit_eval(err) == 0) {
|
||||||
stats->tx_bytes += pkt_len;
|
stats->tx_bytes += pkt_len;
|
||||||
|
|
|
@ -121,7 +121,6 @@ static void send_reset(struct sk_buff *oldskb)
|
||||||
ip6h->version = 6;
|
ip6h->version = 6;
|
||||||
ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
|
ip6h->hop_limit = dst_metric(dst, RTAX_HOPLIMIT);
|
||||||
ip6h->nexthdr = IPPROTO_TCP;
|
ip6h->nexthdr = IPPROTO_TCP;
|
||||||
ip6h->payload_len = htons(sizeof(struct tcphdr));
|
|
||||||
ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr);
|
ipv6_addr_copy(&ip6h->saddr, &oip6h->daddr);
|
||||||
ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr);
|
ipv6_addr_copy(&ip6h->daddr, &oip6h->saddr);
|
||||||
|
|
||||||
|
@ -159,8 +158,7 @@ static void send_reset(struct sk_buff *oldskb)
|
||||||
|
|
||||||
nf_ct_attach(nskb, oldskb);
|
nf_ct_attach(nskb, oldskb);
|
||||||
|
|
||||||
NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
|
ip6_local_out(nskb);
|
||||||
dst_output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
|
|
@ -75,16 +75,12 @@ EXPORT_SYMBOL(xfrm6_prepare_output);
|
||||||
|
|
||||||
static inline int xfrm6_output_one(struct sk_buff *skb)
|
static inline int xfrm6_output_one(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct ipv6hdr *iph;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = xfrm_output(skb);
|
err = xfrm_output(skb);
|
||||||
if (err)
|
if (err)
|
||||||
goto error_nolock;
|
goto error_nolock;
|
||||||
|
|
||||||
iph = ipv6_hdr(skb);
|
|
||||||
iph->payload_len = htons(skb->len - sizeof(*iph));
|
|
||||||
|
|
||||||
IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
|
IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
|
||||||
err = 0;
|
err = 0;
|
||||||
|
|
||||||
|
@ -102,8 +98,7 @@ static int xfrm6_output_finish2(struct sk_buff *skb)
|
||||||
while (likely((err = xfrm6_output_one(skb)) == 0)) {
|
while (likely((err = xfrm6_output_one(skb)) == 0)) {
|
||||||
nf_reset(skb);
|
nf_reset(skb);
|
||||||
|
|
||||||
err = nf_hook(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL,
|
err = __ip6_local_out(skb);
|
||||||
skb->dst->dev, dst_output);
|
|
||||||
if (unlikely(err != 1))
|
if (unlikely(err != 1))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue