소스 검색

[IPV4]: Add ip_local_out

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>
Herbert Xu 17 년 전
부모
커밋
c439cb2e4b
7개의 변경된 파일35개의 추가작업 그리고 45개의 파일을 삭제
  1. 2 0
      include/net/ip.h
  2. 2 3
      include/net/ipip.h
  3. 2 10
      net/ipv4/igmp.c
  4. 25 14
      net/ipv4/ip_output.c
  5. 2 4
      net/ipv4/ipvs/ip_vs_xmit.c
  6. 1 7
      net/ipv4/netfilter/ipt_REJECT.c
  7. 1 7
      net/ipv4/xfrm4_output.c

+ 2 - 0
include/net/ip.h

@@ -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_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *));
 extern int		ip_do_nat(struct sk_buff *skb);
 extern int		ip_do_nat(struct sk_buff *skb);
 extern void		ip_send_check(struct iphdr *ip);
 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 int		ip_queue_xmit(struct sk_buff *skb, int ipfragok);
 extern void		ip_init(void);
 extern void		ip_init(void);
 extern int		ip_append_data(struct sock *sk,
 extern int		ip_append_data(struct sock *sk,

+ 2 - 3
include/net/ipip.h

@@ -2,6 +2,7 @@
 #define __NET_IPIP_H 1
 #define __NET_IPIP_H 1
 
 
 #include <linux/if_tunnel.h>
 #include <linux/if_tunnel.h>
+#include <net/ip.h>
 
 
 /* Keep error state on tunnel for 30 sec */
 /* Keep error state on tunnel for 30 sec */
 #define IPTUNNEL_ERR_TIMEO	(30*HZ)
 #define IPTUNNEL_ERR_TIMEO	(30*HZ)
@@ -30,11 +31,9 @@ struct ip_tunnel
 	int pkt_len = skb->len;						\
 	int pkt_len = skb->len;						\
 									\
 									\
 	skb->ip_summed = CHECKSUM_NONE;					\
 	skb->ip_summed = CHECKSUM_NONE;					\
-	iph->tot_len = htons(skb->len);					\
 	ip_select_ident(iph, &rt->u.dst, NULL);				\
 	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) {					\
 	if (net_xmit_eval(err) == 0) {					\
 		stats->tx_bytes += pkt_len;				\
 		stats->tx_bytes += pkt_len;				\
 		stats->tx_packets++;					\
 		stats->tx_packets++;					\

+ 2 - 10
net/ipv4/igmp.c

@@ -349,17 +349,12 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
 
 
 static int igmpv3_sendpack(struct sk_buff *skb)
 static int igmpv3_sendpack(struct sk_buff *skb)
 {
 {
-	struct iphdr *pip = ip_hdr(skb);
 	struct igmphdr *pig = igmp_hdr(skb);
 	struct igmphdr *pig = igmp_hdr(skb);
-	const int iplen = skb->tail - skb->network_header;
 	const int igmplen = skb->tail - skb->transport_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);
 	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)
 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->daddr    = dst;
 	iph->saddr    = rt->rt_src;
 	iph->saddr    = rt->rt_src;
 	iph->protocol = IPPROTO_IGMP;
 	iph->protocol = IPPROTO_IGMP;
-	iph->tot_len  = htons(IGMP_SIZE);
 	ip_select_ident(iph, &rt->u.dst, NULL);
 	ip_select_ident(iph, &rt->u.dst, NULL);
 	((u8*)&iph[1])[0] = IPOPT_RA;
 	((u8*)&iph[1])[0] = IPOPT_RA;
 	((u8*)&iph[1])[1] = 4;
 	((u8*)&iph[1])[1] = 4;
 	((u8*)&iph[1])[2] = 0;
 	((u8*)&iph[1])[2] = 0;
 	((u8*)&iph[1])[3] = 0;
 	((u8*)&iph[1])[3] = 0;
-	ip_send_check(iph);
 
 
 	ih = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
 	ih = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
 	ih->type=type;
 	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->group=group;
 	ih->csum=ip_compute_csum((void *)ih, sizeof(struct igmphdr));
 	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)
 static void igmp_gq_timer_expire(unsigned long data)

+ 25 - 14
net/ipv4/ip_output.c

@@ -91,6 +91,28 @@ __inline__ void ip_send_check(struct iphdr *iph)
 	iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 	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. */
 /* dev_loopback_xmit for use with netfilter. */
 static int ip_dev_loopback_xmit(struct sk_buff *newskb)
 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->daddr    = rt->rt_dst;
 	iph->saddr    = rt->rt_src;
 	iph->saddr    = rt->rt_src;
 	iph->protocol = sk->sk_protocol;
 	iph->protocol = sk->sk_protocol;
-	iph->tot_len  = htons(skb->len);
 	ip_select_ident(iph, &rt->u.dst, sk);
 	ip_select_ident(iph, &rt->u.dst, sk);
 
 
 	if (opt && opt->optlen) {
 	if (opt && opt->optlen) {
 		iph->ihl += opt->optlen>>2;
 		iph->ihl += opt->optlen>>2;
 		ip_options_build(skb, opt, daddr, rt, 0);
 		ip_options_build(skb, opt, daddr, rt, 0);
 	}
 	}
-	ip_send_check(iph);
 
 
 	skb->priority = sk->sk_priority;
 	skb->priority = sk->sk_priority;
 
 
 	/* Send it out. */
 	/* 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);
 EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
@@ -347,7 +366,6 @@ packet_routed:
 	skb_reset_network_header(skb);
 	skb_reset_network_header(skb);
 	iph = ip_hdr(skb);
 	iph = ip_hdr(skb);
 	*((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff));
 	*((__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)
 	if (ip_dont_fragment(sk, &rt->u.dst) && !ipfragok)
 		iph->frag_off = htons(IP_DF);
 		iph->frag_off = htons(IP_DF);
 	else
 	else
@@ -366,13 +384,9 @@ packet_routed:
 	ip_select_ident_more(iph, &rt->u.dst, sk,
 	ip_select_ident_more(iph, &rt->u.dst, sk,
 			     (skb_shinfo(skb)->gso_segs ?: 1) - 1);
 			     (skb_shinfo(skb)->gso_segs ?: 1) - 1);
 
 
-	/* Add an IP checksum. */
-	ip_send_check(iph);
-
 	skb->priority = sk->sk_priority;
 	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:
 no_route:
 	IP_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
 	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);
 		ip_options_build(skb, opt, inet->cork.addr, rt, 0);
 	}
 	}
 	iph->tos = inet->tos;
 	iph->tos = inet->tos;
