Netdev List
 help / color / mirror / Atom feed
* Re: [PKT_SCHED]: Add stateless NAT
From: Evgeniy Polyakov @ 2007-09-27 13:29 UTC (permalink / raw)
  To: Herbert Xu; +Cc: David S. Miller, netdev, Alexey Kuznetsov, jamal
In-Reply-To: <20070927132037.GA17056@gondor.apana.org.au>

On Thu, Sep 27, 2007 at 09:20:37PM +0800, Herbert Xu (herbert@gondor.apana.org.au) wrote:
> How about putting it in net/core/utils.c?

I knew, that was a bad idea to try to fix netfilter dependency :)

diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 1dd075e..51b5a22 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -40,6 +40,35 @@
 #endif
 
 #ifdef __KERNEL__
+
+static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
+{
+	__be32 diff[] = { ~from, to };
+
+	*sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum)));
+}
+
+static inline void nf_csum_replace2(__sum16 *sum, __be16 from, __be16 to)
+{
+	nf_csum_replace4(sum, (__force __be32)from, (__force __be32)to);
+}
+
+extern void proto_csum_replace(__sum16 *sum, struct sk_buff *skb,
+			    __be32 from, __be32 to, int pseudohdr);
+
+static inline void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
+			    __be32 from, __be32 to, int pseudohdr)
+{
+	proto_csum_replace(sum, skb, from, to, pseudohdr);
+}
+
+static inline void nf_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
+				      __be16 from, __be16 to, int pseudohdr)
+{
+	nf_proto_csum_replace4(sum, skb, (__force __be32)from,
+				(__force __be32)to, pseudohdr);
+}
+
 #ifdef CONFIG_NETFILTER
 
 extern void netfilter_init(void);
@@ -289,28 +318,6 @@ extern void nf_invalidate_cache(int pf);
    Returns true or false. */
 extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len);
 
-static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
-{
-	__be32 diff[] = { ~from, to };
-
-	*sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum)));
-}
-
-static inline void nf_csum_replace2(__sum16 *sum, __be16 from, __be16 to)
-{
-	nf_csum_replace4(sum, (__force __be32)from, (__force __be32)to);
-}
-
-extern void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
-				      __be32 from, __be32 to, int pseudohdr);
-
-static inline void nf_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
-				      __be16 from, __be16 to, int pseudohdr)
-{
-	nf_proto_csum_replace4(sum, skb, (__force __be32)from,
-				(__force __be32)to, pseudohdr);
-}
-
 struct nf_afinfo {
 	unsigned short	family;
 	__sum16		(*checksum)(struct sk_buff *skb, unsigned int hook,
diff --git a/net/core/utils.c b/net/core/utils.c
index 0bf17da..2f6d4d2 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -293,3 +293,20 @@ out:
 }
 
 EXPORT_SYMBOL(in6_pton);
+
+void proto_csum_replace(__sum16 *sum, struct sk_buff *skb,
+			    __be32 from, __be32 to, int pseudohdr)
+{
+	__be32 diff[] = { ~from, to };
+	if (skb->ip_summed != CHECKSUM_PARTIAL) {
+		*sum = csum_fold(csum_partial(diff, sizeof(diff),
+				~csum_unfold(*sum)));
+		if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
+			skb->csum = ~csum_partial(diff, sizeof(diff),
+						~skb->csum);
+	} else if (pseudohdr)
+		*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
+				csum_unfold(*sum)));
+}
+
+EXPORT_SYMBOL(proto_csum_replace);
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 381a77c..9ffbbe2 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -226,22 +226,6 @@ copy_skb:
 }
 EXPORT_SYMBOL(skb_make_writable);
 
-void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
-			    __be32 from, __be32 to, int pseudohdr)
-{
-	__be32 diff[] = { ~from, to };
-	if (skb->ip_summed != CHECKSUM_PARTIAL) {
-		*sum = csum_fold(csum_partial(diff, sizeof(diff),
-				~csum_unfold(*sum)));
-		if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
-			skb->csum = ~csum_partial(diff, sizeof(diff),
-						~skb->csum);
-	} else if (pseudohdr)
-		*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
-				csum_unfold(*sum)));
-}
-EXPORT_SYMBOL(nf_proto_csum_replace4);
-
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 /* This does not belong here, but locally generated errors need it if connection
    tracking in use: without this, connection may not be in hash table, and hence

-- 
	Evgeniy Polyakov

^ permalink raw reply related

* Re: [PKT_SCHED]: Add stateless NAT
From: Evgeniy Polyakov @ 2007-09-27 13:25 UTC (permalink / raw)
  To: Patrick McHardy
  Cc: Herbert Xu, David S. Miller, netdev, Alexey Kuznetsov, jamal
In-Reply-To: <46FBAD40.8040806@trash.net>

On Thu, Sep 27, 2007 at 03:16:48PM +0200, Patrick McHardy (kaber@trash.net) wrote:
> Evgeniy Polyakov wrote:
> > +static inline void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
> > +			    __be32 from, __be32 to, int pseudohdr)
> > +{
> > +	__be32 diff[] = { ~from, to };
> > +	if (skb->ip_summed != CHECKSUM_PARTIAL) {
> > +		*sum = csum_fold(csum_partial(diff, sizeof(diff),
> > +				~csum_unfold(*sum)));
> > +		if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
> > +			skb->csum = ~csum_partial(diff, sizeof(diff),
> > +						~skb->csum);
> > +	} else if (pseudohdr)
> > +		*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
> > +				csum_unfold(*sum)));
> > +}
> > +
> > +static inline void nf_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
> > +				      __be16 from, __be16 to, int pseudohdr)
> > +{
> > +	nf_proto_csum_replace4(sum, skb, (__force __be32)from,
> > +				(__force __be32)to, pseudohdr);
> > +}
> 
> 
> These are way too large to get inlined, please move somewhere below
> net/core.

I knew that... :)
I'm pretty sure new files called net/core/helpers.c which will host that
helper is not a good solution too?

diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 1dd075e..624d78b 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -40,6 +40,29 @@
 #endif
 
 #ifdef __KERNEL__
+
+static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
+{
+	__be32 diff[] = { ~from, to };
+
+	*sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum)));
+}
+
+static inline void nf_csum_replace2(__sum16 *sum, __be16 from, __be16 to)
+{
+	nf_csum_replace4(sum, (__force __be32)from, (__force __be32)to);
+}
+
+extern void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
+			    __be32 from, __be32 to, int pseudohdr);
+
+static inline void nf_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
+				      __be16 from, __be16 to, int pseudohdr)
+{
+	nf_proto_csum_replace4(sum, skb, (__force __be32)from,
+				(__force __be32)to, pseudohdr);
+}
+
 #ifdef CONFIG_NETFILTER
 
 extern void netfilter_init(void);
@@ -289,28 +312,6 @@ extern void nf_invalidate_cache(int pf);
    Returns true or false. */
 extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len);
 
-static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
-{
-	__be32 diff[] = { ~from, to };
-
-	*sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum)));
-}
-
-static inline void nf_csum_replace2(__sum16 *sum, __be16 from, __be16 to)
-{
-	nf_csum_replace4(sum, (__force __be32)from, (__force __be32)to);
-}
-
-extern void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
-				      __be32 from, __be32 to, int pseudohdr);
-
-static inline void nf_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
-				      __be16 from, __be16 to, int pseudohdr)
-{
-	nf_proto_csum_replace4(sum, skb, (__force __be32)from,
-				(__force __be32)to, pseudohdr);
-}
-
 struct nf_afinfo {
 	unsigned short	family;
 	__sum16		(*checksum)(struct sk_buff *skb, unsigned int hook,
diff --git a/net/core/Makefile b/net/core/Makefile
index 4751613..5757323 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -3,7 +3,7 @@
 #
 
 obj-y := sock.o request_sock.o skbuff.o iovec.o datagram.o stream.o scm.o \
-	 gen_stats.o gen_estimator.o
+	 gen_stats.o gen_estimator.o helpers.o
 
 obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
 
diff --git a/net/core/helpers.c b/net/core/helpers.c
new file mode 100644
index 0000000..d3c8d97
--- /dev/null
+++ b/net/core/helpers.c
@@ -0,0 +1,23 @@
+/*
+ * Generic helper functions.
+ */
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+
+#include <net/checksum.h>
+
+void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
+			    __be32 from, __be32 to, int pseudohdr)
+{
+	__be32 diff[] = { ~from, to };
+	if (skb->ip_summed != CHECKSUM_PARTIAL) {
+		*sum = csum_fold(csum_partial(diff, sizeof(diff),
+				~csum_unfold(*sum)));
+		if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
+			skb->csum = ~csum_partial(diff, sizeof(diff),
+						~skb->csum);
+	} else if (pseudohdr)
+		*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
+				csum_unfold(*sum)));
+}
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 381a77c..9ffbbe2 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -226,22 +226,6 @@ copy_skb:
 }
 EXPORT_SYMBOL(skb_make_writable);
 
