[IPV4]: Add ip_local_out
authorHerbert Xu <herbert@gondor.apana.org.au>
Sat, 12 Jan 2008 03:14:00 +0000 (19:14 -0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Jan 2008 22:53:47 +0000 (14:53 -0800)
Most callers of the LOCAL_OUT chain will set the IP packet length and
header checksum before doing so.  They also share the same output
function dst_output.

This patch creates a new function called ip_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 once the same thing is done for IPv6.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ip.h
include/net/ipip.h
net/ipv4/igmp.c
net/ipv4/ip_output.c
net/ipv4/ipvs/ip_vs_xmit.c
net/ipv4/netfilter/ipt_REJECT.c
net/ipv4/xfrm4_output.c

index 50c8889b1b8d7e6625cf4580a673c9a516e27bfd..66d51616ade8bee54da4c091d3adbc001095575d 100644 (file)
@@ -102,6 +102,8 @@ extern int          ip_mc_output(struct sk_buff *skb);
 extern int             ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
 extern int             ip_do_nat(struct sk_buff *skb);
 extern void            ip_send_check(struct iphdr *ip);
+extern int             __ip_local_out(struct sk_buff *skb);
+extern int             ip_local_out(struct sk_buff *skb);
 extern int             ip_queue_xmit(struct sk_buff *skb, int ipfragok);
 extern void            ip_init(void);
 extern int             ip_append_data(struct sock *sk,
index 7cdc914322f0c490fbed511fbddd6b7f167a0eba..549e132bca9c834638416182698169175859e80c 100644 (file)
@@ -2,6 +2,7 @@
 #define __NET_IPIP_H 1
 
 #include <linux/if_tunnel.h>
+#include <net/ip.h>
 
 /* Keep error state on tunnel for 30 sec */
 #define IPTUNNEL_ERR_TIMEO     (30*HZ)
@@ -30,11 +31,9 @@ struct ip_tunnel
        int pkt_len = skb->len;                                         \
                                                                        \
        skb->ip_summed = CHECKSUM_NONE;                                 \
-       iph->tot_len = htons(skb->len);                                 \
        ip_select_ident(iph, &rt->u.dst, NULL);                         \
-       ip_send_check(iph);                                             \
                                                                        \
-       err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output);\
+       err = ip_local_out(skb);                                        \
        if (net_xmit_eval(err) == 0) {                                  \
                stats->tx_bytes += pkt_len;                             \
                stats->tx_packets++;                                    \
index 701558564e96863d0d3b01ee679687aa72f1c8e9..c560a9392b1d2974b795a631cd2a3da1778041bd 100644 (file)
@@ -349,17 +349,12 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
 
 static int igmpv3_sendpack(struct sk_buff *skb)
 {
-       struct iphdr *pip = ip_hdr(skb);
        struct igmphdr *pig = igmp_hdr(skb);
-       const int iplen = skb->tail - skb->network_header;
        const int igmplen = skb->tail - skb->transport_header;
 
-       pip->tot_len = htons(iplen);
-       ip_send_check(pip);
        pig->csum = ip_compute_csum(igmp_hdr(skb), igmplen);
 
-       return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dev,
-                      dst_output);
+       return ip_local_out(skb);
 }
 
 static int grec_size(struct ip_mc_list *pmc, int type, int gdel, int sdel)
@@ -680,13 +675,11 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
        iph->daddr    = dst;
        iph->saddr    = rt->rt_src;
        iph->protocol = IPPROTO_IGMP;
-       iph->tot_len  = htons(IGMP_SIZE);
        ip_select_ident(iph, &rt->u.dst, NULL);
        ((u8*)&iph[1])[0] = IPOPT_RA;
        ((u8*)&iph[1])[1] = 4;
        ((u8*)&iph[1])[2] = 0;
        ((u8*)&iph[1])[3] = 0;
-       ip_send_check(iph);
 
        ih = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
        ih->type=type;
@@ -695,8 +688,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
        ih->group=group;
        ih->csum=ip_compute_csum((void *)ih, sizeof(struct igmphdr));
 
-       return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
-                      dst_output);
+       return ip_local_out(skb);
 }
 
 static void igmp_gq_timer_expire(unsigned long data)
index bc9e57550e86d9b4f5b9ee965466f3d4f52f2585..03b9b0600276708ce407c5e44e568e3ddc292396 100644 (file)
@@ -91,6 +91,28 @@ __inline__ void ip_send_check(struct iphdr *iph)
        iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 }
 
+int __ip_local_out(struct sk_buff *skb)
+{
+       struct iphdr *iph = ip_hdr(skb);
+
+       iph->tot_len = htons(skb->len);
+       ip_send_check(iph);
+       return nf_hook(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, skb->dst->dev,
+                      dst_output);
+}
+
+int ip_local_out(struct sk_buff *skb)
+{
+       int err;
+
+       err = __ip_local_out(skb);
+       if (likely(err == 1))
+               err = dst_output(skb);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(ip_local_out);
+
 /* dev_loopback_xmit for use with netfilter. */
 static int ip_dev_loopback_xmit(struct sk_buff *newskb)
 {
@@ -138,20 +160,17 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
        iph->daddr    = rt->rt_dst;
        iph->saddr    = rt->rt_src;
        iph->protocol = sk->sk_protocol;
-       iph->tot_len  = htons(skb->len);
        ip_select_ident(iph, &rt->u.dst, sk);
 
        if (opt && opt->optlen) {
                iph->ihl += opt->optlen>>2;
                ip_options_build(skb, opt, daddr, rt, 0);
        }
-       ip_send_check(iph);
 
        skb->priority = sk->sk_priority;
 
        /* Send it out. */
-       return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
-                      dst_output);
+       return ip_local_out(skb);
 }
 
 EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