-	iph->tot_len = htons(skb->len);
 	iph->frag_off = df;
 	iph->frag_off = df;
 	ip_select_ident(iph, &rt->u.dst, sk);
 	ip_select_ident(iph, &rt->u.dst, sk);
 	iph->ttl = ttl;
 	iph->ttl = ttl;
 	iph->protocol = sk->sk_protocol;
 	iph->protocol = sk->sk_protocol;
 	iph->saddr = rt->rt_src;
 	iph->saddr = rt->rt_src;
 	iph->daddr = rt->rt_dst;
 	iph->daddr = rt->rt_dst;
-	ip_send_check(iph);
 
 
 	skb->priority = sk->sk_priority;
 	skb->priority = sk->sk_priority;
 	skb->dst = dst_clone(&rt->u.dst);
 	skb->dst = dst_clone(&rt->u.dst);
@@ -1279,8 +1291,7 @@ int ip_push_pending_frames(struct sock *sk)
 			skb_transport_header(skb))->type);
 			skb_transport_header(skb))->type);
 
 
 	/* Netfilter gets whole the not fragmented skb. */
 	/* 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) {
 		if (err > 0)
 		if (err > 0)
 			err = inet->recverr ? net_xmit_errno(err) : 0;
 			err = inet->recverr ? net_xmit_errno(err) : 0;

+ 2 - 4
net/ipv4/ipvs/ip_vs_xmit.c

@@ -16,8 +16,8 @@
  */
  */
 
 
 #include <linux/kernel.h>
 #include <linux/kernel.h>