-void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
-			    __be32 from, __be32 to, int pseudohdr)
-{
-	__be32 diff[] = { ~from, to };
-	if (skb->ip_summed != CHECKSUM_PARTIAL) {
-		*sum = csum_fold(csum_partial(diff, sizeof(diff),
-				~csum_unfold(*sum)));
-		if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
-			skb->csum = ~csum_partial(diff, sizeof(diff),
-						~skb->csum);
-	} else if (pseudohdr)
-		*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
-				csum_unfold(*sum)));
-}
-EXPORT_SYMBOL(nf_proto_csum_replace4);
-
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 /* This does not belong here, but locally generated errors need it if connection
    tracking in use: without this, connection may not be in hash table, and hence


-- 
	Evgeniy Polyakov

^ permalink raw reply related

* Re: [PKT_SCHED]: Add stateless NAT
From: Herbert Xu @ 2007-09-27 13:20 UTC (permalink / raw)
  To: Evgeniy Polyakov; +Cc: David S. Miller, netdev, Alexey Kuznetsov, jamal
In-Reply-To: <20070927131008.GA15997@2ka.mipt.ru>

On Thu, Sep 27, 2007 at 05:10:08PM +0400, Evgeniy Polyakov wrote:
>
> +static inline void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
> +			    __be32 from, __be32 to, int pseudohdr)
> +{
> +	__be32 diff[] = { ~from, to };
> +	if (skb->ip_summed != CHECKSUM_PARTIAL) {
> +		*sum = csum_fold(csum_partial(diff, sizeof(diff),
> +				~csum_unfold(*sum)));
> +		if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
> +			skb->csum = ~csum_partial(diff, sizeof(diff),
> +						~skb->csum);
> +	} else if (pseudohdr)
> +		*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
> +				csum_unfold(*sum)));
> +}

The embedded people are going to hate you for this :)

How about putting it in net/core/utils.c?

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* Re: [PKT_SCHED]: Add stateless NAT
From: Patrick McHardy @ 2007-09-27 13:16 UTC (permalink / raw)
  To: Evgeniy Polyakov
  Cc: Herbert Xu, David S. Miller, netdev, Alexey Kuznetsov, jamal
In-Reply-To: <20070927131008.GA15997@2ka.mipt.ru>

Evgeniy Polyakov wrote:
> +static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
> +{
> +	__be32 diff[] = { ~from, to };
> +
> +	*sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum)));
> +}
> +
> +static inline void nf_csum_replace2(__sum16 *sum, __be16 from, __be16 to)
> +{
> +	nf_csum_replace4(sum, (__force __be32)from, (__force __be32)to);
> +}
> +
> +static inline void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
> +			    __be32 from, __be32 to, int pseudohdr)
> +{
> +	__be32 diff[] = { ~from, to };
> +	if (skb->ip_summed != CHECKSUM_PARTIAL) {
> +		*sum = csum_fold(csum_partial(diff, sizeof(diff),
> +				~csum_unfold(*sum)));
> +		if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
> +			skb->csum = ~csum_partial(diff, sizeof(diff),
> +						~skb->csum);
> +	} else if (pseudohdr)
> +		*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
> +				csum_unfold(*sum)));
> +}
> +
> +static inline void nf_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
> +				      __be16 from, __be16 to, int pseudohdr)
> +{
> +	nf_proto_csum_replace4(sum, skb, (__force __be32)from,
> +				(__force __be32)to, pseudohdr);
> +}


These are way too large to get inlined, please move somewhere below
net/core.

^ permalink raw reply

* Re: [PKT_SCHED]: Add stateless NAT
From: jamal @ 2007-09-27 13:16 UTC (permalink / raw)
  To: Herbert Xu; +Cc: Stephen Hemminger, David S. Miller, netdev, Alexey Kuznetsov
In-Reply-To: <20070927130104.GA16881@gondor.apana.org.au>

On Thu, 2007-27-09 at 21:01 +0800, Herbert Xu wrote:
> On Thu, Sep 27, 2007 at 08:39:45AM -0400, jamal wrote:
> >
> > Do you have plans to do the iproute bits? If you do it will be nice to
> > also update the doc/examples with some simple example(s).
> 
> Oh yes, I didn't test this by poking bits in the kernel
> you know :)

Trust me - it has been done before ;->

Thanks Herbert, looks good to me. 

cheers,
jamal



^ permalink raw reply

* RTL8111 PCI Express Gigabit driver r8169 produces slow file transfers
From: Achim Frase @ 2007-09-27 13:14 UTC (permalink / raw)
  To: netdev

Dear Linux r8169 crew,

I have got your e-mail address from the modinfo of the r8196 module.

I am not sure if this is the right way to contact you, but I hope you
could help me.

The current driver in Kernel 2.6.22 produces very bad network speeds.
I only geht 100 kb/s.

Maybe you could take a look at this bug-report at launchpad.net.

https://bugs.launchpad.net/ubuntu/+source/linux-ubuntu-modules-2.6.22/+bug/114171

The latest driver from realtek is working very well.
ftp://210.51.181.211/cn/nic/r8168-8.003.00.tar.bz2

What I would like to know, is, if the latest realtek driver will make it
into the kernel, or if the problems with the r8196 module are already
solved.

If there are any questions feel free to contact me.

Thanks in Advanced

Achim Frase


^ permalink raw reply

* Re: [PKT_SCHED]: Add stateless NAT
From: Evgeniy Polyakov @ 2007-09-27 13:10 UTC (permalink / raw)
  To: Herbert Xu; +Cc: David S. Miller, netdev, Alexey Kuznetsov, jamal
In-Reply-To: <20070927124515.GA16706@gondor.apana.org.au>

On Thu, Sep 27, 2007 at 08:45:15PM +0800, Herbert Xu (herbert@gondor.apana.org.au) wrote:
> On Thu, Sep 27, 2007 at 04:41:21PM +0400, Evgeniy Polyakov wrote:
> >
> > I've attached simple patch which moves checksum helpers out of
> > CONFIG_NETFILTER option but still in the same linux/netfilter.h header.
> > This should be enough for removing 'select NETFILTER' in your patch.
> 
> Close but no cigar :)

:) take 2.

diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 1dd075e..5313739 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -40,6 +40,41 @@
 #endif
 
 #ifdef __KERNEL__
+
+static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
+{
+	__be32 diff[] = { ~from, to };
+
+	*sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum)));
+}
+
+static inline void nf_csum_replace2(__sum16 *sum, __be16 from, __be16 to)
+{
+	nf_csum_replace4(sum, (__force __be32)from, (__force __be32)to);
+}
+
+static inline void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
+			    __be32 from, __be32 to, int pseudohdr)
+{
+	__be32 diff[] = { ~from, to };
+	if (skb->ip_summed != CHECKSUM_PARTIAL) {
+		*sum = csum_fold(csum_partial(diff, sizeof(diff),
+				~csum_unfold(*sum)));
+		if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
+			skb->csum = ~csum_partial(diff, sizeof(diff),
+						~skb->csum);
+	} else if (pseudohdr)
+		*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
+				csum_unfold(*sum)));
+}
+
+static inline void nf_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
+				      __be16 from, __be16 to, int pseudohdr)
+{
+	nf_proto_csum_replace4(sum, skb, (__force __be32)from,
+				(__force __be32)to, pseudohdr);
+}
+
 #ifdef CONFIG_NETFILTER
 
 extern void netfilter_init(void);
@@ -289,28 +324,6 @@ extern void nf_invalidate_cache(int pf);
    Returns true or false. */
 extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len);
 
-static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
-{
-	__be32 diff[] = { ~from, to };
-
-	*sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum)));
-}
-
-static inline void nf_csum_replace2(__sum16 *sum, __be16 from, __be16 to)
-{
-	nf_csum_replace4(sum, (__force __be32)from, (__force __be32)to);
-}
-
-extern void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
-				      __be32 from, __be32 to, int pseudohdr);
-
-static inline void nf_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
-				      __be16 from, __be16 to, int pseudohdr)
-{
-	nf_proto_csum_replace4(sum, skb, (__force __be32)from,
-				(__force __be32)to, pseudohdr);
-}
-
 struct nf_afinfo {
 	unsigned short	family;
 	__sum16		(*checksum)(struct sk_buff *skb, unsigned int hook,
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 381a77c..9ffbbe2 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -226,22 +226,6 @@ copy_skb:
 }
 EXPORT_SYMBOL(skb_make_writable);
 
-void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
-			    __be32 from, __be32 to, int pseudohdr)
-{
-	__be32 diff[] = { ~from, to };
-	if (skb->ip_summed != CHECKSUM_PARTIAL) {
-		*sum = csum_fold(csum_partial(diff, sizeof(diff),
-				~csum_unfold(*sum)));
-		if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
-			skb->csum = ~csum_partial(diff, sizeof(diff),
-						~skb->csum);
-	} else if (pseudohdr)
-		*sum = ~csum_fold(csum_partial(diff, sizeof(diff),
-				csum_unfold(*sum)));
-}
-EXPORT_SYMBOL(nf_proto_csum_replace4);
-
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
 /* This does not belong here, but locally generated errors need it if connection
    tracking in use: without this, connection may not be in hash table, and hence

-- 
	Evgeniy Polyakov

^ permalink raw reply related

* Re: [PKT_SCHED]: Add stateless NAT
From: Herbert Xu @ 2007-09-27 12:58 UTC (permalink / raw)
  To: jamal; +Cc: David S. Miller, netdev, Alexey Kuznetsov
In-Reply-To: <1190896785.4290.18.camel@localhost>

On Thu, Sep 27, 2007 at 08:39:45AM -0400, jamal wrote:
>
> You also need to p->tcf_qstats.drops++ for all packets that get shot.

I was rather hoping that my packets wouldn't get shot :)
But yeah let's increment the drops counter for consistency.

[PKT_SCHED]: Add stateless NAT

Stateless NAT is useful in controlled environments where restrictions are
placed on through traffic such that we don't need connection tracking to
correctly NAT protocol-specific data.

In particular, this is of interest when the number of flows or the number
of addresses being NATed is large, or if connection tracking information
has to be replicated and where it is not practical to do so.

Previously we had stateless NAT functionality which was integrated into
the IPv4 routing subsystem.  This was a great solution as long as the NAT
worked on a subnet to subnet basis such that the number of NAT rules was
relatively small.  The reason is that for SNAT the routing based system
had to perform a linear scan through the rules.

If the number of rules is large then major renovations would have take
place in the routing subsystem to make this practical.

For the time being, the least intrusive way of achieving this is to use
the u32 classifier written by Alexey Kuznetsov along with the actions
infrastructure implemented by Jamal Hadi Salim.

The following patch is an attempt at this problem by creating a new nat
action that can be invoked from u32 hash tables which would allow large
number of stateless NAT rules that can be used/updated in constant time.

The actual NAT code is mostly based on the previous stateless NAT code
written by Alexey.  In future we might be able to utilise the protocol
NAT code from netfilter to improve support for other protocols.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Thanks,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
diff --git a/include/linux/tc_act/tc_nat.h b/include/linux/tc_act/tc_nat.h
new file mode 100644
index 0000000..9280c6f
--- /dev/null
+++ b/include/linux/tc_act/tc_nat.h
@@ -0,0 +1,29 @@
+#ifndef __LINUX_TC_NAT_H
+#define __LINUX_TC_NAT_H
+
+#include <linux/pkt_cls.h>
+#include <linux/types.h>
+
+#define TCA_ACT_NAT 9
+
+enum
+{
+	TCA_NAT_UNSPEC,
+	TCA_NAT_PARMS,
+	TCA_NAT_TM,
+	__TCA_NAT_MAX
+};
+#define TCA_NAT_MAX (__TCA_NAT_MAX - 1)
+
+#define TCA_NAT_FLAG_EGRESS 1
+                                                                               
+struct tc_nat
+{
+	tc_gen;
+	__be32 old_addr;
+	__be32 new_addr;
+	__be32 mask;
+	__u32 flags;
+};
+
+#endif
diff --git a/include/net/tc_act/tc_nat.h b/include/net/tc_act/tc_nat.h
new file mode 100644
index 0000000..4a691f3
--- /dev/null
+++ b/include/net/tc_act/tc_nat.h
@@ -0,0 +1,21 @@
+#ifndef __NET_TC_NAT_H
+#define __NET_TC_NAT_H
+
+#include <linux/types.h>
+#include <net/act_api.h>
+
+struct tcf_nat {
+	struct tcf_common common;
+
+	__be32 old_addr;
+	__be32 new_addr;
+	__be32 mask;
+	u32 flags;
+};
+
+static inline struct tcf_nat *to_tcf_nat(struct tcf_common *pc)
+{
+	return container_of(pc, struct tcf_nat, common);
+}
+
+#endif /* __NET_TC_NAT_H */
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 8a74cac..92435a8 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -447,6 +447,17 @@ config NET_ACT_IPT
 	  To compile this code as a module, choose M here: the
 	  module will be called ipt.
 