@@ -347,7 +366,6 @@ packet_routed:
        skb_reset_network_header(skb);
        iph = ip_hdr(skb);
        *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
-       iph->tot_len = htons(skb->len);
        if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)
                iph->frag_off = htons(IP_DF);
        else
@@ -366,13 +384,9 @@ packet_routed:
        ip_select_ident_more(iph, &rt->u.dst, sk,
                             (skb_shinfo(skb)->gso_segs ?: 1) - 1);
 
-       /* Add an IP checksum. */
-       ip_send_check(iph);
-
        skb->priority = sk->sk_priority;
 
-       return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
-                      dst_output);
+       return ip_local_out(skb);
 
 no_route:
        IP_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
@@ -1262,14 +1276,12 @@ int ip_push_pending_frames(struct sock *sk)
                ip_options_build(skb, opt, inet->cork.addr, rt, 0);
        }
        iph->tos = inet->tos;
-       iph->tot_len = htons(skb->len);
        iph->frag_off = df;
        ip_select_ident(iph, &rt->u.dst, sk);
        iph->ttl = ttl;
        iph->protocol = sk->sk_protocol;
        iph->saddr = rt->rt_src;
        iph->daddr = rt->rt_dst;
-       ip_send_check(iph);
 
        skb->priority = sk->sk_priority;
        skb->dst = dst_clone(&rt->u.dst);
@@ -1279,8 +1291,7 @@ int ip_push_pending_frames(struct sock *sk)
                        skb_transport_header(skb))->type);
 
        /* Netfilter gets whole the not fragmented skb. */
-       err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
-                     skb->dst->dev, dst_output);
+       err = ip_local_out(skb);
        if (err) {
                if (err > 0)
                        err = inet->recverr ? net_xmit_errno(err) : 0;
index 7c074e386c17235a3f9a98bd350a390b316f4835..66775ad9e328774b93229e913d8c40e74816cc74 100644 (file)
@@ -16,8 +16,8 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/ip.h>
 #include <linux/tcp.h>                  /* for tcphdr */
+#include <net/ip.h>
 #include <net/tcp.h>                    /* for csum_tcpudp_magic */
 #include <net/udp.h>
 #include <net/icmp.h>                   /* for icmp_send */
@@ -406,14 +406,12 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
        iph->daddr              =       rt->rt_dst;
        iph->saddr              =       rt->rt_src;
        iph->ttl                =       old_iph->ttl;
-       iph->tot_len            =       htons(skb->len);
        ip_select_ident(iph, &rt->u.dst, NULL);
-       ip_send_check(iph);
 
        /* Another hack: avoid icmp_send in ip_fragment */
        skb->local_df = 1;
 
-       IP_VS_XMIT(skb, rt);
+       ip_local_out(skb);
 
        LeaveFunction(10);
 
index dcf4d21d51161fa99625168c9990379cd988e01f..ccb2a03dcd5a237793204beec92add8b586b6497 100644 (file)
@@ -90,7 +90,6 @@ static void send_reset(struct sk_buff *oldskb, int hook)
        /* Truncate to length (no data) */
        tcph->doff = sizeof(struct tcphdr)/4;
        skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr));
-       niph->tot_len = htons(nskb->len);
 
        if (tcph->ack) {
                needs_ack = 0;
@@ -139,18 +138,13 @@ static void send_reset(struct sk_buff *oldskb, int hook)
        /* Adjust IP TTL */
        niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
 
-       /* Adjust IP checksum */
-       niph->check = 0;
-       niph->check = ip_fast_csum(skb_network_header(nskb), niph->ihl);
-
        /* "Never happens" */
        if (nskb->len > dst_mtu(nskb->dst))
                goto free_nskb;
 
        nf_ct_attach(nskb, oldskb);
 
-       NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
-               dst_output);
+       ip_local_out(nskb);
        return;
 
  free_nskb:
index 13fd11335e28ecbb303b8725fa93294a221733b8..0ffc3d07848942b78eb41025a175876d81b4fbe5 100644 (file)
@@ -69,17 +69,12 @@ EXPORT_SYMBOL(xfrm4_prepare_output);
 
 static inline int xfrm4_output_one(struct sk_buff *skb)
 {
-       struct iphdr *iph;
        int err;
 
        err = xfrm_output(skb);
        if (err)
                goto error_nolock;
 
-       iph = ip_hdr(skb);
-       iph->tot_len = htons(skb->len);
-       ip_send_check(iph);
-
        IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
        err = 0;
 
@@ -97,8 +92,7 @@ static int xfrm4_output_finish2(struct sk_buff *skb)
        while (likely((err = xfrm4_output_one(skb)) == 0)) {
                nf_reset(skb);
 
-               err = nf_hook(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
-                             skb->dst->dev, dst_output);
+               err = __ip_local_out(skb);
                if (unlikely(err != 1))
                        break;