At the moment, a fragment comes in, must be defragmented for
connection tracking. It is then forwarded, fragmented, then must be
defragemented AGAIN for NAT in POST_ROUTING hook. Ick.
This patch defers fragmentation to past the hook, by effectively
reversing ip_send and ip_finish_output (renaming ip_finish_output
because it's EXPORTed), and making everyone use ip_send (it's harmless
to set skb->dev and skb->protocol AFAICT).
I think this also means that the fragment: part in ip_queue_xmit2 can
be reduced, since skb->dst->output() will now do fragmenting.
This is a patch mainly to how much Alexey hates it. 8-)
Rusty.
PS. Alexey; I saw your photograph in Linux Magazine: very
disappointed! I hope, at least, that *your* head? 8-)
diff -ur linux-2.3-official/include/net/ip.h linux-2.3-mangled/include/net/ip.h
--- linux-2.3-official/include/net/ip.h Tue Nov 30 19:08:08 1999
+++ linux-2.3-mangled/include/net/ip.h Tue Nov 30 21:43:10 1999
@@ -29,6 +29,7 @@
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/in_route.h>
+#include <linux/netfilter_ipv4.h>
#include <net/route.h>
#include <net/arp.h>
@@ -138,7 +139,7 @@
void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg
*arg,
unsigned int len);
-extern __inline__ int ip_finish_output(struct sk_buff *skb);
+extern int ip_finish_output_and_frag(struct sk_buff *skb);
struct ipv4_config
{
@@ -156,10 +157,13 @@
#ifdef CONFIG_INET
extern __inline__ int ip_send(struct sk_buff *skb)
{
- if (skb->len > skb->dst->pmtu)
- return ip_fragment(skb, ip_finish_output);
- else
- return ip_finish_output(skb);
+ struct net_device *dev = skb->dst->dev;
+
+ skb->dev = dev;
+ skb->protocol = __constant_htons(ETH_P_IP);
+
+ return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
+ ip_finish_output_and_frag);
}
extern __inline__
diff -ur linux-2.3-official/net/ipv4/ip_output.c
linux-2.3-mangled/net/ipv4/ip_output.c
--- linux-2.3-official/net/ipv4/ip_output.c Tue Nov 30 17:58:59 1999
+++ linux-2.3-mangled/net/ipv4/ip_output.c Tue Nov 30 21:45:38 1999
@@ -209,22 +209,18 @@
return -EINVAL;
}
-__inline__ int ip_finish_output(struct sk_buff *skb)
+int ip_finish_output_and_frag(struct sk_buff *skb)
{
- struct net_device *dev = skb->dst->dev;
-
- skb->dev = dev;
- skb->protocol = __constant_htons(ETH_P_IP);
-
- return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
- ip_finish_output2);
+ if (skb->len > skb->dst->pmtu)
+ return ip_fragment(skb, ip_finish_output2);
+ else
+ return ip_finish_output2(skb);
}
int ip_mc_output(struct sk_buff *skb)
{
struct sock *sk = skb->sk;
struct rtable *rt = (struct rtable*)skb->dst;
- struct net_device *dev = rt->u.dst.dev;
/*
* If the indicated interface is up and running, send the packet.
@@ -235,9 +231,6 @@
ip_do_nat(skb);
#endif
- skb->dev = dev;
- skb->protocol = __constant_htons(ETH_P_IP);
-
/*
* Multicasts are looped back for other local users
*/
@@ -277,7 +270,7 @@
newskb->dev, ip_dev_loopback_xmit);
}
- return ip_finish_output(skb);
+ return ip_send(skb);
}
int ip_output(struct sk_buff *skb)
@@ -293,7 +286,7 @@
ip_do_nat(skb);
#endif
- return ip_finish_output(skb);
+ return ip_send(skb);
}
/* Queues a packet to be sent, and starts the transmitter if necessary.
@@ -837,6 +830,8 @@
skb2->pkt_type = skb->pkt_type;
skb2->priority = skb->priority;
+ skb2->dev = skb->dev;
+ skb2->protocol = skb->protocol;
skb_reserve(skb2, (dev->hard_header_len+15)&~15);
skb_put(skb2, len + hlen);
skb2->nh.raw = skb2->data;
diff -ur linux-2.3-official/net/netsyms.c linux-2.3-mangled/net/netsyms.c
--- linux-2.3-official/net/netsyms.c Tue Nov 30 17:58:59 1999
+++ linux-2.3-mangled/net/netsyms.c Tue Nov 30 21:36:48 1999
@@ -239,7 +239,7 @@
EXPORT_SYMBOL(in_aton);
EXPORT_SYMBOL(ip_mc_inc_group);
EXPORT_SYMBOL(ip_mc_dec_group);
-EXPORT_SYMBOL(ip_finish_output);
+EXPORT_SYMBOL(ip_finish_output_and_frag);
EXPORT_SYMBOL(inet_dgram_ops);
EXPORT_SYMBOL(ip_cmsg_recv);
EXPORT_SYMBOL(inet_addr_type);
--
Hacking time.
|