+config NET_ACT_NAT
+        tristate "Stateless NAT"
+        depends on NET_CLS_ACT
+        select NETFILTER
+        ---help---
+	  Say Y here to do stateless NAT on IPv4 packets.  You should use
+	  netfilter for NAT unless you know what you are doing.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called nat.
+
 config NET_ACT_PEDIT
         tristate "Packet Editing"
         depends on NET_CLS_ACT
diff --git a/net/sched/Makefile b/net/sched/Makefile
index b67c36f..81ecbe8 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_NET_ACT_POLICE)	+= act_police.o
 obj-$(CONFIG_NET_ACT_GACT)	+= act_gact.o
 obj-$(CONFIG_NET_ACT_MIRRED)	+= act_mirred.o
 obj-$(CONFIG_NET_ACT_IPT)	+= act_ipt.o
+obj-$(CONFIG_NET_ACT_NAT)	+= act_nat.o
 obj-$(CONFIG_NET_ACT_PEDIT)	+= act_pedit.o
 obj-$(CONFIG_NET_ACT_SIMP)	+= act_simple.o
 obj-$(CONFIG_NET_SCH_FIFO)	+= sch_fifo.o
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
new file mode 100644
index 0000000..1bce750
--- /dev/null
+++ b/net/sched/act_nat.c
@@ -0,0 +1,322 @@
+/*
+ * Stateless NAT actions
+ *
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/rtnetlink.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/tc_act/tc_nat.h>
+#include <net/act_api.h>
+#include <net/icmp.h>
+#include <net/ip.h>
+#include <net/netlink.h>
+#include <net/tc_act/tc_nat.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+
+
+#define NAT_TAB_MASK	15
+static struct tcf_common *tcf_nat_ht[NAT_TAB_MASK + 1];
+static u32 nat_idx_gen;
+static DEFINE_RWLOCK(nat_lock);
+
+static struct tcf_hashinfo nat_hash_info = {
+	.htab	=	tcf_nat_ht,
+	.hmask	=	NAT_TAB_MASK,
+	.lock	=	&nat_lock,
+};
+
+static int tcf_nat_init(struct rtattr *rta, struct rtattr *est,
+			struct tc_action *a, int ovr, int bind)
+{
+	struct rtattr *tb[TCA_NAT_MAX];
+	struct tc_nat *parm;
+	int ret = 0;
+	struct tcf_nat *p;
+	struct tcf_common *pc;
+
+	if (rta == NULL || rtattr_parse_nested(tb, TCA_NAT_MAX, rta) < 0)
+		return -EINVAL;
+
+	if (tb[TCA_NAT_PARMS - 1] == NULL ||
+	    RTA_PAYLOAD(tb[TCA_NAT_PARMS - 1]) < sizeof(*parm))
+		return -EINVAL;
+	parm = RTA_DATA(tb[TCA_NAT_PARMS - 1]);
+
+	pc = tcf_hash_check(parm->index, a, bind, &nat_hash_info);
+	if (!pc) {
+		pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
+				     &nat_idx_gen, &nat_hash_info);
+		if (unlikely(!pc))
+			return -ENOMEM;
+		p = to_tcf_nat(pc);
+		ret = ACT_P_CREATED;
+	} else {
+		p = to_tcf_nat(pc);
+		if (!ovr) {
+			tcf_hash_release(pc, bind, &nat_hash_info);
+			return -EEXIST;
+		}
+	}
+
+	spin_lock_bh(&p->tcf_lock);
+	p->old_addr = parm->old_addr;
+	p->new_addr = parm->new_addr;
+	p->mask = parm->mask;
+	p->flags = parm->flags;
+
+	p->tcf_action = parm->action;
+	spin_unlock_bh(&p->tcf_lock);
+
+	if (ret == ACT_P_CREATED)
+		tcf_hash_insert(pc, &nat_hash_info);
+
+	return ret;
+}
+
+static int tcf_nat_cleanup(struct tc_action *a, int bind)
+{
+	struct tcf_nat *p = a->priv;
+
+	return tcf_hash_release(&p->common, bind, &nat_hash_info);
+}
+
+static int tcf_nat(struct sk_buff *skb, struct tc_action *a,
+		   struct tcf_result *res)
+{
+	struct tcf_nat *p = a->priv;
+	struct iphdr *iph;
+	__be32 old_addr;
+	__be32 new_addr;
+	__be32 mask;
+	__be32 addr;
+	int egress;
+	int action;
+	int ihl;
+
+	spin_lock(&p->tcf_lock);
+
+	p->tcf_tm.lastuse = jiffies;
+	old_addr = p->old_addr;
+	new_addr = p->new_addr;
+	mask = p->mask;
+	egress = p->flags & TCA_NAT_FLAG_EGRESS;
+	action = p->tcf_action;
+
+	p->tcf_bstats.bytes += skb->len;
+	p->tcf_bstats.packets++;
+
+	spin_unlock(&p->tcf_lock);
+
+	if (unlikely(action == TC_ACT_SHOT))
+		goto drop;
+
+	if (!pskb_may_pull(skb, sizeof(*iph)))
+		goto drop;
+
+	iph = ip_hdr(skb);
+
+	if (egress)
+		addr = iph->saddr;
+	else
+		addr = iph->daddr;
+
+	if (!((old_addr ^ addr) & mask)) {
+		if (skb_cloned(skb) &&
+		    !skb_clone_writable(skb, sizeof(*iph)) &&
+		    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+			goto drop;
+
+		new_addr &= mask;
+		new_addr |= addr & ~mask;
+
+		/* Rewrite IP header */
+		iph = ip_hdr(skb);
+		if (egress)
+			iph->saddr = new_addr;
+		else
+			iph->daddr = new_addr;
+
+		nf_csum_replace4(&iph->check, addr, new_addr);
+	}
+
+	ihl = iph->ihl * 4;
+
+	/* It would be nice to share code with stateful NAT. */
+	switch (iph->frag_off & htons(IP_OFFSET) ? 0 : iph->protocol) {
+	case IPPROTO_TCP:
+	{
+		struct tcphdr *tcph;
+
+		if (!pskb_may_pull(skb, ihl + sizeof(*tcph)) ||
+		    (skb_cloned(skb) &&
+		     !skb_clone_writable(skb, ihl + sizeof(*tcph)) &&
+		     pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+			goto drop;
+
+		tcph = (void *)(skb_network_header(skb) + ihl);
+		nf_proto_csum_replace4(&tcph->check, skb, addr, new_addr, 1);
+		break;
+	}
+	case IPPROTO_UDP:
+	{
+		struct udphdr *udph;
+
+		if (!pskb_may_pull(skb, ihl + sizeof(*udph)) ||
+		    (skb_cloned(skb) &&
+		     !skb_clone_writable(skb, ihl + sizeof(*udph)) &&
+		     pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+			goto drop;
+
+		udph = (void *)(skb_network_header(skb) + ihl);
+		if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) {
+			nf_proto_csum_replace4(&udph->check, skb, addr,
+					       new_addr, 1);
+			if (!udph->check)
+				udph->check = CSUM_MANGLED_0;
+		}
+		break;
+	}
+	case IPPROTO_ICMP:
+	{
+		struct icmphdr *icmph;
+
+		if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph)))
+			goto drop;
+
+		icmph = (void *)(skb_network_header(skb) + ihl);
+
+		if ((icmph->type != ICMP_DEST_UNREACH) &&
+		    (icmph->type != ICMP_TIME_EXCEEDED) &&
+		    (icmph->type != ICMP_PARAMETERPROB))
+			break;
+
+		iph = (void *)(icmph + 1);
+		if (egress)
+			addr = iph->daddr;
+		else
+			addr = iph->saddr;
+
+		if ((old_addr ^ addr) & mask)
+			break;
+
+		if (skb_cloned(skb) &&
+		    !skb_clone_writable(skb,
+		    			ihl + sizeof(*icmph) + sizeof(*iph)) &&
+		    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+			goto drop;
+
+		icmph = (void *)(skb_network_header(skb) + ihl);
+		iph = (void *)(icmph + 1);
+
+		new_addr &= mask;
+		new_addr |= addr & ~mask;
+
+		/* XXX Fix up the inner checksums. */
+		if (egress)
+			iph->daddr = new_addr;
+		else
+			iph->saddr = new_addr;
+
+		nf_proto_csum_replace4(&icmph->checksum, skb, addr, new_addr,
+				       1);
+		break;
+	}
+	default:
+		break;
+	}
+
+	return action;
+
+drop:
+	spin_lock(&p->tcf_lock);
+	p->tcf_qstats.drops++;
+	spin_unlock(&p->tcf_lock);
+	return TC_ACT_SHOT;
+}
+
+static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a,
+			int bind, int ref)
+{
+	unsigned char *b = skb_tail_pointer(skb);
+	struct tcf_nat *p = a->priv;
+	struct tc_nat *opt;
+	struct tcf_t t;
+	int s;
+
+	s = sizeof(*opt);
+
+	/* netlink spinlocks held above us - must use ATOMIC */
+	opt = kzalloc(s, GFP_ATOMIC);
+	if (unlikely(!opt))
+		return -ENOBUFS;
+
+	opt->old_addr = p->old_addr;
+	opt->new_addr = p->new_addr;
+	opt->mask = p->mask;
+	opt->flags = p->flags;
+
+	opt->index = p->tcf_index;
+	opt->action = p->tcf_action;
+	opt->refcnt = p->tcf_refcnt - ref;
+	opt->bindcnt = p->tcf_bindcnt - bind;
+
+	RTA_PUT(skb, TCA_NAT_PARMS, s, opt);
+	t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install);
+	t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse);
+	t.expires = jiffies_to_clock_t(p->tcf_tm.expires);
+	RTA_PUT(skb, TCA_NAT_TM, sizeof(t), &t);
+
+	kfree(opt);
+
+	return skb->len;
+
+rtattr_failure:
+	nlmsg_trim(skb, b);
+	kfree(opt);
+	return -1;
+}
+
+static struct tc_action_ops act_nat_ops = {
+	.kind		=	"nat",
+	.hinfo		=	&nat_hash_info,
+	.type		=	TCA_ACT_NAT,
+	.capab		=	TCA_CAP_NONE,
+	.owner		=	THIS_MODULE,
+	.act		=	tcf_nat,
+	.dump		=	tcf_nat_dump,
+	.cleanup	=	tcf_nat_cleanup,
+	.lookup		=	tcf_hash_search,
+	.init		=	tcf_nat_init,
+	.walk		=	tcf_generic_walker
+};
+
+MODULE_DESCRIPTION("Stateless NAT actions");
+MODULE_LICENSE("GPL");
+
+static int __init nat_init_module(void)
+{
+	return tcf_register_action(&act_nat_ops);
+}
+
+static void __exit nat_cleanup_module(void)
+{
+	tcf_unregister_action(&act_nat_ops);
+}
+
+module_init(nat_init_module);
+module_exit(nat_cleanup_module);