-#include <linux/ip.h>
 #include <linux/tcp.h>                  /* for tcphdr */
 #include <linux/tcp.h>                  /* for tcphdr */
+#include <net/ip.h>
 #include <net/tcp.h>                    /* for csum_tcpudp_magic */
 #include <net/tcp.h>                    /* for csum_tcpudp_magic */
 #include <net/udp.h>
 #include <net/udp.h>
 #include <net/icmp.h>                   /* for icmp_send */
 #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->daddr		=	rt->rt_dst;
 	iph->saddr		=	rt->rt_src;
 	iph->saddr		=	rt->rt_src;
 	iph->ttl		=	old_iph->ttl;
 	iph->ttl		=	old_iph->ttl;
-	iph->tot_len		=	htons(skb->len);
 	ip_select_ident(iph, &rt->u.dst, NULL);
 	ip_select_ident(iph, &rt->u.dst, NULL);
-	ip_send_check(iph);
 
 
 	/* Another hack: avoid icmp_send in ip_fragment */
 	/* Another hack: avoid icmp_send in ip_fragment */
 	skb->local_df = 1;
 	skb->local_df = 1;
 
 
-	IP_VS_XMIT(skb, rt);
+	ip_local_out(skb);
 
 
 	LeaveFunction(10);
 	LeaveFunction(10);
 
 

+ 1 - 7
net/ipv4/netfilter/ipt_REJECT.c

@@ -90,7 +90,6 @@ static void send_reset(struct sk_buff *oldskb, int hook)
 	/* Truncate to length (no data) */
 	/* Truncate to length (no data) */
 	tcph->doff = sizeof(struct tcphdr)/4;
 	tcph->doff = sizeof(struct tcphdr)/4;
 	skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr));
 	skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr));
-	niph->tot_len = htons(nskb->len);
 
 
 	if (tcph->ack) {
 	if (tcph->ack) {
 		needs_ack = 0;
 		needs_ack = 0;
@@ -139,18 +138,13 @@ static void send_reset(struct sk_buff *oldskb, int hook)
 	/* Adjust IP TTL */
 	/* Adjust IP TTL */
 	niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
 	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" */
 	/* "Never happens" */
 	if (nskb->len > dst_mtu(nskb->dst))
 	if (nskb->len > dst_mtu(nskb->dst))
 		goto free_nskb;
 		goto free_nskb;
 
 
 	nf_ct_attach(nskb, oldskb);
 	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;
 	return;
 
 
  free_nskb:
  free_nskb:

+ 1 - 7
net/ipv4/xfrm4_output.c

@@ -69,17 +69,12 @@ EXPORT_SYMBOL(xfrm4_prepare_output);
 
 
 static inline int xfrm4_output_one(struct sk_buff *skb)
 static inline int xfrm4_output_one(struct sk_buff *skb)
 {
 {
-	struct iphdr *iph;
 	int err;
 	int err;
 
 
 	err = xfrm_output(skb);
 	err = xfrm_output(skb);
 	if (err)
 	if (err)
 		goto error_nolock;
 		goto error_nolock;
 
 
-	iph = ip_hdr(skb);
-	iph->tot_len = htons(skb->len);
-	ip_send_check(iph);
-
 	IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
 	IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;
 	err = 0;
 	err = 0;
 
 
@@ -97,8 +92,7 @@ static int xfrm4_output_finish2(struct sk_buff *skb)
 	while (likely((err = xfrm4_output_one(skb)) == 0)) {
 	while (likely((err = xfrm4_output_one(skb)) == 0)) {
 		nf_reset(skb);
 		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))
 		if (unlikely(err != 1))
 			break;
 			break;