^ permalink raw reply related

* Re: [PKT_SCHED]: Add stateless NAT
From: Herbert Xu @ 2007-09-27 13:01 UTC (permalink / raw)
  To: jamal, Stephen Hemminger; +Cc: David S. Miller, netdev, Alexey Kuznetsov
In-Reply-To: <1190896785.4290.18.camel@localhost>

On Thu, Sep 27, 2007 at 08:39:45AM -0400, jamal wrote:
>
> Do you have plans to do the iproute bits? If you do it will be nice to
> also update the doc/examples with some simple example(s).

Oh yes, I didn't test this by poking bits in the kernel
you know :)

Here are the iproute bits.

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
diff --git a/include/utils.h b/include/utils.h
index a3fd335..b0dc03e 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -36,7 +36,7 @@ extern char * _SL_;
 
 extern void incomplete_command(void) __attribute__((noreturn));
 
-#define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while(0)
+#define NEXT_ARG() do { argv++; if (--argc < 0) incomplete_command(); } while(0)
 #define NEXT_ARG_OK() (argc - 1 > 0)
 #define PREV_ARG() do { argv--; argc++; } while(0)
 
diff --git a/tc/Makefile b/tc/Makefile
index 22cd437..cd5a69e 100644
--- a/tc/Makefile
+++ b/tc/Makefile
@@ -26,6 +26,7 @@ TCMODULES += q_htb.o
 TCMODULES += m_gact.o
 TCMODULES += m_mirred.o
 TCMODULES += m_ipt.o
+TCMODULES += m_nat.o
 TCMODULES += m_pedit.o
 TCMODULES += p_ip.o
 TCMODULES += p_icmp.o
diff --git a/tc/m_nat.c b/tc/m_nat.c
new file mode 100644
index 0000000..9a6c7da
--- /dev/null
+++ b/tc/m_nat.c
@@ -0,0 +1,208 @@
+/*
+ * m_nat.c		NAT module
+ *
+ *		This program is free software; you can distribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ * Authors:	Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <dlfcn.h>
+#include "utils.h"
+#include "tc_util.h"
+#include <linux/tc_act/tc_nat.h>
+
+static void
+explain(void)
+{
+	fprintf(stderr, "Usage: ... nat NAT\n"
+			"NAT := DIRECTION OLD NEW\n"
+			"DIRECTION := { ingress | egress }\n"
+			"OLD := PREFIX\n"
+			"NEW := ADDRESS\n");
+}
+
+static void
+usage(void)
+{
+	explain();
+	exit(-1);
+}
+
+static int
+parse_nat_args(int *argc_p, char ***argv_p,struct tc_nat *sel)
+{
+	int argc = *argc_p;
+	char **argv = *argv_p;
+	inet_prefix addr;
+
+	if (argc <= 0)
+		return -1;
+
+	if (matches(*argv, "egress") == 0)
+		sel->flags |= TCA_NAT_FLAG_EGRESS;
+	else if (matches(*argv, "ingress") != 0)
+		goto bad_val;
+
+	NEXT_ARG();
+
+	if (get_prefix_1(&addr, *argv, AF_INET))
+		goto bad_val;
+
+	sel->old_addr = addr.data[0];
+	sel->mask = htonl(~0u << (32 - addr.bitlen));
+
+	NEXT_ARG();
+
+	if (get_prefix_1(&addr, *argv, AF_INET))
+		goto bad_val;
+
+	sel->new_addr = addr.data[0];
+
+	NEXT_ARG();
+
+	*argc_p = argc;
+	*argv_p = argv;
+	return 0;
+
+bad_val:
+	return -1;
+}
+
+static int
+parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
+{
+	struct tc_nat sel;
+
+	int argc = *argc_p;
+	char **argv = *argv_p;
+	int ok = 0, iok = 0;
+	struct rtattr *tail;
+
+	memset(&sel, 0, sizeof(sel));
+
+	while (argc > 0) {
+		if (matches(*argv, "nat") == 0) {
+			NEXT_ARG();
+			if (parse_nat_args(&argc, &argv, &sel)) {
+				fprintf(stderr, "Illegal nat construct (%s) \n",
+					*argv);
+				explain();
+				return -1;
+			}
+			ok++;
+			continue;
+		} else if (matches(*argv, "help") == 0) {
+			usage();
+		} else {
+			break;
+		}
+
+	}
+
+	if (!ok) {
+		explain();
+		return -1;
+	}
+
+	if (argc) {
+		if (matches(*argv, "reclassify") == 0) {
+			sel.action = TC_ACT_RECLASSIFY;
+			NEXT_ARG();
+		} else if (matches(*argv, "pipe") == 0) {
+			sel.action = TC_ACT_PIPE;
+			NEXT_ARG();
+		} else if (matches(*argv, "drop") == 0 ||
+			matches(*argv, "shot") == 0) {
+			sel.action = TC_ACT_SHOT;
+			NEXT_ARG();
+		} else if (matches(*argv, "continue") == 0) {
+			sel.action = TC_ACT_UNSPEC;
+			NEXT_ARG();
+		} else if (matches(*argv, "pass") == 0) {
+			sel.action = TC_ACT_OK;
+			NEXT_ARG();
+		}
+	}
+
+	if (argc) {
+		if (matches(*argv, "index") == 0) {
+			NEXT_ARG();
+			if (get_u32(&sel.index, *argv, 10)) {
+				fprintf(stderr, "Pedit: Illegal \"index\"\n");
+				return -1;
+			}
+			argc--;
+			argv++;
+			iok++;
+		}
+	}
+
+	tail = NLMSG_TAIL(n);
+	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
+	addattr_l(n, MAX_MSG, TCA_NAT_PARMS, &sel, sizeof(sel));
+	tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
+
+	*argc_p = argc;
+	*argv_p = argv;
+	return 0;
+}
+
+static int
+print_nat(struct action_util *au,FILE * f, struct rtattr *arg)
+{
+	struct tc_nat *sel;
+	struct rtattr *tb[TCA_NAT_MAX + 1];
+	char buf1[256];
+	char buf2[256];
+	SPRINT_BUF(buf3);
+	int len;
+
+	if (arg == NULL)
+		return -1;
+
+	parse_rtattr_nested(tb, TCA_NAT_MAX, arg);
+
+	if (tb[TCA_NAT_PARMS] == NULL) {
+		fprintf(f, "[NULL nat parameters]");
+		return -1;
+	}
+	sel = RTA_DATA(tb[TCA_NAT_PARMS]);
+
+	len = ffs(sel->mask);
+	len = len ? 33 - len : 0;
+
+	fprintf(f, " nat %s %s/%d %s %s", sel->flags & TCA_NAT_FLAG_EGRESS ?
+					  "egress" : "ingress",
+		format_host(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)),
+		len,
+		format_host(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)),
+		action_n2a(sel->action, buf3, sizeof (buf3)));
+
+	if (show_stats) {
+		if (tb[TCA_NAT_TM]) {
+			struct tcf_t *tm = RTA_DATA(tb[TCA_NAT_TM]);
+			print_tm(f,tm);
+		}
+	}
+
+	return 0;
+}
+
+struct action_util nat_action_util = {
+	.id = "nat",
+	.parse_aopt = parse_nat,
+	.print_aopt = print_nat,
+};

^ permalink raw reply related

* Re: [PKT_SCHED]: Add stateless NAT
From: Evgeniy Polyakov @ 2007-09-27 13:06 UTC (permalink / raw)
  To: jamal; +Cc: Herbert Xu, David S. Miller, netdev, Alexey Kuznetsov
In-Reply-To: <1190897523.4290.29.camel@localhost>

On Thu, Sep 27, 2007 at 08:52:03AM -0400, jamal (hadi@cyberus.ca) wrote:
> On Thu, 2007-27-09 at 16:41 +0400, Evgeniy Polyakov wrote:
> 
> > I've attached simple patch which moves checksum helpers out of
> > CONFIG_NETFILTER option but still in the same linux/netfilter.h header.
> > This should be enough for removing 'select NETFILTER' in your patch.
> 
> Is there any point in keeping the code inside netfilter or keeping
> the nf_ prefix? something in net/utilities/ or net/core maybe?
> the nf_* can still exist in netfilter as aliases to wherever this is
> moved to.

No, there is no point in keeping that, I just wanted the smallest
possible change :)

-- 
	Evgeniy Polyakov

^ permalink raw reply

* Re: [PKT_SCHED]: Add stateless NAT
From: jamal @ 2007-09-27 12:52 UTC (permalink / raw)
  To: Evgeniy Polyakov; +Cc: Herbert Xu, David S. Miller, netdev, Alexey Kuznetsov
In-Reply-To: <20070927124120.GA8897@2ka.mipt.ru>

On Thu, 2007-27-09 at 16:41 +0400, Evgeniy Polyakov wrote:

> I've attached simple patch which moves checksum helpers out of
> CONFIG_NETFILTER option but still in the same linux/netfilter.h header.
> This should be enough for removing 'select NETFILTER' in your patch.

Is there any point in keeping the code inside netfilter or keeping
the nf_ prefix? something in net/utilities/ or net/core maybe?
the nf_* can still exist in netfilter as aliases to wherever this is
moved to.

cheers,
jamal




^ permalink raw reply

* Re: [PKT_SCHED]: Add stateless NAT
From: jamal @ 2007-09-27 12:46 UTC (permalink / raw)
  To: Evgeniy Polyakov; +Cc: Herbert Xu, David S. Miller, netdev, Alexey Kuznetsov
In-Reply-To: <20070927092512.GD29329@2ka.mipt.ru>

On Thu, 2007-27-09 at 13:25 +0400, Evgeniy Polyakov wrote:


> > +#define NAT_TAB_MASK	15
> 
> This really wants to be configurable at least via module parameter.

Would not be a bad idea, but not specific to just this one action.
Note: probably not a very big deal to have 15 there because in the fast
path that table is not being looked up; once an action is bound to a
filter, its the filter lookups that count.

> > +static struct tcf_common *tcf_nat_ht[NAT_TAB_MASK + 1];
> > +static u32 nat_idx_gen;
> > +static DEFINE_RWLOCK(nat_lock);
> 
> > +static struct tcf_hashinfo nat_hash_info = {
> > +	.htab	=	tcf_nat_ht,
> > +	.hmask	=	NAT_TAB_MASK,
> > +	.lock	=	&nat_lock,
> > +};
> 
> When I read this I swear I heard 'I want to be RCU'.
> But that is another task.

Go ahead and clean that up to use rcu. What would be really nice is to
have generic hash table scheme which uses the scheme above and then this
code (and a lot other) is converted to use it; if you stared a bit at
the code youd notice a lot of commonalities with a lot of similar
netcode (look at the ipip driver for example). The LinuxWay(tm).
I know Patrick hinted at some point he may do that (or maybe it was my
imagination;->)

cheers,
jamal


^ permalink raw reply

* Re: [PKT_SCHED]: Add stateless NAT
From: Herbert Xu @ 2007-09-27 12:45 UTC (permalink / raw)
  To: Evgeniy Polyakov; +Cc: David S. Miller, netdev, Alexey Kuznetsov, jamal
In-Reply-To: <20070927124120.GA8897@2ka.mipt.ru>

On Thu, Sep 27, 2007 at 04:41:21PM +0400, Evgeniy Polyakov wrote:
>
> I've attached simple patch which moves checksum helpers out of
> CONFIG_NETFILTER option but still in the same linux/netfilter.h header.
> This should be enough for removing 'select NETFILTER' in your patch.

Close but no cigar :)

> diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
> index 1dd075e..6c3fb10 100644
> --- a/include/linux/netfilter.h
> +++ b/include/linux/netfilter.h
> @@ -40,6 +40,29 @@
>  #endif
>  
>  #ifdef __KERNEL__
> +
> +static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
> +{
> +	__be32 diff[] = { ~from, to };
> +
> +	*sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum)));
> +}
> +
> +static inline void nf_csum_replace2(__sum16 *sum, __be16 from, __be16 to)
> +{
> +	nf_csum_replace4(sum, (__force __be32)from, (__force __be32)to);
> +}
> +
> +extern void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
> +				      __be32 from, __be32 to, int pseudohdr);

This function won't exist if NETFILTER is off.

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* Re: [PKT_SCHED]: Add stateless NAT
From: Evgeniy Polyakov @ 2007-09-27 12:41 UTC (permalink / raw)
  To: Herbert Xu; +Cc: David S. Miller, netdev, Alexey Kuznetsov, jamal
In-Reply-To: <20070927102916.GA15749@gondor.apana.org.au>

On Thu, Sep 27, 2007 at 06:29:16PM +0800, Herbert Xu (herbert@gondor.apana.org.au) wrote:
> On Thu, Sep 27, 2007 at 02:07:53PM +0400, Evgeniy Polyakov wrote:
> >
> > It forces all inpuit/pre/post/forward hooks to be enbled not as a direct
> > function call, but as additional lookups. And unability to remove
> > netfilter from config. And just because of couple of checksum helpers...
> 
> I'm certainly not against patches moving that code out of
> netfilter.

I've attached simple patch which moves checksum helpers out of
CONFIG_NETFILTER option but still in the same linux/netfilter.h header.
This should be enough for removing 'select NETFILTER' in your patch.

diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 1dd075e..6c3fb10 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -40,6 +40,29 @@
 #endif
 
 #ifdef __KERNEL__
+
+static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
+{
+	__be32 diff[] = { ~from, to };
+
+	*sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum)));
+}
+
+static inline void nf_csum_replace2(__sum16 *sum, __be16 from, __be16 to)
+{
+	nf_csum_replace4(sum, (__force __be32)from, (__force __be32)to);
+}
+
+extern void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
+				      __be32 from, __be32 to, int pseudohdr);
+
+static inline void nf_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
+				      __be16 from, __be16 to, int pseudohdr)
+{
+	nf_proto_csum_replace4(sum, skb, (__force __be32)from,
+				(__force __be32)to, pseudohdr);
+}
+
 #ifdef CONFIG_NETFILTER
 
 extern void netfilter_init(void);
@@ -289,28 +312,6 @@ extern void nf_invalidate_cache(int pf);
    Returns true or false. */
 extern int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len);
 
-static inline void nf_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
-{
-	__be32 diff[] = { ~from, to };
-
-	*sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum)));
-}
-
-static inline void nf_csum_replace2(__sum16 *sum, __be16 from, __be16 to)
-{
-	nf_csum_replace4(sum, (__force __be32)from, (__force __be32)to);
-}
-
-extern void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
-				      __be32 from, __be32 to, int pseudohdr);
-
-static inline void nf_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
-				      __be16 from, __be16 to, int pseudohdr)
-{
-	nf_proto_csum_replace4(sum, skb, (__force __be32)from,
-				(__force __be32)to, pseudohdr);
-}
-
 struct nf_afinfo {
 	unsigned short	family;
 	__sum16		(*checksum)(struct sk_buff *skb, unsigned int hook,



-- 
	Evgeniy Polyakov

^ permalink raw reply related

* Re: [PKT_SCHED]: Add stateless NAT
From: jamal @ 2007-09-27 12:39 UTC (permalink / raw)
  To: Herbert Xu; +Cc: David S. Miller, netdev, Alexey Kuznetsov
In-Reply-To: <20070927073446.GA14643@gondor.apana.org.au>

nice work. I like the egress flag idea;->
and who would have thunk stateless nat could be written in such a few
lines ;-> I would have put the checksum as a separate action but it is
fine the way you did it since it simplifies config.
more comments below.

On Thu, 2007-27-09 at 15:34 +0800, Herbert Xu wrote:

> +config NET_ACT_NAT
> +        tristate "Stateless NAT"
> +        depends on NET_CLS_ACT
> +        select NETFILTER

I am gonna have to agree with Evgeniy on this Herbert;->
The rewards are it will improve performance for people who dont need
netfilter.
Ok, who is gonna move the csum utility functions out? /me looks at
Evgeniy;->
I could do it realsoonnow if noone raises their hands. 
In any case, it would be real nice to have but i dont see it as a show
stopper for inclusion.
 
> +static int tcf_nat(struct sk_buff *skb, struct tc_action *a,
> +		   struct tcf_result *res)
> +{
> +	struct tcf_nat *p = a->priv;

> +	spin_lock(&p->tcf_lock);
> +
> +	p->tcf_tm.lastuse = jiffies;
> +	old_addr = p->old_addr;
> +	new_addr = p->new_addr;
> +	mask = p->mask;
> +	egress = p->flags & TCA_NAT_FLAG_EGRESS;
> +	action = p->tcf_action;
> +
> +	p->tcf_bstats.bytes += skb->len;
> +	p->tcf_bstats.packets++;
> +
> +	spin_unlock(&p->tcf_lock);

You also need to p->tcf_qstats.drops++ for all packets that get shot.
I would just hold tcf_lock until the end.
If you are concerned about performance of multiple flows contending for
the lock, then just create a new action entry per flow by using a
different index for each; you cant avoid contention with control path in
case of updates, but i suspect that would be a rare occasion.

Do you have plans to do the iproute bits? If you do it will be nice to
also update the doc/examples with some simple example(s).

cheers,
jamal


^ permalink raw reply

* Re: [PKT_SCHED]: Add stateless NAT
From: Herbert Xu @ 2007-09-27 12:27 UTC (permalink / raw)
  To: Evgeniy Polyakov; +Cc: David S. Miller, netdev, Alexey Kuznetsov, jamal
In-Reply-To: <20070927093358.GA15357@gondor.apana.org.au>

On Thu, Sep 27, 2007 at 05:33:58PM +0800, Herbert Xu wrote:
>
> > Modile will be called 'nat' I believe.
> 
> Good catch, now you know where I copied it from :)

Here's an updated version with this typo fixed.

[PKT_SCHED]: Add stateless NAT

Stateless NAT is useful in controlled environments where restrictions are
placed on through traffic such that we don't need connection tracking to
correctly NAT protocol-specific data.

In particular, this is of interest when the number of flows or the number
of addresses being NATed is large, or if connection tracking information
has to be replicated and where it is not practical to do so.

Previously we had stateless NAT functionality which was integrated into
the IPv4 routing subsystem.  This was a great solution as long as the NAT
worked on a subnet to subnet basis such that the number of NAT rules was
relatively small.  The reason is that for SNAT the routing based system
had to perform a linear scan through the rules.

If the number of rules is large then major renovations would have take
place in the routing subsystem to make this practical.

For the time being, the least intrusive way of achieving this is to use
the u32 classifier written by Alexey Kuznetsov along with the actions
infrastructure implemented by Jamal Hadi Salim.

The following patch is an attempt at this problem by creating a new nat
action that can be invoked from u32 hash tables which would allow large
number of stateless NAT rules that can be used/updated in constant time.

The actual NAT code is mostly based on the previous stateless NAT code
written by Alexey.  In future we might be able to utilise the protocol
NAT code from netfilter to improve support for other protocols.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
diff --git a/include/linux/tc_act/tc_nat.h b/include/linux/tc_act/tc_nat.h
new file mode 100644
index 0000000..9280c6f
--- /dev/null
+++ b/include/linux/tc_act/tc_nat.h
@@ -0,0 +1,29 @@
+#ifndef __LINUX_TC_NAT_H
+#define __LINUX_TC_NAT_H
+
+#include <linux/pkt_cls.h>
+#include <linux/types.h>
+
+#define TCA_ACT_NAT 9
+
+enum
+{
+	TCA_NAT_UNSPEC,
+	TCA_NAT_PARMS,
+	TCA_NAT_TM,
+	__TCA_NAT_MAX
+};
+#define TCA_NAT_MAX (__TCA_NAT_MAX - 1)
+
+#define TCA_NAT_FLAG_EGRESS 1
+                                                                               
+struct tc_nat
+{
+	tc_gen;
+	__be32 old_addr;
+	__be32 new_addr;
+	__be32 mask;
+	__u32 flags;
+};
+
+#endif
diff --git a/include/net/tc_act/tc_nat.h b/include/net/tc_act/tc_nat.h
new file mode 100644
index 0000000..4a691f3
--- /dev/null
+++ b/include/net/tc_act/tc_nat.h
@@ -0,0 +1,21 @@
+#ifndef __NET_TC_NAT_H
+#define __NET_TC_NAT_H
+
+#include <linux/types.h>
+#include <net/act_api.h>
+
+struct tcf_nat {
+	struct tcf_common common;
+
+	__be32 old_addr;
+	__be32 new_addr;
+	__be32 mask;
+	u32 flags;
+};
+
+static inline struct tcf_nat *to_tcf_nat(struct tcf_common *pc)
+{
+	return container_of(pc, struct tcf_nat, common);
+}
+
+#endif /* __NET_TC_NAT_H */
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 8a74cac..22b34f2 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -447,6 +447,17 @@ config NET_ACT_IPT
 	  To compile this code as a module, choose M here: the
 	  module will be called ipt.
 
+config NET_ACT_NAT
+        tristate "Stateless NAT"
+        depends on NET_CLS_ACT
+        select NETFILTER
+        ---help---
+	  Say Y here to do stateless NAT on IPv4 packets.  You should use
+	  netfilter for NAT unless you know what you are doing.
+
+	  To compile this code as a module, choose M here: the
+	  module will be called nat.
+
 config NET_ACT_PEDIT
         tristate "Packet Editing"
         depends on NET_CLS_ACT
diff --git a/net/sched/Makefile b/net/sched/Makefile
index b67c36f..81ecbe8 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_NET_ACT_POLICE)	+= act_police.o
 obj-$(CONFIG_NET_ACT_GACT)	+= act_gact.o
 obj-$(CONFIG_NET_ACT_MIRRED)	+= act_mirred.o
 obj-$(CONFIG_NET_ACT_IPT)	+= act_ipt.o
+obj-$(CONFIG_NET_ACT_NAT)	+= act_nat.o
 obj-$(CONFIG_NET_ACT_PEDIT)	+= act_pedit.o
 obj-$(CONFIG_NET_ACT_SIMP)	+= act_simple.o
 obj-$(CONFIG_NET_SCH_FIFO)	+= sch_fifo.o
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
new file mode 100644
index 0000000..efd6d7d
--- /dev/null
+++ b/net/sched/act_nat.c
@@ -0,0 +1,313 @@
+/*
+ * Stateless NAT actions
+ *
+ * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/rtnetlink.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/tc_act/tc_nat.h>
+#include <net/act_api.h>
+#include <net/icmp.h>
+#include <net/ip.h>
+#include <net/netlink.h>
+#include <net/tc_act/tc_nat.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+
+
+#define NAT_TAB_MASK	15
+static struct tcf_common *tcf_nat_ht[NAT_TAB_MASK + 1];
+static u32 nat_idx_gen;
+static DEFINE_RWLOCK(nat_lock);
+
+static struct tcf_hashinfo nat_hash_info = {
+	.htab	=	tcf_nat_ht,
+	.hmask	=	NAT_TAB_MASK,
+	.lock	=	&nat_lock,
+};
+
+static int tcf_nat_init(struct rtattr *rta, struct rtattr *est,
+			struct tc_action *a, int ovr, int bind)
+{
+	struct rtattr *tb[TCA_NAT_MAX];
+	struct tc_nat *parm;
+	int ret = 0;
+	struct tcf_nat *p;
+	struct tcf_common *pc;
+
+	if (rta == NULL || rtattr_parse_nested(tb, TCA_NAT_MAX, rta) < 0)
+		return -EINVAL;
+
+	if (tb[TCA_NAT_PARMS - 1] == NULL ||
+	    RTA_PAYLOAD(tb[TCA_NAT_PARMS - 1]) < sizeof(*parm))
+		return -EINVAL;
+	parm = RTA_DATA(tb[TCA_NAT_PARMS - 1]);
+
+	pc = tcf_hash_check(parm->index, a, bind, &nat_hash_info);
+	if (!pc) {
+		pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind,
+				     &nat_idx_gen, &nat_hash_info);
+		if (unlikely(!pc))
+			return -ENOMEM;
+		p = to_tcf_nat(pc);
+		ret = ACT_P_CREATED;
+	} else {
+		p = to_tcf_nat(pc);
+		if (!ovr) {
+			tcf_hash_release(pc, bind, &nat_hash_info);
+			return -EEXIST;
+		}
+	}
+
+	spin_lock_bh(&p->tcf_lock);
+	p->old_addr = parm->old_addr;
+	p->new_addr = parm->new_addr;
+	p->mask = parm->mask;
+	p->flags = parm->flags;
+
+	p->tcf_action = parm->action;
+	spin_unlock_bh(&p->tcf_lock);
+
+	if (ret == ACT_P_CREATED)
+		tcf_hash_insert(pc, &nat_hash_info);
+
+	return ret;
+}
+
+static int tcf_nat_cleanup(struct tc_action *a, int bind)
+{
+	struct tcf_nat *p = a->priv;
+
+	return tcf_hash_release(&p->common, bind, &nat_hash_info);
+}
+
+static int tcf_nat(struct sk_buff *skb, struct tc_action *a,
+		   struct tcf_result *res)
+{
+	struct tcf_nat *p = a->priv;
+	struct iphdr *iph;
+	__be32 old_addr;
+	__be32 new_addr;
+	__be32 mask;
+	__be32 addr;
+	int egress;
+	int action;
+	int ihl;
+
+	spin_lock(&p->tcf_lock);
+
+	p->tcf_tm.lastuse = jiffies;
+	old_addr = p->old_addr;
+	new_addr = p->new_addr;
+	mask = p->mask;
+	egress = p->flags & TCA_NAT_FLAG_EGRESS;
+	action = p->tcf_action;
+
+	p->tcf_bstats.bytes += skb->len;
+	p->tcf_bstats.packets++;
+
+	spin_unlock(&p->tcf_lock);
+
+	if (!pskb_may_pull(skb, sizeof(*iph)))
+		return TC_ACT_SHOT;
+
+	iph = ip_hdr(skb);
+
+	if (egress)
+		addr = iph->saddr;
+	else
+		addr = iph->daddr;
+
+	if (!((old_addr ^ addr) & mask)) {
+		if (skb_cloned(skb) &&
+		    !skb_clone_writable(skb, sizeof(*iph)) &&
+		    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+			return TC_ACT_SHOT;
+
+		new_addr &= mask;
+		new_addr |= addr & ~mask;
+
+		/* Rewrite IP header */
+		iph = ip_hdr(skb);
+		if (egress)
+			iph->saddr = new_addr;
+		else
+			iph->daddr = new_addr;
+
+		nf_csum_replace4(&iph->check, addr, new_addr);
+	}
+
+	ihl = iph->ihl * 4;
+
+	/* It would be nice to share code with stateful NAT. */
+	switch (iph->frag_off & htons(IP_OFFSET) ? 0 : iph->protocol) {
+	case IPPROTO_TCP:
+	{
+		struct tcphdr *tcph;
+
+		if (!pskb_may_pull(skb, ihl + sizeof(*tcph)) ||
+		    (skb_cloned(skb) &&
+		     !skb_clone_writable(skb, ihl + sizeof(*tcph)) &&
+		     pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+			return TC_ACT_SHOT;
+
+		tcph = (void *)(skb_network_header(skb) + ihl);
+		nf_proto_csum_replace4(&tcph->check, skb, addr, new_addr, 1);
+		break;
+	}
+	case IPPROTO_UDP:
+	{
+		struct udphdr *udph;
+
+		if (!pskb_may_pull(skb, ihl + sizeof(*udph)) ||
+		    (skb_cloned(skb) &&
+		     !skb_clone_writable(skb, ihl + sizeof(*udph)) &&
+		     pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
+			return TC_ACT_SHOT;
+
+		udph = (void *)(skb_network_header(skb) + ihl);
+		if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) {
+			nf_proto_csum_replace4(&udph->check, skb, addr,
+					       new_addr, 1);
+			if (!udph->check)
+				udph->check = CSUM_MANGLED_0;
+		}
+		break;
+	}
+	case IPPROTO_ICMP:
+	{
+		struct icmphdr *icmph;
+
+		if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph)))
+			return TC_ACT_SHOT;
+
+		icmph = (void *)(skb_network_header(skb) + ihl);
+
+		if ((icmph->type != ICMP_DEST_UNREACH) &&
+		    (icmph->type != ICMP_TIME_EXCEEDED) &&
+		    (icmph->type != ICMP_PARAMETERPROB))
+			break;
+
+		iph = (void *)(icmph + 1);
+		if (egress)
+			addr = iph->daddr;
+		else
+			addr = iph->saddr;
+
+		if ((old_addr ^ addr) & mask)
+			break;
+
+		if (skb_cloned(skb) &&
+		    !skb_clone_writable(skb,
+		    			ihl + sizeof(*icmph) + sizeof(*iph)) &&
+		    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+			return TC_ACT_SHOT;
+
+		icmph = (void *)(skb_network_header(skb) + ihl);
+		iph = (void *)(icmph + 1);
+
+		new_addr &= mask;
+		new_addr |= addr & ~mask;
+
+		/* XXX Fix up the inner checksums. */
+		if (egress)
+			iph->daddr = new_addr;
+		else
+			iph->saddr = new_addr;
+
+		nf_proto_csum_replace4(&icmph->checksum, skb, addr, new_addr,
+				       1);
+		break;
+	}
+	default:
+		break;
+	}
+
+	return action;
+}
+
+static int tcf_nat_dump(struct sk_buff *skb, struct tc_action *a,
+			int bind, int ref)
+{
+	unsigned char *b = skb_tail_pointer(skb);
+	struct tcf_nat *p = a->priv;
+	struct tc_nat *opt;
+	struct tcf_t t;
+	int s;
+
+	s = sizeof(*opt);
+
+	/* netlink spinlocks held above us - must use ATOMIC */
+	opt = kzalloc(s, GFP_ATOMIC);
+	if (unlikely(!opt))
+		return -ENOBUFS;
+
+	opt->old_addr = p->old_addr;
+	opt->new_addr = p->new_addr;
+	opt->mask = p->mask;
+	opt->flags = p->flags;
+
+	opt->index = p->tcf_index;
+	opt->action = p->tcf_action;
+	opt->refcnt = p->tcf_refcnt - ref;
+	opt->bindcnt = p->tcf_bindcnt - bind;
+
+	RTA_PUT(skb, TCA_NAT_PARMS, s, opt);
+	t.install = jiffies_to_clock_t(jiffies - p->tcf_tm.install);
+	t.lastuse = jiffies_to_clock_t(jiffies - p->tcf_tm.lastuse);
+	t.expires = jiffies_to_clock_t(p->tcf_tm.expires);
+	RTA_PUT(skb, TCA_NAT_TM, sizeof(t), &t);
+
+	kfree(opt);
+
+	return skb->len;
+
+rtattr_failure:
+	nlmsg_trim(skb, b);
+	kfree(opt);
+	return -1;
+}
+
+static struct tc_action_ops act_nat_ops = {
+	.kind		=	"nat",
+	.hinfo		=	&nat_hash_info,
+	.type		=	TCA_ACT_NAT,
+	.capab		=	TCA_CAP_NONE,
+	.owner		=	THIS_MODULE,
+	.act		=	tcf_nat,
+	.dump		=	tcf_nat_dump,
+	.cleanup	=	tcf_nat_cleanup,
+	.lookup		=	tcf_hash_search,
+	.init		=	tcf_nat_init,
+	.walk		=	tcf_generic_walker
+};
+
+MODULE_DESCRIPTION("Stateless NAT actions");
+MODULE_LICENSE("GPL");
+
+static int __init nat_init_module(void)
+{
+	return tcf_register_action(&act_nat_ops);
+}
+
+static void __exit nat_cleanup_module(void)
+{
+	tcf_unregister_action(&act_nat_ops);
+}
+
+module_init(nat_init_module);
+module_exit(nat_cleanup_module);

^ permalink raw reply related

* [PATCH] proper comment for loopback initialization order
From: Denis V. Lunev @ 2007-09-27 12:25 UTC (permalink / raw)
  To: davem; +Cc: dev, devel, netdev, containers

Loopback device is special. It should be initialized at the very
beginning.  Initialization order has been changed by
Eric W. Biederman <ebiederm@xmission.com> and this change is non-obvious
and important enough to add proper comment.

Signed-off-by: Denis V. Lunev <den@openvz.org>

--- ./drivers/net/loopback.c.loopcomment	2007-08-26 19:30:38.000000000 +0400
+++ ./drivers/net/loopback.c	2007-09-27 16:08:06.000000000 +0400
@@ -293,4 +293,6 @@ static int __init loopback_init(void)
 	return register_pernet_device(&loopback_net_ops);
 }
 
+/* Loopback is special. It should be initialized before any other network
+   device and network subsystem */
 fs_initcall(loopback_init);

^ permalink raw reply

* Re: [Devel] [PATCH 4/4] net: Make the loopback device per network namespace
From: Denis V. Lunev @ 2007-09-27 12:14 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: David Miller, Linux Containers, netdev
In-Reply-To: <m17imdrn8r.fsf_-_@ebiederm.dsl.xmission.com>

Eric W. Biederman wrote:
> This patch makes loopback_dev per network namespace.  Adding
> code to create a different loopback device for each network
> namespace and adding the code to free a loopback device
> when a network namespace exits.
> 
> This patch modifies all users the loopback_dev so they
> access it as init_net.loopback_dev, keeping all of the
> code compiling and working.  A later pass will be needed to
> update the users to use something other than the initial network
> namespace.

A pity that an important bit of explanation is missed. The
initialization of loopback_dev is moved from a chain of devices
(init_module) to a subsystem initialization to keep proper order, i.e.
we must be sure that the initialization order is correct.

Regards,
	Den

^ permalink raw reply

* Re: 2.6.23-rc8-mm2 - drivers/net/ibm_newemac/mal - broken
From: Kamalesh Babulal @ 2007-09-27 10:52 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, netdev, eugene.surovegin
In-Reply-To: <20070927022220.c76a7a6e.akpm@linux-foundation.org>

Andrew Morton wrote:
> ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.23-rc8/2.6.23-rc8-mm2/

Hi Andrew,

The drivers/net/ibm_newemac/mal seems to be broken with 2.6.23-rc8-mm2 also, it was
reported on 2.6.23-rc8-mm1 (http://lkml.org/lkml/2007/9/25/173).


-- 
Thanks & Regards,
Kamalesh Babulal,
Linux Technology Center,
IBM, ISTL.

^ permalink raw reply

* ax88796: add 93cx6 eeprom support
From: Magnus Damm @ 2007-09-27 10:51 UTC (permalink / raw)
  To: netdev; +Cc: Magnus Damm, lethal, jgarzik, akpm, ben-linux

ax88796: add 93cx6 eeprom support

This patch hooks up the 93cx6 eeprom code to the ax88796 driver and modifies
the ax88796 driver to read out the mac address from the eeprom. We need
this for the ax88796 on certain SuperH boards. The pin configuration used
to connect the eeprom to the ax88796 on these boards is the same as pointed
out by the ax88796 datasheet, so we can probably reuse this code for multiple
platforms in the future.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
---

 This is a broken out version of the larger patch recently posted to netdev:
 http://www.mail-archive.com/netdev@vger.kernel.org/msg47278.html

 drivers/net/Kconfig          |    7 ++++++
 drivers/net/ax88796.c        |   49 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/eeprom_93cx6.h |    3 +-
 include/net/ax88796.h        |    1 
 4 files changed, 59 insertions(+), 1 deletion(-)

--- 0001/drivers/net/Kconfig
+++ work/drivers/net/Kconfig	2007-09-27 19:32:10.000000000 +0900
@@ -225,6 +225,13 @@ config AX88796
 	  AX88796 driver, using platform bus to provide
 	  chip detection and resources
 
+config AX88796_93CX6
+	bool "ASIX AX88796 external 93CX6 eeprom support"
+	depends on AX88796
+	select EEPROM_93CX6
+	help
+	  Select this if your platform comes with an external 93CX6 eeprom.
+
 config MACE
 	tristate "MACE (Power Mac ethernet) support"
 	depends on PPC_PMAC && PPC32
--- 0001/drivers/net/ax88796.c
+++ work/drivers/net/ax88796.c	2007-09-27 19:17:44.000000000 +0900
@@ -24,6 +24,7 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/eeprom_93cx6.h>
 
 #include <net/ax88796.h>
 
@@ -582,6 +583,37 @@ static const struct ethtool_ops ax_ethto
 	.get_link		= ax_get_link,
 };
 
+#ifdef CONFIG_AX88796_93CX6
+static void ax_eeprom_register_read(struct eeprom_93cx6 *eeprom)
+{
+	struct ei_device *ei_local = eeprom->data;
+	u8 reg = ei_inb(ei_local->mem + AX_MEMR);
+
+	eeprom->reg_data_in = reg & AX_MEMR_EEI;
+	eeprom->reg_data_out = reg & AX_MEMR_EEO; /* Input pin */
+	eeprom->reg_data_clock = reg & AX_MEMR_EECLK;
+	eeprom->reg_chip_select = reg & AX_MEMR_EECS;
+}
+
+static void ax_eeprom_register_write(struct eeprom_93cx6 *eeprom)
+{
+	struct ei_device *ei_local = eeprom->data;
+	u8 reg = ei_inb(ei_local->mem + AX_MEMR);
+
+	reg &= ~(AX_MEMR_EEI | AX_MEMR_EECLK | AX_MEMR_EECS);
+
+	if (eeprom->reg_data_in)
+		reg |= AX_MEMR_EEI;
+	if (eeprom->reg_data_clock)
+		reg |= AX_MEMR_EECLK;
+	if (eeprom->reg_chip_select)
+		reg |= AX_MEMR_EECS;
+
+	ei_outb(reg, ei_local->mem + AX_MEMR);
+	udelay(10);
+}
+#endif
+
 /* setup code */
 
 static void ax_initial_setup(struct net_device *dev, struct ei_device *ei_local)
@@ -640,6 +672,23 @@ static int ax_init_dev(struct net_device
 		memcpy(dev->dev_addr,  SA_prom, 6);
 	}
 
+#ifdef CONFIG_AX88796_93CX6
+	if (first_init && ax->plat->flags & AXFLG_HAS_93CX6) {
+		unsigned char mac_addr[6];
+		struct eeprom_93cx6 eeprom;
+
+		eeprom.data = ei_local;
+		eeprom.register_read = ax_eeprom_register_read;
+		eeprom.register_write = ax_eeprom_register_write;
+		eeprom.width = PCI_EEPROM_WIDTH_93C56;
+
+		eeprom_93cx6_multiread(&eeprom, 0,
+				       (__le16 __force *)mac_addr,
+				       sizeof(mac_addr) >> 1);
+
+		memcpy(dev->dev_addr,  mac_addr, 6);
+	}
+#endif
 	if (ax->plat->wordlength == 2) {
 		/* We must set the 8390 for word mode. */
 		ei_outb(ax->plat->dcr_val, ei_local->mem + EN0_DCFG);
--- 0001/include/linux/eeprom_93cx6.h
+++ work/include/linux/eeprom_93cx6.h	2007-09-27 19:17:44.000000000 +0900
@@ -21,13 +21,14 @@
 /*
 	Module: eeprom_93cx6
 	Abstract: EEPROM reader datastructures for 93cx6 chipsets.
-	Supported chipsets: 93c46 & 93c66.
+	Supported chipsets: 93c46, 93c56 and 93c66.
  */
 
 /*
  * EEPROM operation defines.
  */
 #define PCI_EEPROM_WIDTH_93C46	6
+#define PCI_EEPROM_WIDTH_93C56	8
 #define PCI_EEPROM_WIDTH_93C66	8
 #define PCI_EEPROM_WIDTH_OPCODE	3
 #define PCI_EEPROM_WRITE_OPCODE	0x05
--- 0001/include/net/ax88796.h
+++ work/include/net/ax88796.h	2007-09-27 19:17:44.000000000 +0900
@@ -14,6 +14,7 @@
 
 #define AXFLG_HAS_EEPROM		(1<<0)
 #define AXFLG_MAC_FROMDEV		(1<<1)	/* device already has MAC */
+#define AXFLG_HAS_93CX6			(1<<2)	/* use eeprom_93cx6 driver */
 
 struct ax_plat_data {
 	unsigned int	 flags;

^ permalink raw reply

* Re: Linux networking implementation and packet capture
From: Alan Menegotto @ 2007-09-27 10:48 UTC (permalink / raw)
  To: Gaurav Aggarwal; +Cc: kernelnewbies, linux-net, netdev
In-Reply-To: <1a41e0840709262347m1fc5d99dge9aeb172b7fc610e@mail.gmail.com>

Gaurav Aggarwal escreveu:
> Hi,
>
> I am trying to understand the implementation of linux 2.4 and linux 
> 2.6's networking (IPV4) . Can anyone give me some idea/pointers about 
> some of the good resources/whitepapers available in the market to 
> understand the same. If there is any document that mention the changes 
> between the implementation of networking in 2.4 & 2.6
>
> I am also trying to write a simple program(preferably a userspace 
> application) which captures all the incoming and outgoing packets of a 
> particular machine (preferably at PREROUTING stage), then according to 
> the SRC/DST addresses, changes the IP address of some of the packets 
> and then reinject it back into the local IP stack. I am able to do 
> that in 2.4 kernel by using libipq and ip_tables but that prog is not 
> running in 2.6 kernel. (It hits at ip_route_BUG). Any idea or code 
> snippet will be really appreciated.
>
> -- 
> Regards,
> Gaurav Aggarwal
>
You may also see the information on the linux-net wiki: 
http://linux-net.osdl.org/index.php/Main_Page.

Also, read some threads on netdev list. It has a lot of information 
there too.





-- 


--
Best Regards

Alan Menegotto


^ permalink raw reply

* [PATCH] fixed broken bootp compilation
From: Denis V. Lunev @ 2007-09-27 10:46 UTC (permalink / raw)
  To: davem; +Cc: shemminger, netdev

Compilation fix. Extra bracket removed.
Broken by "[NET]: Wrap netdevice hardware header creation" from
Stephen Hemminger <shemminger@linux-foundation.org>

Signed-off-by: Denis V. Lunev <den@openvz.org>

--- ./net/ipv4/ipconfig.c.compile	2007-09-27 13:32:35.000000000 +0400
+++ ./net/ipv4/ipconfig.c	2007-09-27 14:36:19.000000000 +0400
@@ -758,7 +758,7 @@ static void __init ic_bootp_send_if(stru
 	skb->dev = dev;
 	skb->protocol = htons(ETH_P_IP);
 	if (dev_hard_header(skb, dev, ntohs(skb->protocol),
-			    dev->broadcast, dev->dev_addr, skb->len) < 0) ||
+			    dev->broadcast, dev->dev_addr, skb->len) < 0 ||
 	    dev_queue_xmit(skb) < 0)
 		printk("E");
 }

^ permalink raw reply

* Re: [PATCH 3/4] net ipv4: When possible test for IFF_LOOPBACK and not dev == loopback_dev
From: Daniel Lezcano @ 2007-09-27 10:34 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: David Miller, Linux Containers, netdev, urs
In-Reply-To: <m1bqbprnc2.fsf_-_@ebiederm.dsl.xmission.com>

Eric W. Biederman wrote:
> Now that multiple loopback devices are becoming possible it makes
> the code a little cleaner and more maintainable to test if a deivice
> is th a loopback device by testing dev->flags & IFF_LOOPBACK instead
> of dev == loopback_dev.
> 
> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>


Urs Thuermann posted the patch:

	[PATCH 5/7] CAN: Add virtual CAN netdevice driver

This network driver set its flag to IFF_LOOPBACK for testing.
Is it possible this can be a collision with your patch ?


^ permalink raw reply

* Re: [PKT_SCHED]: Add stateless NAT
From: Herbert Xu @ 2007-09-27 10:29 UTC (permalink / raw)
  To: Evgeniy Polyakov; +Cc: David S. Miller, netdev, Alexey Kuznetsov, jamal
In-Reply-To: <20070927100753.GA22323@2ka.mipt.ru>

On Thu, Sep 27, 2007 at 02:07:53PM +0400, Evgeniy Polyakov wrote:
>
> It forces all inpuit/pre/post/forward hooks to be enbled not as a direct
> function call, but as additional lookups. And unability to remove
> netfilter from config. And just because of couple of checksum helpers...

I'm certainly not against patches moving that code out of
netfilter.

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

^ permalink raw reply

* Re: [PKT_SCHED]: Add stateless NAT
From: Evgeniy Polyakov @ 2007-09-27 10:07 UTC (permalink / raw)
  To: Herbert Xu; +Cc: David S. Miller, netdev, Alexey Kuznetsov, jamal
In-Reply-To: <20070927093358.GA15357@gondor.apana.org.au>

On Thu, Sep 27, 2007 at 05:33:58PM +0800, Herbert Xu (herbert@gondor.apana.org.au) wrote:
> > > +config NET_ACT_NAT
> > > +        tristate "Stateless NAT"
> > > +        depends on NET_CLS_ACT
> > > +        select NETFILTER
> > 
> > Argh... People usually do not understand such jokes :)
> > What about not using netfilter helpers and just move them to the
> > accessible header so that no additional slow path would ever be enabled?
> 
> Sure.  However, as it is it's just including the netfilter core
> which does not mean the inclusion of connection trakcing.  It's
> only connection tracking that *may* (so don't flame me for this :)
> pose a scalability problem.

It forces all inpuit/pre/post/forward hooks to be enbled not as a direct
function call, but as additional lookups. And unability to remove
netfilter from config. And just because of couple of checksum helpers...

> > > +++ b/net/sched/act_nat.c
> > ...
> > > +#define NAT_TAB_MASK	15
> > 
> > This really wants to be configurable at least via module parameter.
> > 
> > > +static struct tcf_common *tcf_nat_ht[NAT_TAB_MASK + 1];
> > > +static u32 nat_idx_gen;
> > > +static DEFINE_RWLOCK(nat_lock);
> > 
> > > +static struct tcf_hashinfo nat_hash_info = {
> > > +	.htab	=	tcf_nat_ht,
> > > +	.hmask	=	NAT_TAB_MASK,
> > > +	.lock	=	&nat_lock,
> > > +};
> > 
> > When I read this I swear I heard 'I want to be RCU'.
> > But that is another task.
> 
> Yes there are a lot of clean-up's that can be done for all
> actions.  You're most welcome to send patches in this area.
> 
> > > +		tcph = (void *)(skb_network_header(skb) + ihl);
> > 
> > Were you too lazy to write struct tcphdr here and in other places? :)
> 
> Unfortunately it doesn't work.  For prerouting, we've not
> entered the IP stack yet so the transport header isn't set.

I meant instead of dereferencing to void * it should be struct tcphdr *.

-- 
	Evgeniy Polyakov

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox