Netdev List
 help / color / mirror / Atom feed
* [PATCH 2/2] NFS: handle IPv6 addresses in nfs ctl
From: Aurélien Charbon @ 2007-10-12  9:14 UTC (permalink / raw)
  To: Mailing list NFSv4, netdev ML

[-- Attachment #1: Type: text/plain, Size: 4206 bytes --]

Here is a second missing part of the IPv6 support in NFS server code 
concerning knfd syscall interface.
It updates write_getfd and write_getfd to accept IPv6 addresses.

Applies on a kernel including ip_map cache modifications

Tests: tested with only IPv4 network and basic nfs ops (mount, file creation and modification) 


Signed-off-by: Aurelien Charbon <aurelien.charbon@ext.bull.net>
---

 nfsctl.c |   41 ++++++++++++++++++++++++++++++-----------
 1 file changed, 30 insertions(+), 11 deletions(-)

diff -p -u -r -N linux-2.6.23-ipmap-cache/fs/nfsd/nfsctl.c 
linux-2.6.23-nfsctl/fs/nfsd/nfsctl.c
--- linux-2.6.23-ipmap-cache/fs/nfsd/nfsctl.c    2007-10-11 
15:23:07.000000000 +0200
+++ linux-2.6.23-nfsctl/fs/nfsd/nfsctl.c    2007-10-12 
10:49:31.000000000 +0200
@@ -219,7 +219,7 @@ static ssize_t write_unexport(struct fil
 static ssize_t write_getfs(struct file *file, char *buf, size_t size)
 {
     struct nfsctl_fsparm *data;
-    struct sockaddr_in *sin;
+    struct sockaddr_in6 *sin, sin6_storage;
     struct auth_domain *clp;
     int err = 0;
     struct knfsd_fh *res;
@@ -228,9 +228,20 @@ static ssize_t write_getfs(struct file *
         return -EINVAL;
     data = (struct nfsctl_fsparm*)buf;
     err = -EPROTONOSUPPORT;
-    if (data->gd_addr.sa_family != AF_INET)
+    sin = &sin6_storage;
+    switch (data->gd_addr.sa_family) {
+    case AF_INET6:
+        sin = (struct sockaddr_in6 *)&data->gd_addr;
+        in6 = sin->sin6_addr;
+        break;
+    case AF_INET:
+        /* Map v4 address into v6 structure */
+        ipv6_addr_v4map(((struct sockaddr_in 
*)&data->gd_addr)->sin_addr, in6);
+        break;
+    default:
         goto out;
-    sin = (struct sockaddr_in *)&data->gd_addr;
+    }
+
     if (data->gd_maxlen > NFS3_FHSIZE)
         data->gd_maxlen = NFS3_FHSIZE;
 
@@ -238,9 +249,6 @@ static ssize_t write_getfs(struct file *
 
     exp_readlock();
 
-    /* IPv6 address mapping */
-    ipv6_addr_v4map(sin->sin_addr, in6);
-
     if (!(clp = auth_unix_lookup(in6)))
         err = -EPERM;
     else {
@@ -257,7 +265,7 @@ static ssize_t write_getfs(struct file *
 static ssize_t write_getfd(struct file *file, char *buf, size_t size)
 {
     struct nfsctl_fdparm *data;
-    struct sockaddr_in *sin;
+    struct sockaddr_in6 *sin, sin6_storage;
     struct in6_addr in6;
     struct auth_domain *clp;
     int err = 0;
@@ -268,18 +276,29 @@ static ssize_t write_getfd(struct file *
         return -EINVAL;
     data = (struct nfsctl_fdparm*)buf;
     err = -EPROTONOSUPPORT;
-    if (data->gd_addr.sa_family != AF_INET)
+    if (data->gd_addr.sa_family != AF_INET &&
+        data->gd_addr.sa_family != AF_INET6)
         goto out;
     err = -EINVAL;
     if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
         goto out;
 
     res = buf;
-    sin = (struct sockaddr_in *)&data->gd_addr;
+    sin = &sin6_storage;
     exp_readlock();
 
-    /* IPv6 address mapping */
-    ipv6_addr_v4map(sin->sin_addr, in6);
+    switch (data->gd_addr.sa_family) {
+    case AF_INET:
+        /* IPv6 address mapping */
+        ipv6_addr_v4map(((struct sockaddr_in 
*)&data->gd_addr)->sin_addr, in6);
+        break;
+    case AF_INET6:
+        sin = (struct sockaddr_in6 *)&data->gd_addr;
+        in6 = sin->sin6_addr;
+        break;
+    default:
+        BUG();
+    }
 
     if (!(clp = auth_unix_lookup(in6)))
         err = -EPERM;
diff -p -u -r -N linux-2.6.23-ipmap-cache/net/sunrpc/svcauth_unix.c 
linux-2.6.23-nfsctl/net/sunrpc/svcauth_unix.c
--- linux-2.6.23-ipmap-cache/net/sunrpc/svcauth_unix.c    2007-10-12 
10:47:27.000000000 +0200
+++ linux-2.6.23-nfsctl/net/sunrpc/svcauth_unix.c    2007-10-12 
10:03:56.000000000 +0200
@@ -677,7 +677,7 @@ svcauth_unix_set_client(struct svc_rqst
     case AF_INET:
         sin = svc_addr_in(rqstp);
         sin6 = &sin6_storage;
-        ipv6_addr_set(&sin6->sin6_addr, 0, 0,
+        ipv6_addr_set(&sin6->sin6_addr, 0, 0,
                 htonl(0x0000FFFF), sin->sin_addr.s_addr);
         break;
     case AF_INET6:

-- 

********************************
       Aurelien Charbon
           Bull SAS
     Echirolles - France
 http://www.bullopensource.org/
********************************


[-- Attachment #2: linux-2.6.23-nfsctl.diff --]
[-- Type: text/x-patch, Size: 2612 bytes --]

diff -p -u -r -N linux-2.6.23-ipmap-cache/fs/nfsd/nfsctl.c linux-2.6.23-nfsctl/fs/nfsd/nfsctl.c
--- linux-2.6.23-ipmap-cache/fs/nfsd/nfsctl.c	2007-10-11 15:23:07.000000000 +0200
+++ linux-2.6.23-nfsctl/fs/nfsd/nfsctl.c	2007-10-12 10:49:31.000000000 +0200
@@ -219,7 +219,7 @@ static ssize_t write_unexport(struct fil
 static ssize_t write_getfs(struct file *file, char *buf, size_t size)
 {
 	struct nfsctl_fsparm *data;
-	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin, sin6_storage;
 	struct auth_domain *clp;
 	int err = 0;
 	struct knfsd_fh *res;
@@ -228,9 +228,20 @@ static ssize_t write_getfs(struct file *
 		return -EINVAL;
 	data = (struct nfsctl_fsparm*)buf;
 	err = -EPROTONOSUPPORT;
-	if (data->gd_addr.sa_family != AF_INET)
+	sin = &sin6_storage;
+	switch (data->gd_addr.sa_family) {
+	case AF_INET6:
+		sin = (struct sockaddr_in6 *)&data->gd_addr;
+		in6 = sin->sin6_addr;
+		break;
+	case AF_INET:
+		/* Map v4 address into v6 structure */
+		ipv6_addr_v4map(((struct sockaddr_in *)&data->gd_addr)->sin_addr, in6);
+		break;
+	default:
 		goto out;
-	sin = (struct sockaddr_in *)&data->gd_addr;
+	}
+
 	if (data->gd_maxlen > NFS3_FHSIZE)
 		data->gd_maxlen = NFS3_FHSIZE;
 
@@ -238,9 +249,6 @@ static ssize_t write_getfs(struct file *
 
 	exp_readlock();
 
-	/* IPv6 address mapping */
-	ipv6_addr_v4map(sin->sin_addr, in6);
-
 	if (!(clp = auth_unix_lookup(in6)))
 		err = -EPERM;
 	else {
@@ -257,7 +265,7 @@ static ssize_t write_getfs(struct file *
 static ssize_t write_getfd(struct file *file, char *buf, size_t size)
 {
 	struct nfsctl_fdparm *data;
-	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin, sin6_storage;
 	struct in6_addr in6;
 	struct auth_domain *clp;
 	int err = 0;
@@ -268,18 +276,29 @@ static ssize_t write_getfd(struct file *
 		return -EINVAL;
 	data = (struct nfsctl_fdparm*)buf;
 	err = -EPROTONOSUPPORT;
-	if (data->gd_addr.sa_family != AF_INET)
+	if (data->gd_addr.sa_family != AF_INET && 
+		data->gd_addr.sa_family != AF_INET6)
 		goto out;
 	err = -EINVAL;
 	if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS)
 		goto out;
 
 	res = buf;
-	sin = (struct sockaddr_in *)&data->gd_addr;
+	sin = &sin6_storage;
 	exp_readlock();
 
-	/* IPv6 address mapping */
-	ipv6_addr_v4map(sin->sin_addr, in6);
+	switch (data->gd_addr.sa_family) {
+	case AF_INET:
+		/* IPv6 address mapping */
+		ipv6_addr_v4map(((struct sockaddr_in *)&data->gd_addr)->sin_addr, in6);
+		break;
+	case AF_INET6:
+		sin = (struct sockaddr_in6 *)&data->gd_addr;
+		in6 = sin->sin6_addr;
+		break;
+	default:
+		BUG();
+	}
 
 	if (!(clp = auth_unix_lookup(in6)))
 		err = -EPERM;


^ permalink raw reply

* Re: authenc compile warnings in current net-2.6.24
From: Herbert Xu @ 2007-10-12 10:18 UTC (permalink / raw)
  To: Oliver Hartkopp; +Cc: David Miller, netdev
In-Reply-To: <470F10E5.7090606@hartkopp.net>

On Fri, Oct 12, 2007 at 08:15:01AM +0200, Oliver Hartkopp wrote:
> Hi Dave,
> 
> this compile fix seems not to be applied (maybe my compiler is the only 
> one who complains ;-)

That's because the patch is in my cryptodev-2.6 tree :)

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

^ permalink raw reply

* Re: Regression in net-2.6.24?
From: TAKANO Ryousei @ 2007-10-12 10:22 UTC (permalink / raw)
  To: davem; +Cc: shemminger, netdev, ilpo.jarvinen, mchan
In-Reply-To: <20071011.181449.130846976.davem@davemloft.net>

From: David Miller <davem@davemloft.net>
Subject: Re: Regression in net-2.6.24?
Date: Thu, 11 Oct 2007 18:14:49 -0700 (PDT)

> 
> Here is what I'm checking into net-2.6 for now:
> 
> commit 6f535763165331bb91277d7519b507fed22034e5
> Author: David S. Miller <davem@sunset.davemloft.net>
> Date:   Thu Oct 11 18:08:29 2007 -0700
> 
>     [NET]: Fix NAPI completion handling in some drivers.
>     
>     In order for the list handling in net_rx_action() to be
>     correct, drivers must follow certain rules as stated by
>     this comment in net_rx_action():
>     
>     		/* Drivers must not modify the NAPI state if they
>     		 * consume the entire weight.  In such cases this code
>     		 * still "owns" the NAPI instance and therefore can
>     		 * move the instance around on the list at-will.
>     		 */
>     
>     A few drivers do not do this because they mix the budget checks
>     with reading hardware state, resulting in crashes like the one
>     reported by takano@axe-inc.co.jp.
>     
>     BNX2 and TG3 are taken care of here, SKY2 fix is from Stephen
>     Hemminger.
>     
>     Signed-off-by: David S. Miller <davem@davemloft.net>
> 
I am sorry for late reply.
I confirmed this patch fixes the kernel panic that I reported.
Thanks David and others.

Ryousei Takano

^ permalink raw reply

* Re: Regression in net-2.6.24?
From: David Miller @ 2007-10-12 10:56 UTC (permalink / raw)
  To: takano; +Cc: shemminger, netdev, ilpo.jarvinen, mchan
In-Reply-To: <20071012.192200.23848971.takano@axe-inc.co.jp>

From: TAKANO Ryousei <takano@axe-inc.co.jp>
Date: Fri, 12 Oct 2007 19:22:00 +0900 (JST)

> I am sorry for late reply.
> I confirmed this patch fixes the kernel panic that I reported.
> Thanks David and others.

Thank you for testing.

^ permalink raw reply

* Re: [RFD] iptables:  mangle table obsoletes filter table
From: Patrick McHardy @ 2007-10-12 11:48 UTC (permalink / raw)
  To: Al Boldi; +Cc: netfilter-devel, netdev
In-Reply-To: <200710120837.18152.a1426z@gawab.com>

Al Boldi wrote:
> Patrick McHardy wrote:
> 
>>Please send mails discussing netfilter to netfilter-devel.
> 
> 
> Ok.  I just found out this changed to vger.  But 
> netfilter-devel@vger.kernel.org is bouncing me.

Seems to work, I got your mail on netfilter-devel.

>>Al Boldi wrote:
>>
>>>With the existence of the mangle table, how useful is the filter table?
>>>
>>>Other than requiring the REJECT target to be ported to the mangle table,
>>>is the filter table faster than the mangle table?
>>
>>There are some minor differences in ordering (mangle comes before
>>DNAT, filter afterwards), but for most rulesets thats completely
>>irrelevant. The only difference that really matters is that mangle
>>performs rerouting in LOCAL_OUT for packets that had their routing
>>key changed, so its really a superset of the filter table. If you
>>want to use REJECT in the mangle table, you just need to remove the
>>restriction to filter, it works fine. I would prefer to also remove
>>the restriction of MARK, CONNMARK etc. to mangle, they're used for
>>more than just routing today so that restriction also doesn't make
>>much sense. Patches for this are welcome.
> 
> 
> Something like this (untested):
> 
> --- ipt_REJECT.bak.c    2007-10-12 08:25:17.000000000 +0300
> +++ ipt_REJECT.c        2007-10-12 08:31:44.000000000 +0300
> @@ -165,6 +165,7 @@ static void send_reset(struct sk_buff *o
>  
>  static inline void send_unreach(struct sk_buff *skb_in, int code)
>  {
> +       if (!skb_in->dst) ip_route_me_harder(&skb_in, RTN_UNSPEC);
>         icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);
>  }
>  
> @@ -245,9 +246,6 @@ static struct xt_target ipt_reject_reg =
>         .family         = AF_INET,
>         .target         = reject,
>         .targetsize     = sizeof(struct ipt_reject_info),
> -       .table          = "filter",
> -       .hooks          = (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) |
> -                         (1 << NF_IP_LOCAL_OUT),
>         .checkentry     = check,
>         .me             = THIS_MODULE,
>  };


That includes an unrelated change, I meant to simply remove the filter
table restriction.

>>>If not, then shouldn't the filter table be obsoleted to avoid confusion?
>>
>>That would probably confuse people. Just don't use it if you don't
>>need to.
> 
> 
> The problem is that people think they are safe with the filter table, when in 
> fact they need the prerouting chain to seal things.  Right now this is only 
> possible in the mangle table.


Why do they need PREROUTING?

^ permalink raw reply

* [PATCH] Switch helpers tc_core_{time2ktime,ktime2time} from long to unsigned as well.
From: Andreas Henriksson @ 2007-10-12 11:49 UTC (permalink / raw)
  To: shemminger; +Cc: netdev, Andreas Henriksson

Follow up patch to "Fix overflow in time2tick / tick2time." which switches
the remaining two helper functions from long to unsigned as well.
These functions are only used in "tc/q_hfsc.c" where both the passed argument
and the place the return value is stored are unsigned/u32 variables, so this
change should be safe to make but hasn't been tested as extensively as the
time2tick patch.

Signed-off-by: Andreas Henriksson <andreas@fatal.se>
---
 tc/tc_core.c |    4 ++--
 tc/tc_core.h |    4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/tc/tc_core.c b/tc/tc_core.c
index fb89876..8c3a2ac 100644
--- a/tc/tc_core.c
+++ b/tc/tc_core.c
@@ -45,12 +45,12 @@ unsigned tc_core_tick2time(unsigned tick)
 	return tick/tick_in_usec;
 }
 
-long tc_core_time2ktime(long time)
+unsigned tc_core_time2ktime(unsigned time)
 {
 	return time * clock_factor;
 }
 
-long tc_core_ktime2time(long ktime)
+unsigned tc_core_ktime2time(unsigned ktime)
 {
 	return ktime / clock_factor;
 }
diff --git a/tc/tc_core.h b/tc/tc_core.h
index b2a16bc..b1ede1e 100644
--- a/tc/tc_core.h
+++ b/tc/tc_core.h
@@ -9,8 +9,8 @@
 int  tc_core_time2big(long time);
 unsigned tc_core_time2tick(unsigned time);
 unsigned tc_core_tick2time(unsigned tick);
-long tc_core_time2ktime(long time);
-long tc_core_ktime2time(long ktime);
+unsigned tc_core_time2ktime(unsigned time);
+unsigned tc_core_ktime2time(unsigned ktime);
 unsigned tc_calc_xmittime(unsigned rate, unsigned size);
 unsigned tc_calc_xmitsize(unsigned rate, unsigned ticks);
 int tc_calc_rtable(unsigned bps, __u32 *rtab, int cell_log, unsigned mtu, unsigned mpu);
-- 
1.5.3.4


^ permalink raw reply related

* [PATCH] Also do tc_core_time2big argument (long->unsigned).
From: Andreas Henriksson @ 2007-10-12 11:56 UTC (permalink / raw)
  To: shemminger; +Cc: netdev, Andreas Henriksson
In-Reply-To: <1192189789-23538-1-git-send-email-andreas@fatal.se>

tc_core_time2big only used in tc/q_netem.c where it gets passed an unsigned.

Signed-off-by: Andreas Henriksson <andreas@fatal.se>
---
 tc/tc_core.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/tc/tc_core.c b/tc/tc_core.c
index 8c3a2ac..1365e08 100644
--- a/tc/tc_core.c
+++ b/tc/tc_core.c
@@ -26,7 +26,7 @@
 static double tick_in_usec = 1;
 static double clock_factor = 1;
 
-int tc_core_time2big(long time)
+int tc_core_time2big(unsigned time)
 {
 	__u64 t = time;
 
-- 
1.5.3.4


^ permalink raw reply related

* Re: [RFC/PATCH 4/4] UDP memory usage accounting (take 4): memory limitation
From: Satoshi OSHIMA @ 2007-10-12 11:58 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Andi Kleen, David Miller, Evgeniy Polyakov, Herbert Xu, netdev,
	?? ??, Yumiko SUGITA, ??@RedHat
In-Reply-To: <20071011124656.01dd575b@freepuppy.rosehill>

Hi Stephen,

> On Thu, 11 Oct 2007 21:51:14 +0900
> Satoshi OSHIMA <satoshi.oshima.fk@hitachi.com> wrote:
> 
>> Hi Stephen,
>>
>> Thank you for your comment.
>>
>>>>  	{
>>>> +		.ctl_name	= NET_UDP_MEM,
>>>> +		.procname	= "udp_mem",
>>>> +		.data		= &sysctl_udp_mem,
>>>> +		.maxlen		= sizeof(sysctl_udp_mem),
>>>> +		.mode		= 0644,
>>>> +		.proc_handler	= &proc_dointvec
>>>> +	},
>>>> +	{
>>>>  		.ctl_name	= NET_TCP_APP_WIN,
>>>>  		.procname	= "tcp_app_win",
>>>>  		.data		= &sysctl_tcp_app_win,
>>> if you use &proc_dointvec_minmax, then you could inforce min/max
>>> values for udp_mem for the sysctl
> 
> One other comment. Sysctl value indexes are deprecated at this point
> so all new values should use CTL_UNNUMBERED.  Therefore unless NET_UDP_MEM
> already exists, please don't add it.

Thank you for letting me know. I will fix it.

Satoshi Oshima


^ permalink raw reply

* [PATCH 0/4]UDP memory accounting and limitation(take 5)
From: Satoshi OSHIMA @ 2007-10-12 12:00 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: Hideo AOKI, Yumiko SUGITA, "青木@RedHat",
	Andi Kleen, Evgeniy Polyakov, Herbert Xu, Stephen Hemminger,
	吉藤 英明

Hi,

I revised a patch set of UDP memory accounting and
limitation.

This patch set is for kernel 2.6.23. The differences
from take 4 are

* removing unnessesary EXPORT_SYMBOLs
* adding minimal limit of /proc/sys/net/udp_mem
* bugfix of UDP limit affecting protocol other
  than UDP
* introducing __ip_check_max_skb_pages()
* using CTL_UNNUMBERED
* adding udp_mem usage to Documentation/networking/ip_sysctl.txt

How to use UDP memory limitation:

This patch set add

/proc/sys/net/ipv4/udp_mem

as a tuning parameter. 

When you give the number that is greater than 4096,
UDP memory limitation will work. The number of pages
for socket buffer is limited up to udp_mem[pages].

Currently this function drops the packet when
it is sent or received and the number of pages for
socket buffer is beyond the limit. It won't collect
the buffer that is already allocated.

On the other hand, udp_mem is specified as 4096,
UDP memory limitaion will not work.
The deafult number of udp_mem is 4096. 

Comment, review and test are welcome.

Thanks,

Satoshi Oshima

^ permalink raw reply

* Re: [PATCH 03/12] Prevent renaming interfaces to empty string.
From: Patrick McHardy @ 2007-10-12 12:01 UTC (permalink / raw)
  To: Andreas Henriksson; +Cc: shemminger, netdev, Alexander Wirt
In-Reply-To: <1192179407-22461-3-git-send-email-andreas@fatal.se>

[-- Attachment #1: Type: text/plain, Size: 785 bytes --]

Andreas Henriksson wrote:
> From: Alexander Wirt <formorer@debian.org>
> 
> 
> Signed-off-by: Andreas Henriksson <andreas@fatal.se>
> ---
>  ip/iplink.c |    4 ++++
>  1 files changed, 4 insertions(+), 0 deletions(-)
> 
> diff --git a/ip/iplink.c b/ip/iplink.c
> index 4060845..da1f64e 100644
> --- a/ip/iplink.c
> +++ b/ip/iplink.c
> @@ -670,6 +670,10 @@ static int do_set(int argc, char **argv)
>  	}
>  
>  	if (newname && strcmp(dev, newname)) {
> +		if (strlen(newname) == 0) {
> +		    printf("\"\" is not valid device identifier\n");
> +		    return -1;
> +		}


Indentation fixed, same change for the non-ioctl case, use invarg.
While I'm at it I also fixed the error message for "name too long",
*argv is NULL at this point.

Signed-off-by: Patrick McHardy <kaber@trash.net>


[-- Attachment #2: x --]
[-- Type: text/plain, Size: 770 bytes --]

diff --git a/ip/iplink.c b/ip/iplink.c
index 4060845..8e0ed2a 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -336,8 +336,10 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
 
 	if (name) {
 		len = strlen(name) + 1;
+		if (len == 1)
+			invarg("\"\" is not a valid device identifier\n", "name");
 		if (len > IFNAMSIZ)
-			invarg("\"name\" too long\n", *argv);
+			invarg("\"name\" too long\n", name);
 		addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
 	}
 
@@ -670,6 +672,8 @@ static int do_set(int argc, char **argv)
 	}
 
 	if (newname && strcmp(dev, newname)) {
+		if (strlen(newname) == 0)
+			invarg("\"\" is not a valid device identifier\n", "name");
 		if (do_changename(dev, newname) < 0)
 			return -1;
 		dev = newname;

^ permalink raw reply related

* [PATCH 1/4] UDP memory accounting and limitation(take 5): fix send buffer check
From: Satoshi OSHIMA @ 2007-10-12 12:01 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: Hideo AOKI, Yumiko SUGITA, "??@RedHat", Andi Kleen,
	Evgeniy Polyakov, Herbert Xu, Stephen Hemminger, ?? ??
In-Reply-To: <470F61D4.6040808@hitachi.com>

This patch introduces sndbuf size check before
memory allcation for send buffer.


signed-off-by: Satoshi Oshima <satoshi.oshima.fk@hitachi.com>
signed-off-by: Hideo Aoki <haoki@redhat.com>

Index: 2.6.23-rc7-udp_limit/net/ipv4/ip_output.c
===================================================================
--- 2.6.23-rc7-udp_limit.orig/net/ipv4/ip_output.c
+++ 2.6.23-rc7-udp_limit/net/ipv4/ip_output.c
@@ -1004,6 +1004,11 @@ alloc_new_skb:
 					frag = &skb_shinfo(skb)->frags[i];
 				}
 			} else if (i < MAX_SKB_FRAGS) {
+				if (atomic_read(&sk->sk_wmem_alloc) + PAGE_SIZE
+				    > 2 * sk->sk_sndbuf) {
+					err = -ENOBUFS;
+					goto error;
+				}
 				if (copy > PAGE_SIZE)
 					copy = PAGE_SIZE;
 				page = alloc_pages(sk->sk_allocation, 0);


^ permalink raw reply

* Re: [PATCH] Also do tc_core_time2big argument (long->unsigned).
From: Patrick McHardy @ 2007-10-12 12:02 UTC (permalink / raw)
  To: Andreas Henriksson; +Cc: shemminger, netdev
In-Reply-To: <1192190193-23653-1-git-send-email-andreas@fatal.se>

Andreas Henriksson wrote:
> tc_core_time2big only used in tc/q_netem.c where it gets passed an unsigned.
> 
> Signed-off-by: Andreas Henriksson <andreas@fatal.se>
> ---
>  tc/tc_core.c |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)


Seems to be missing a tc_core.h update.

^ permalink raw reply

* [PATCH 2/4] UDP memory accounting and limitation(take 5): accounting unit and variable
From: Satoshi OSHIMA @ 2007-10-12 12:07 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: Hideo AOKI, Yumiko SUGITA, "青木@RedHat",
	Andi Kleen, Evgeniy Polyakov, Herbert Xu, Stephen Hemminger,
	吉藤 英明
In-Reply-To: <470F61D4.6040808@hitachi.com>

This patch introduces global variable for UDP memory accounting.
The unit is page.


signed-off-by: Satoshi Oshima <satoshi.oshima.fk@hitachi.com>
signed-off-by: Hideo Aoki <haoki@redhat.com>

Index: 2.6.23-udp_limit/include/net/sock.h
===================================================================
--- 2.6.23-udp_limit.orig/include/net/sock.h
+++ 2.6.23-udp_limit/include/net/sock.h
@@ -723,6 +723,13 @@ static inline int sk_stream_wmem_schedul
 	       sk_stream_mem_schedule(sk, size, 0);
 }
 
+#define SK_DATAGRAM_MEM_QUANTUM ((int)PAGE_SIZE)
+
+static inline int sk_datagram_pages(int amt)
+{
+	return DIV_ROUND_UP(amt, SK_DATAGRAM_MEM_QUANTUM);
+}
+
 /* Used by processes to "lock" a socket state, so that
  * interrupts and bottom half handlers won't change it
  * from under us. It essentially blocks any incoming
Index: 2.6.23-udp_limit/include/net/udp.h
===================================================================
--- 2.6.23-udp_limit.orig/include/net/udp.h
+++ 2.6.23-udp_limit/include/net/udp.h
@@ -65,6 +65,8 @@ extern rwlock_t udp_hash_lock;
 
 extern struct proto udp_prot;
 
+extern atomic_t udp_memory_allocated;
+
 struct sk_buff;
 
 /*
Index: 2.6.23-udp_limit/net/ipv4/proc.c
===================================================================
--- 2.6.23-udp_limit.orig/net/ipv4/proc.c
+++ 2.6.23-udp_limit/net/ipv4/proc.c
@@ -66,7 +66,8 @@ static int sockstat_seq_show(struct seq_
 		   fold_prot_inuse(&tcp_prot), atomic_read(&tcp_orphan_count),
 		   tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated),
 		   atomic_read(&tcp_memory_allocated));
-	seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot));
+	seq_printf(seq, "UDP: inuse %d mem %d\n", fold_prot_inuse(&udp_prot),
+		   atomic_read(&udp_memory_allocated));
 	seq_printf(seq, "UDPLITE: inuse %d\n", fold_prot_inuse(&udplite_prot));
 	seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot));
 	seq_printf(seq,  "FRAG: inuse %d memory %d\n", ip_frag_nqueues,
Index: 2.6.23-udp_limit/net/ipv4/udp.c
===================================================================
--- 2.6.23-udp_limit.orig/net/ipv4/udp.c
+++ 2.6.23-udp_limit/net/ipv4/udp.c
@@ -113,6 +113,8 @@ DEFINE_SNMP_STAT(struct udp_mib, udp_sta
 struct hlist_head udp_hash[UDP_HTABLE_SIZE];
 DEFINE_RWLOCK(udp_hash_lock);
 
+atomic_t udp_memory_allocated;
+
 static int udp_port_rover;
 
 static inline int __udp_lib_lport_inuse(__u16 num, struct hlist_head udptable[])


^ permalink raw reply

* [PATCH 3/4] UDP memory accounting and limitation(take 5): memory accounting
From: Satoshi OSHIMA @ 2007-10-12 12:10 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: Hideo AOKI, Yumiko SUGITA, "青木@RedHat",
	Andi Kleen, Evgeniy Polyakov, Herbert Xu, Stephen Hemminger,
	吉藤 英明
In-Reply-To: <470F61D4.6040808@hitachi.com>

This patch introduces memory usage accounting for UDP.


signed-off-by: Satoshi Oshima <satoshi.oshima.fk@hitachi.com>
signed-off-by: Hideo Aoki <haoki@redhat.com>

Index: 2.6.23-udp_limit/net/ipv4/ip_output.c
===================================================================
--- 2.6.23-udp_limit.orig/net/ipv4/ip_output.c
+++ 2.6.23-udp_limit/net/ipv4/ip_output.c
@@ -743,6 +743,8 @@ static inline int ip_ufo_append_data(str
 		/* specify the length of each IP datagram fragment*/
 		skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
 		skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
+		atomic_add(sk_datagram_pages(skb->truesize),
+			   sk->sk_prot->memory_allocated);
 		__skb_queue_tail(&sk->sk_write_queue, skb);
 
 		return 0;
@@ -924,6 +926,9 @@ alloc_new_skb:
 			}
 			if (skb == NULL)
 				goto error;
+			if (sk->sk_prot->memory_allocated)
+				atomic_add(sk_datagram_pages(skb->truesize),
+					   sk->sk_prot->memory_allocated);
 
 			/*
 			 *	Fill in the control structures
@@ -1023,6 +1028,8 @@ alloc_new_skb:
 				frag = &skb_shinfo(skb)->frags[i];
 				skb->truesize += PAGE_SIZE;
 				atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc);
+				if (sk->sk_prot->memory_allocated)
+					atomic_inc(sk->sk_prot->memory_allocated);
 			} else {
 				err = -EMSGSIZE;
 				goto error;
@@ -1123,7 +1130,9 @@ ssize_t	ip_append_page(struct sock *sk, 
 			if (unlikely(!skb)) {
 				err = -ENOBUFS;
 				goto error;
-			}
+			} else if (sk->sk_prot->memory_allocated)
+				atomic_add(sk_datagram_pages(skb->truesize),
+					   sk->sk_prot->memory_allocated);
 
 			/*
 			 *	Fill in the control structures
@@ -1202,13 +1211,14 @@ int ip_push_pending_frames(struct sock *
 	struct iphdr *iph;
 	__be16 df = 0;
 	__u8 ttl;
-	int err = 0;
+	int err = 0, send_page_size;
 
 	if ((skb = __skb_dequeue(&sk->sk_write_queue)) == NULL)
 		goto out;
 	tail_skb = &(skb_shinfo(skb)->frag_list);
 
 	/* move skb->data to ip header from ext header */
+	send_page_size = sk_datagram_pages(skb->truesize);
 	if (skb->data < skb_network_header(skb))
 		__skb_pull(skb, skb_network_offset(skb));
 	while ((tmp_skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) {
@@ -1218,6 +1228,7 @@ int ip_push_pending_frames(struct sock *
 		skb->len += tmp_skb->len;
 		skb->data_len += tmp_skb->len;
 		skb->truesize += tmp_skb->truesize;
+		send_page_size += sk_datagram_pages(tmp_skb->truesize);
 		__sock_put(tmp_skb->sk);
 		tmp_skb->destructor = NULL;
 		tmp_skb->sk = NULL;
@@ -1269,6 +1280,8 @@ int ip_push_pending_frames(struct sock *
 	/* Netfilter gets whole the not fragmented skb. */
 	err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
 		      skb->dst->dev, dst_output);
+	if (sk->sk_prot->memory_allocated)
+		atomic_sub(send_page_size, sk->sk_prot->memory_allocated);
 	if (err) {
 		if (err > 0)
 			err = inet->recverr ? net_xmit_errno(err) : 0;
@@ -1298,9 +1311,15 @@ void ip_flush_pending_frames(struct sock
 {
 	struct inet_sock *inet = inet_sk(sk);
 	struct sk_buff *skb;
+	int num_flush_mem = 0;
 
-	while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL)
+	while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) {
+		num_flush_mem += sk_datagram_pages(skb->truesize);
 		kfree_skb(skb);
+	}
+
+	if (sk->sk_prot->memory_allocated)
+		atomic_sub(num_flush_mem, sk->sk_prot->memory_allocated);
 
 	inet->cork.flags &= ~IPCORK_OPT;
 	kfree(inet->cork.opt);
Index: 2.6.23-udp_limit/net/ipv4/udp.c
===================================================================
--- 2.6.23-udp_limit.orig/net/ipv4/udp.c
+++ 2.6.23-udp_limit/net/ipv4/udp.c
@@ -885,6 +885,9 @@ try_again:
 		err = ulen;
 
 out_free:
+	atomic_sub(sk_datagram_pages(skb->truesize),
+		   sk->sk_prot->memory_allocated);
+
 	skb_free_datagram(sk, skb);
 out:
 	return err;
@@ -892,6 +895,9 @@ out:
 csum_copy_err:
 	UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite);
 
+	atomic_sub(sk_datagram_pages(skb->truesize),
+		   sk->sk_prot->memory_allocated);
+
 	skb_kill_datagram(sk, skb, flags);
 
 	if (noblock)
@@ -1017,6 +1023,9 @@ int udp_queue_rcv_skb(struct sock * sk, 
 		goto drop;
 	}
 
+	atomic_add(sk_datagram_pages(skb->truesize),
+		   sk->sk_prot->memory_allocated);
+
 	UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag);
 	return 0;
 
@@ -1441,6 +1450,7 @@ struct proto udp_prot = {
 	.hash		   = udp_lib_hash,
 	.unhash		   = udp_lib_unhash,
 	.get_port	   = udp_v4_get_port,
+	.memory_allocated  = &udp_memory_allocated,
 	.obj_size	   = sizeof(struct udp_sock),
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_udp_setsockopt,
Index: 2.6.23-udp_limit/net/ipv4/af_inet.c
===================================================================
--- 2.6.23-udp_limit.orig/net/ipv4/af_inet.c
+++ 2.6.23-udp_limit/net/ipv4/af_inet.c
@@ -126,13 +126,41 @@ extern void ip_mc_drop_socket(struct soc
 static struct list_head inetsw[SOCK_MAX];
 static DEFINE_SPINLOCK(inetsw_lock);
 
+/**
+ *	__skb_queue_purge_and_sub_memory_allocated
+ *		- empty a list and subtruct memory allocation counter
+ *	@sk:   sk
+ *	@list: list to empty
+ *	Delete all buffers on an &sk_buff list and subtruct the
+ *	turesize of the sk_buff for memory accounting. Each buffer
+ *	is removed from the list and one reference dropped. This
+ *	function does not take the list lock and the caller must
+ *	hold the relevant locks to use it.
+ */
+void __skb_queue_purge_and_sub_memory_allocated(struct sock *sk,
+					struct sk_buff_head *list)
+{
+	struct sk_buff *skb;
+	int purged_skb_size = 0;
+	while ((skb = __skb_dequeue(list)) != NULL) {
+		purged_skb_size += sk_datagram_pages(skb->truesize);
+		kfree_skb(skb);
+	}
+	atomic_sub(purged_skb_size, sk->sk_prot->memory_allocated);
+}
+
 /* New destruction routine */
 
 void inet_sock_destruct(struct sock *sk)
 {
 	struct inet_sock *inet = inet_sk(sk);
 
-	__skb_queue_purge(&sk->sk_receive_queue);
+	if (sk->sk_prot->memory_allocated && sk->sk_type != SOCK_STREAM)
+		__skb_queue_purge_and_sub_memory_allocated(sk,
+				&sk->sk_receive_queue);
+	else
+		__skb_queue_purge(&sk->sk_receive_queue);
+
 	__skb_queue_purge(&sk->sk_error_queue);
 
 	if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) {


^ permalink raw reply

* [PATCH 4/4] UDP memory accounting and limitation(take 5): memory limitation
From: Satoshi OSHIMA @ 2007-10-12 12:11 UTC (permalink / raw)
  To: David Miller, netdev
  Cc: Hideo AOKI, Yumiko SUGITA, "青木@RedHat",
	Andi Kleen, Evgeniy Polyakov, Herbert Xu, Stephen Hemminger,
	吉藤 英明
In-Reply-To: <470F61D4.6040808@hitachi.com>

This patch introduces memory limitation for UDP.


signed-off-by: Satoshi Oshima <satoshi.oshima.fk@hitachi.com>
signed-off-by: Hideo Aoki <haoki@redhat.com>

Index: 2.6.23-udp_limit/include/net/udp.h
===================================================================
--- 2.6.23-udp_limit.orig/include/net/udp.h
+++ 2.6.23-udp_limit/include/net/udp.h
@@ -65,7 +65,10 @@ extern rwlock_t udp_hash_lock;
 
 extern struct proto udp_prot;
 
+/* Used by memory accounting and capping */
+#define UDP_MIN_SKB_PAGES	4096
 extern atomic_t udp_memory_allocated;
+extern int sysctl_udp_mem;
 
 struct sk_buff;
 
Index: 2.6.23-udp_limit/net/ipv4/udp.c
===================================================================
--- 2.6.23-udp_limit.orig/net/ipv4/udp.c
+++ 2.6.23-udp_limit/net/ipv4/udp.c
@@ -114,6 +114,7 @@ struct hlist_head udp_hash[UDP_HTABLE_SI
 DEFINE_RWLOCK(udp_hash_lock);
 
 atomic_t udp_memory_allocated;
+int sysctl_udp_mem = UDP_MIN_SKB_PAGES;
 
 static int udp_port_rover;
 
@@ -1016,6 +1017,16 @@ int udp_queue_rcv_skb(struct sock * sk, 
 			goto drop;
 	}
 
+	if (sk->sk_prot->sysctl_mem[0] > UDP_MIN_SKB_PAGES) {
+		if ((atomic_read(sk->sk_prot->memory_allocated)
+			       + sk_datagram_pages(skb->truesize))
+			>= sk->sk_prot->sysctl_mem[0]) {
+			UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS,
+				up->pcflag);
+			goto drop;
+		}
+	}
+
 	if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) {
 		/* Note that an ENOMEM error is charged twice */
 		if (rc == -ENOMEM)
@@ -1451,6 +1462,7 @@ struct proto udp_prot = {
 	.unhash		   = udp_lib_unhash,
 	.get_port	   = udp_v4_get_port,
 	.memory_allocated  = &udp_memory_allocated,
+	.sysctl_mem	   = &sysctl_udp_mem,
 	.obj_size	   = sizeof(struct udp_sock),
 #ifdef CONFIG_COMPAT
 	.compat_setsockopt = compat_udp_setsockopt,
Index: 2.6.23-udp_limit/net/ipv4/sysctl_net_ipv4.c
===================================================================
--- 2.6.23-udp_limit.orig/net/ipv4/sysctl_net_ipv4.c
+++ 2.6.23-udp_limit/net/ipv4/sysctl_net_ipv4.c
@@ -17,6 +17,7 @@
 #include <net/ip.h>
 #include <net/route.h>
 #include <net/tcp.h>
+#include <net/udp.h>
 #include <net/cipso_ipv4.h>
 
 /* From af_inet.c */
@@ -25,6 +26,7 @@ extern int sysctl_ip_nonlocal_bind;
 #ifdef CONFIG_SYSCTL
 static int zero;
 static int tcp_retr1_max = 255;
+static int udp_mem_min = UDP_MIN_SKB_PAGES;
 static int ip_local_port_range_min[] = { 1, 1 };
 static int ip_local_port_range_max[] = { 65535, 65535 };
 #endif
@@ -599,6 +601,16 @@ ctl_table ipv4_table[] = {
 		.proc_handler	= &proc_dointvec
 	},
 	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "udp_mem",
+		.data		= &sysctl_udp_mem,
+		.maxlen		= sizeof(sysctl_udp_mem),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_minmax,
+		.strategy	= &sysctl_intvec,
+		.extra1		= &udp_mem_min
+	},
+	{
 		.ctl_name	= NET_TCP_APP_WIN,
 		.procname	= "tcp_app_win",
 		.data		= &sysctl_tcp_app_win,
Index: 2.6.23-udp_limit/net/ipv4/ip_output.c
===================================================================
--- 2.6.23-udp_limit.orig/net/ipv4/ip_output.c
+++ 2.6.23-udp_limit/net/ipv4/ip_output.c
@@ -75,6 +75,7 @@
 #include <net/icmp.h>
 #include <net/checksum.h>
 #include <net/inetpeer.h>
+#include <net/udp.h>
 #include <linux/igmp.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter_bridge.h>
@@ -699,6 +700,21 @@ csum_page(struct page *page, int offset,
 	return csum;
 }
 
+static inline int __ip_check_max_skb_pages(struct sock *sk, int size)
+{
+	switch(sk->sk_protocol) {
+	case IPPROTO_UDP:
+		if (sk->sk_prot->sysctl_mem[0] > UDP_MIN_SKB_PAGES)
+			if (atomic_read(sk->sk_prot->memory_allocated)+size
+			    >= sk->sk_prot->sysctl_mem[0])
+				return -ENOBUFS;
+		/* Fall through */	
+	default:
+		break;
+	}
+	return 0;
+}
+
 static inline int ip_ufo_append_data(struct sock *sk,
 			int getfrag(void *from, char *to, int offset, int len,
 			       int odd, struct sk_buff *skb),
@@ -910,6 +926,12 @@ alloc_new_skb:
 			if (datalen == length + fraggap)
 				alloclen += rt->u.dst.trailer_len;
 
+			err = __ip_check_max_skb_pages(sk,
+				sk_datagram_pages(SKB_DATA_ALIGN(alloclen + hh_len + 15)
+				+ sizeof(struct sk_buff)));
+			if (err)
+				goto error;
+
 			if (transhdrlen) {
 				skb = sock_alloc_send_skb(sk,
 						alloclen + hh_len + 15,
@@ -1009,6 +1031,11 @@ alloc_new_skb:
 					frag = &skb_shinfo(skb)->frags[i];
 				}
 			} else if (i < MAX_SKB_FRAGS) {
+				err = __ip_check_max_skb_pages(sk,
+					sk_datagram_pages(PAGE_SIZE));
+				if (err)
+					goto error;
+
 				if (atomic_read(&sk->sk_wmem_alloc) + PAGE_SIZE
 				    > 2 * sk->sk_sndbuf) {
 					err = -ENOBUFS;
@@ -1126,6 +1153,12 @@ ssize_t	ip_append_page(struct sock *sk, 
 			fraggap = skb_prev->len - maxfraglen;
 
 			alloclen = fragheaderlen + hh_len + fraggap + 15;
+
+			err = __ip_check_max_skb_pages(sk,
+				sk_datagram_pages(alloclen + sizeof(struct sk_buff)));
+			if (err)
+				goto error;
+
 			skb = sock_wmalloc(sk, alloclen, 1, sk->sk_allocation);
 			if (unlikely(!skb)) {
 				err = -ENOBUFS;
Index: 2.6.23-udp_limit/Documentation/networking/ip-sysctl.txt
===================================================================
--- 2.6.23-udp_limit.orig/Documentation/networking/ip-sysctl.txt
+++ 2.6.23-udp_limit/Documentation/networking/ip-sysctl.txt
@@ -439,6 +439,14 @@ tcp_dma_copybreak - INTEGER
 	and CONFIG_NET_DMA is enabled.
 	Default: 4096
 
+UDP variables:
+
+udp_mem - INTERGER
+	Number of pages allowed for queueing by all UDP sockets.
+	Minimal value is 4096. If 4096 is set, UDP memory will not
+	be limited.
+	Default: 4096
+
 CIPSOv4 Variables:
 
 cipso_cache_enable - BOOLEAN


^ permalink raw reply

* Re: [RFD] iptables:  mangle table obsoletes filter table
From: Al Boldi @ 2007-10-12 12:25 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: netfilter-devel, netdev, linux-kernel
In-Reply-To: <470F5F19.70606@trash.net>

Patrick McHardy wrote:
> Al Boldi wrote:
> > Patrick McHardy wrote:
> >>Please send mails discussing netfilter to netfilter-devel.
> >
> > Ok.  I just found out this changed to vger.  But
> > netfilter-devel@vger.kernel.org is bouncing me.
>
> Seems to work, I got your mail on netfilter-devel.

Looks like it works sometimes.  Added lkml as a backup...

> >>Al Boldi wrote:
> >>>With the existence of the mangle table, how useful is the filter table?
> >>>
> >>>Other than requiring the REJECT target to be ported to the mangle
> >>> table, is the filter table faster than the mangle table?
> >>
> >>There are some minor differences in ordering (mangle comes before
> >>DNAT, filter afterwards), but for most rulesets thats completely
> >>irrelevant. The only difference that really matters is that mangle
> >>performs rerouting in LOCAL_OUT for packets that had their routing
> >>key changed, so its really a superset of the filter table. If you
> >>want to use REJECT in the mangle table, you just need to remove the
> >>restriction to filter, it works fine. I would prefer to also remove
> >>the restriction of MARK, CONNMARK etc. to mangle, they're used for
> >>more than just routing today so that restriction also doesn't make
> >>much sense. Patches for this are welcome.
> >
> > Something like this (untested):
> >
> > --- ipt_REJECT.bak.c    2007-10-12 08:25:17.000000000 +0300
> > +++ ipt_REJECT.c        2007-10-12 08:31:44.000000000 +0300
> > @@ -165,6 +165,7 @@ static void send_reset(struct sk_buff *o
> >
> >  static inline void send_unreach(struct sk_buff *skb_in, int code)
> >  {
> > +       if (!skb_in->dst) ip_route_me_harder(&skb_in, RTN_UNSPEC);
> >         icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);
> >  }
> >
> > @@ -245,9 +246,6 @@ static struct xt_target ipt_reject_reg =
> >         .family         = AF_INET,
> >         .target         = reject,
> >         .targetsize     = sizeof(struct ipt_reject_info),
> > -       .table          = "filter",
> > -       .hooks          = (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) |
> > -                         (1 << NF_IP_LOCAL_OUT),
> >         .checkentry     = check,
> >         .me             = THIS_MODULE,
> >  };
>
> That includes an unrelated change, I meant to simply remove the filter
> table restriction.
>
> >>>If not, then shouldn't the filter table be obsoleted to avoid
> >>> confusion?
> >>
> >>That would probably confuse people. Just don't use it if you don't
> >>need to.
> >
> > The problem is that people think they are safe with the filter table,
> > when in fact they need the prerouting chain to seal things.  Right now
> > this is only possible in the mangle table.
>
> Why do they need PREROUTING?

Well, for example to stop any transient packets being forwarded.  You could 
probably hack around this using mark's, but you can't stop the implied route 
lookup, unless you stop it in prerouting.


Thanks!

--
Al


^ permalink raw reply

* Re: [RFD] iptables:  mangle table obsoletes filter table
From: Patrick McHardy @ 2007-10-12 12:31 UTC (permalink / raw)
  To: Al Boldi; +Cc: netfilter-devel, netdev, linux-kernel
In-Reply-To: <200710121525.44510.a1426z@gawab.com>

Al Boldi wrote:
>>>The problem is that people think they are safe with the filter table,
>>>when in fact they need the prerouting chain to seal things.  Right now
>>>this is only possible in the mangle table.
>>
>>Why do they need PREROUTING?
> 
> 
> Well, for example to stop any transient packets being forwarded.  You could 
> probably hack around this using mark's, but you can't stop the implied route 
> lookup, unless you stop it in prerouting.


This also works fine in FORWARD with a little extra overhead.
If you really have to save resources, you should use PREROUTING/raw
to also avoid the creation of a connection tracking entry.


^ permalink raw reply

* Kernel panic (network stack)
From: xeb @ 2007-10-12 12:35 UTC (permalink / raw)
  To: netdev


----------  Пересланное сообщение  ----------

Тема: Kernel panic (network stack)
Дата: 12 октября 2007
Отправитель: xeb@mail.ru
получатель:  linux-kernel@vger.kernel.org

Hello!
I develop network driver.
It works fine while less then 100 network interfaces exists.
Then i give kernel panic. What could cause it ?

general protection fault: 0000 [1] PREEMPT SMP
CPU 1
Modules linked in: ppp_deflate zlib_deflate zlib_inflate pptp pppox 
ppp_generic slhc rtc 8139too 
Pid: 0, comm: swapper Noy tainted 2.6.22-gentoo-r8 #5
RIP: 0010:[<ffffffff8025ec9b>] [<ffffffff8025ec9b>] put_page+0x1b/0x110
RSP: 0018:ffff81000171fda0 EFLAGS: 00010286
RAX: ffff81000ec31080 RBX: a2e9690005e3ffff RCX: 0000000000000000
RDX: 0000000000000000 RSI: 000000000000005a RDI: a2e9690005e3ffff
RBP: ffff81000ec31080 R08: ffff81000ec31046 R09: 0000000000000001
R10: 0000000000000000 R11: ffffffff80467910 R12: ffff81001a912800
R13: 0000000000000008 R14: ffffffff805f7440 R15: ffff81001a912800
FS:  00002ad3cba47ae0(0000) GS: ffff81001be7df40(0000) knlGS: 00000000f7e3b6b0
CS:  0010 DS: 0018 ES: 0018 CR0: 0000000008005003b
CR2: 0000000000413ae0 CR3: 00000000011ef000 CR4: 00000000000006e0
Process swapper (pid:0, threadinfo ffff810001718000, task ffff81001be6e730
Stack: 0000000000000000 0000000000000001 ffff81000f16f0c0 ffff81001a912800
 0000000000000008 fffffff80463ab7 ffff8100129d1e42 ffff81000f16f0c0
 ffff81000f16f0c0 fffffff80463859 ffffffff806081b0 ffffffff80489fb5
Call Trace:
<IRQ> [<ffffffff80463ab7>] skb_release_data+0x77/0xd0
[<ffffffff80463859>] kfree_skbmem+0x9/0x80
[<ffffffff80489fb5>] ip_rcv+0xc5/0x6a0
[<ffffffff8046aeb5>] netif_receive_skb+0x3f5/0x400
[<ffffffff8046ad58>] netif_receive_skb+0x298/0x400
[<ffffffff8046af5b>] process_backlog+0x9b/0x130
[<ffffffff8046b078>] net_rx_action+0x88/0x1d0
[<ffffffff8808e632>] :8139too:rtl8139_interrupt+0x142/0x550
[<ffffffff802335fb>] __do_softirq+0x6b/0xf0
[<ffffffff8020acbc>] call_softirq+0x1c/0x30
[<ffffffff8020cbda>] do_softirq+0x4a/0xb0
[<ffffffff8020cb10>] do_IRQ+0x80/0x100
[<ffffffff80207b40>] default_idle+0x0/0x50
[<ffffffff80209fe1>] ret_from_intr+0x0/0xa
<EOI> <ffffffff80207b69>] default_idle+0x29/0x50
[<ffffffff80207d90>] cpu_idle+0x90/0xa0


Code: 8b 07 f6 c4 40 0f 85 cc 00 00 00 f0 ff 4f 08 0f 94 c0 84 c0
RIP [<ffffffff8025ec9b>] put_page+0x1b/0x110
 RSP: 0018:ffff81000171fda0
Kernel panic - not syncing: Aiee, killing interrupt handler!




-------------------------------------------------------

^ permalink raw reply

* [PATCH] Also do tc_core_time2big argument (long->unsigned).
From: Andreas Henriksson @ 2007-10-12 12:37 UTC (permalink / raw)
  To: shemminger; +Cc: netdev, Patrick McHardy, Andreas Henriksson
In-Reply-To: <470F6264.5090808@trash.net>

tc_core_time2big only used in tc/q_netem.c where it gets passed an unsigned.

Signed-off-by: Andreas Henriksson <andreas@fatal.se>
---
 tc/tc_core.c |    2 +-
 tc/tc_core.h |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/tc/tc_core.c b/tc/tc_core.c
index 8c3a2ac..1365e08 100644
--- a/tc/tc_core.c
+++ b/tc/tc_core.c
@@ -26,7 +26,7 @@
 static double tick_in_usec = 1;
 static double clock_factor = 1;
 
-int tc_core_time2big(long time)
+int tc_core_time2big(unsigned time)
 {
 	__u64 t = time;
 
diff --git a/tc/tc_core.h b/tc/tc_core.h
index b1ede1e..3a0ed7c 100644
--- a/tc/tc_core.h
+++ b/tc/tc_core.h
@@ -6,7 +6,7 @@
 
 #define TIME_UNITS_PER_SEC	1000000
 
-int  tc_core_time2big(long time);
+int  tc_core_time2big(unsigned time);
 unsigned tc_core_time2tick(unsigned time);
 unsigned tc_core_tick2time(unsigned tick);
 unsigned tc_core_time2ktime(unsigned time);
-- 
1.5.3.4


^ permalink raw reply related

* [PATCH 0/9] Consolidate IP fragment management
From: Pavel Emelyanov @ 2007-10-12 12:55 UTC (permalink / raw)
  To: David Miller; +Cc: Patrick McHardy, Linux Netdev List, devel

Patrick recently pointed out, that there are three places that 
perform IP fragments management. In ipv4, ipv6 and in ip6 
conntracks. Looks like these places can be a bit consolidated.

The proposal is to create a common structure inet_frag_queue to 
put common fields like list heads, refcounts etc in, and include
it into the specific fragment queues. Then such objects like 
hash tables, lists, locks etc are moved to common place (struct 
inet_frags). At the end common code is moved to the 
net/ipv4/inet_fragment.c.

The inet_ prefix in file names, data structures and functions, and
the code place (net/ipv4) was proposed by Alexey, but the exact
names were selectd by me, so maybe there can be a better ones.

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>

^ permalink raw reply

* Re: [RFD] iptables:  mangle table obsoletes filter table
From: Jan Engelhardt @ 2007-10-12 13:01 UTC (permalink / raw)
  To: Al Boldi
  Cc: Netfilter Developer Mailing List, netdev, linux-net,
	Linux Kernel Mailing List, kaber
In-Reply-To: <200710120031.42805.a1426z@gawab.com>


On Oct 12 2007 00:31, Al Boldi wrote:
>
>With the existence of the mangle table, how useful is the filter table?

A similar discussion was back in March 2007.
http://marc.info/?l=netfilter-devel&m=117394977210823&w=2
http://marc.info/?l=netfilter-devel&m=117400063907706&w=2

in the end, my proposal was something like
http://jengelh.hopto.org/GFX0/nf_proposal2.svg

^ permalink raw reply

* [PATCH 1/9] Move common fields from frag_queues in one place
From: Pavel Emelyanov @ 2007-10-12 13:00 UTC (permalink / raw)
  To: David Miller; +Cc: Patrick McHardy, Linux Netdev List, devel
In-Reply-To: <470F6EAE.60308@openvz.org>

Introduce the struct inet_frag_queue in include/net/inet_frag.h
file and place there all the common fields from three structs:

 * struct ipq in ipv4/ip_fragment.c
 * struct nf_ct_frag6_queue in nf_conntrack_reasm.c
 * struct frag_queue in ipv6/reassembly.c

After this, replace these fields on appropriate structures with
this structure instance and fix the users to use correct names
i.e. hunks like

-    atomic_dec(&fq->refcnt);
+    atomic_dec(&fq->q.refcnt);

(these occupy most of the patch)

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>

---

diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
new file mode 100644
index 0000000..74e9cb9
--- /dev/null
+++ b/include/net/inet_frag.h
@@ -0,0 +1,21 @@
+#ifndef __NET_FRAG_H__
+#define __NET_FRAG_H__
+
+struct inet_frag_queue {
+	struct hlist_node	list;
+	struct list_head	lru_list;   /* lru list member */
+	spinlock_t		lock;
+	atomic_t		refcnt;
+	struct timer_list	timer;      /* when will this queue expire? */
+	struct sk_buff		*fragments; /* list of received fragments */
+	ktime_t			stamp;
+	int			len;        /* total length of orig datagram */
+	int			meat;
+	__u8			last_in;    /* first/last segment arrived? */
+
+#define COMPLETE		4
+#define FIRST_IN		2
+#define LAST_IN			1
+};
+
+#endif
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index fabb86d..3eb1b6d 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -39,6 +39,7 @@
 #include <net/icmp.h>
 #include <net/checksum.h>
 #include <net/inetpeer.h>
+#include <net/inet_frag.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
 #include <linux/inet.h>
@@ -74,25 +75,13 @@ struct ipfrag_skb_cb
 
 /* Describe an entry in the "incomplete datagrams" queue. */
 struct ipq {
-	struct hlist_node list;
-	struct list_head lru_list;	/* lru list member 			*/
+	struct inet_frag_queue q;
+
 	u32		user;
 	__be32		saddr;
 	__be32		daddr;
 	__be16		id;
 	u8		protocol;
-	u8		last_in;
-#define COMPLETE		4
-#define FIRST_IN		2
-#define LAST_IN			1
-
-	struct sk_buff	*fragments;	/* linked list of received fragments	*/
-	int		len;		/* total length of original datagram	*/
-	int		meat;
-	spinlock_t	lock;
-	atomic_t	refcnt;
-	struct timer_list timer;	/* when will this queue expire?		*/
-	ktime_t		stamp;
 	int             iif;
 	unsigned int    rid;
 	struct inet_peer *peer;
@@ -111,8 +100,8 @@ int ip_frag_nqueues = 0;
 
 static __inline__ void __ipq_unlink(struct ipq *qp)
 {
-	hlist_del(&qp->list);
-	list_del(&qp->lru_list);
+	hlist_del(&qp->q.list);
+	list_del(&qp->q.lru_list);
 	ip_frag_nqueues--;
 }
 
@@ -144,15 +133,15 @@ static void ipfrag_secret_rebuild(unsigned long dummy)
 		struct ipq *q;
 		struct hlist_node *p, *n;
 
-		hlist_for_each_entry_safe(q, p, n, &ipq_hash[i], list) {
+		hlist_for_each_entry_safe(q, p, n, &ipq_hash[i], q.list) {
 			unsigned int hval = ipqhashfn(q->id, q->saddr,
 						      q->daddr, q->protocol);
 
 			if (hval != i) {
-				hlist_del(&q->list);
+				hlist_del(&q->q.list);
 
 				/* Relink to new hash chain. */
-				hlist_add_head(&q->list, &ipq_hash[hval]);
+				hlist_add_head(&q->q.list, &ipq_hash[hval]);
 			}
 		}
 	}
@@ -198,14 +187,14 @@ static void ip_frag_destroy(struct ipq *qp, int *work)
 {
 	struct sk_buff *fp;
 
-	BUG_TRAP(qp->last_in&COMPLETE);
-	BUG_TRAP(del_timer(&qp->timer) == 0);
+	BUG_TRAP(qp->q.last_in&COMPLETE);
+	BUG_TRAP(del_timer(&qp->q.timer) == 0);
 
 	if (qp->peer)
 		inet_putpeer(qp->peer);
 
 	/* Release all fragment data. */
-	fp = qp->fragments;
+	fp = qp->q.fragments;
 	while (fp) {
 		struct sk_buff *xp = fp->next;
 
@@ -219,7 +208,7 @@ static void ip_frag_destroy(struct ipq *qp, int *work)
 
 static __inline__ void ipq_put(struct ipq *ipq, int *work)
 {
-	if (atomic_dec_and_test(&ipq->refcnt))
+	if (atomic_dec_and_test(&ipq->q.refcnt))
 		ip_frag_destroy(ipq, work);
 }
 
@@ -228,13 +217,13 @@ static __inline__ void ipq_put(struct ipq *ipq, int *work)
  */
 static void ipq_kill(struct ipq *ipq)
 {
-	if (del_timer(&ipq->timer))
-		atomic_dec(&ipq->refcnt);
+	if (del_timer(&ipq->q.timer))
+		atomic_dec(&ipq->q.refcnt);
 
-	if (!(ipq->last_in & COMPLETE)) {
+	if (!(ipq->q.last_in & COMPLETE)) {
 		ipq_unlink(ipq);
-		atomic_dec(&ipq->refcnt);
-		ipq->last_in |= COMPLETE;
+		atomic_dec(&ipq->q.refcnt);
+		ipq->q.last_in |= COMPLETE;
 	}
 }
 
@@ -258,14 +247,14 @@ static void ip_evictor(void)
 			return;
 		}
 		tmp = ipq_lru_list.next;
-		qp = list_entry(tmp, struct ipq, lru_list);
-		atomic_inc(&qp->refcnt);
+		qp = list_entry(tmp, struct ipq, q.lru_list);
+		atomic_inc(&qp->q.refcnt);
 		read_unlock(&ipfrag_lock);
 
-		spin_lock(&qp->lock);
-		if (!(qp->last_in&COMPLETE))
+		spin_lock(&qp->q.lock);
+		if (!(qp->q.last_in&COMPLETE))
 			ipq_kill(qp);
-		spin_unlock(&qp->lock);
+		spin_unlock(&qp->q.lock);
 
 		ipq_put(qp, &work);
 		IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
@@ -279,9 +268,9 @@ static void ip_expire(unsigned long arg)
 {
 	struct ipq *qp = (struct ipq *) arg;
 
-	spin_lock(&qp->lock);
+	spin_lock(&qp->q.lock);
 
-	if (qp->last_in & COMPLETE)
+	if (qp->q.last_in & COMPLETE)
 		goto out;
 
 	ipq_kill(qp);
@@ -289,8 +278,8 @@ static void ip_expire(unsigned long arg)
 	IP_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT);
 	IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
 
-	if ((qp->last_in&FIRST_IN) && qp->fragments != NULL) {
-		struct sk_buff *head = qp->fragments;
+	if ((qp->q.last_in&FIRST_IN) && qp->q.fragments != NULL) {
+		struct sk_buff *head = qp->q.fragments;
 		/* Send an ICMP "Fragment Reassembly Timeout" message. */
 		if ((head->dev = dev_get_by_index(&init_net, qp->iif)) != NULL) {
 			icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
@@ -298,7 +287,7 @@ static void ip_expire(unsigned long arg)
 		}
 	}
 out:
-	spin_unlock(&qp->lock);
+	spin_unlock(&qp->q.lock);
 	ipq_put(qp, NULL);
 }
 
@@ -320,15 +309,15 @@ static struct ipq *ip_frag_intern(struct ipq *qp_in)
 	 * such entry could be created on other cpu, while we
 	 * promoted read lock to write lock.
 	 */
-	hlist_for_each_entry(qp, n, &ipq_hash[hash], list) {
+	hlist_for_each_entry(qp, n, &ipq_hash[hash], q.list) {
 		if (qp->id == qp_in->id		&&
 		    qp->saddr == qp_in->saddr	&&
 		    qp->daddr == qp_in->daddr	&&
 		    qp->protocol == qp_in->protocol &&
 		    qp->user == qp_in->user) {
-			atomic_inc(&qp->refcnt);
+			atomic_inc(&qp->q.refcnt);
 			write_unlock(&ipfrag_lock);
-			qp_in->last_in |= COMPLETE;
+			qp_in->q.last_in |= COMPLETE;
 			ipq_put(qp_in, NULL);
 			return qp;
 		}
@@ -336,13 +325,13 @@ static struct ipq *ip_frag_intern(struct ipq *qp_in)
 #endif
 	qp = qp_in;
 
-	if (!mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time))
-		atomic_inc(&qp->refcnt);
+	if (!mod_timer(&qp->q.timer, jiffies + sysctl_ipfrag_time))
+		atomic_inc(&qp->q.refcnt);
 
-	atomic_inc(&qp->refcnt);
-	hlist_add_head(&qp->list, &ipq_hash[hash]);
-	INIT_LIST_HEAD(&qp->lru_list);
-	list_add_tail(&qp->lru_list, &ipq_lru_list);
+	atomic_inc(&qp->q.refcnt);
+	hlist_add_head(&qp->q.list, &ipq_hash[hash]);
+	INIT_LIST_HEAD(&qp->q.lru_list);
+	list_add_tail(&qp->q.lru_list, &ipq_lru_list);
 	ip_frag_nqueues++;
 	write_unlock(&ipfrag_lock);
 	return qp;
@@ -357,23 +346,23 @@ static struct ipq *ip_frag_create(struct iphdr *iph, u32 user)
 		goto out_nomem;
 
 	qp->protocol = iph->protocol;
-	qp->last_in = 0;
+	qp->q.last_in = 0;
 	qp->id = iph->id;
 	qp->saddr = iph->saddr;
 	qp->daddr = iph->daddr;
 	qp->user = user;
-	qp->len = 0;
-	qp->meat = 0;
-	qp->fragments = NULL;
+	qp->q.len = 0;
+	qp->q.meat = 0;
+	qp->q.fragments = NULL;
 	qp->iif = 0;
 	qp->peer = sysctl_ipfrag_max_dist ? inet_getpeer(iph->saddr, 1) : NULL;
 
 	/* Initialize a timer for this entry. */
-	init_timer(&qp->timer);
-	qp->timer.data = (unsigned long) qp;	/* pointer to queue	*/
-	qp->timer.function = ip_expire;		/* expire function	*/
-	spin_lock_init(&qp->lock);
-	atomic_set(&qp->refcnt, 1);
+	init_timer(&qp->q.timer);
+	qp->q.timer.data = (unsigned long) qp;	/* pointer to queue	*/
+	qp->q.timer.function = ip_expire;		/* expire function	*/
+	spin_lock_init(&qp->q.lock);
+	atomic_set(&qp->q.refcnt, 1);
 
 	return ip_frag_intern(qp);
 
@@ -397,13 +386,13 @@ static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
 
 	read_lock(&ipfrag_lock);
 	hash = ipqhashfn(id, saddr, daddr, protocol);
-	hlist_for_each_entry(qp, n, &ipq_hash[hash], list) {
+	hlist_for_each_entry(qp, n, &ipq_hash[hash], q.list) {
 		if (qp->id == id		&&
 		    qp->saddr == saddr	&&
 		    qp->daddr == daddr	&&
 		    qp->protocol == protocol &&
 		    qp->user == user) {
-			atomic_inc(&qp->refcnt);
+			atomic_inc(&qp->q.refcnt);
 			read_unlock(&ipfrag_lock);
 			return qp;
 		}
@@ -429,7 +418,7 @@ static inline int ip_frag_too_far(struct ipq *qp)
 	end = atomic_inc_return(&peer->rid);
 	qp->rid = end;
 
-	rc = qp->fragments && (end - start) > max;
+	rc = qp->q.fragments && (end - start) > max;
 
 	if (rc) {
 		IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
@@ -442,22 +431,22 @@ static int ip_frag_reinit(struct ipq *qp)
 {
 	struct sk_buff *fp;
 
-	if (!mod_timer(&qp->timer, jiffies + sysctl_ipfrag_time)) {
-		atomic_inc(&qp->refcnt);
+	if (!mod_timer(&qp->q.timer, jiffies + sysctl_ipfrag_time)) {
+		atomic_inc(&qp->q.refcnt);
 		return -ETIMEDOUT;
 	}
 
-	fp = qp->fragments;
+	fp = qp->q.fragments;
 	do {
 		struct sk_buff *xp = fp->next;
 		frag_kfree_skb(fp, NULL);
 		fp = xp;
 	} while (fp);
 
-	qp->last_in = 0;
-	qp->len = 0;
-	qp->meat = 0;
-	qp->fragments = NULL;
+	qp->q.last_in = 0;
+	qp->q.len = 0;
+	qp->q.meat = 0;
+	qp->q.fragments = NULL;
 	qp->iif = 0;
 
 	return 0;
@@ -470,7 +459,7 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 	int flags, offset;
 	int ihl, end;
 
-	if (qp->last_in & COMPLETE)
+	if (qp->q.last_in & COMPLETE)
 		goto err;
 
 	if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) &&
@@ -493,22 +482,22 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 		/* If we already have some bits beyond end
 		 * or have different end, the segment is corrrupted.
 		 */
-		if (end < qp->len ||
-		    ((qp->last_in & LAST_IN) && end != qp->len))
+		if (end < qp->q.len ||
+		    ((qp->q.last_in & LAST_IN) && end != qp->q.len))
 			goto err;
-		qp->last_in |= LAST_IN;
-		qp->len = end;
+		qp->q.last_in |= LAST_IN;
+		qp->q.len = end;
 	} else {
 		if (end&7) {
 			end &= ~7;
 			if (skb->ip_summed != CHECKSUM_UNNECESSARY)
 				skb->ip_summed = CHECKSUM_NONE;
 		}
-		if (end > qp->len) {
+		if (end > qp->q.len) {
 			/* Some bits beyond end -> corruption. */
-			if (qp->last_in & LAST_IN)
+			if (qp->q.last_in & LAST_IN)
 				goto err;
-			qp->len = end;
+			qp->q.len = end;
 		}
 	}
 	if (end == offset)
@@ -524,7 +513,7 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 	 * this fragment, right?
 	 */
 	prev = NULL;
-	for (next = qp->fragments; next != NULL; next = next->next) {
+	for (next = qp->q.fragments; next != NULL; next = next->next) {
 		if (FRAG_CB(next)->offset >= offset)
 			break;	/* bingo! */
 		prev = next;
@@ -558,7 +547,7 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 			if (!pskb_pull(next, i))
 				goto err;
 			FRAG_CB(next)->offset += i;
-			qp->meat -= i;
+			qp->q.meat -= i;
 			if (next->ip_summed != CHECKSUM_UNNECESSARY)
 				next->ip_summed = CHECKSUM_NONE;
 			break;
@@ -573,9 +562,9 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 			if (prev)
 				prev->next = next;
 			else
-				qp->fragments = next;
+				qp->q.fragments = next;
 
-			qp->meat -= free_it->len;
+			qp->q.meat -= free_it->len;
 			frag_kfree_skb(free_it, NULL);
 		}
 	}
@@ -587,19 +576,19 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 	if (prev)
 		prev->next = skb;
 	else
-		qp->fragments = skb;
+		qp->q.fragments = skb;
 
 	if (skb->dev)
 		qp->iif = skb->dev->ifindex;
 	skb->dev = NULL;
-	qp->stamp = skb->tstamp;
-	qp->meat += skb->len;
+	qp->q.stamp = skb->tstamp;
+	qp->q.meat += skb->len;
 	atomic_add(skb->truesize, &ip_frag_mem);
 	if (offset == 0)
-		qp->last_in |= FIRST_IN;
+		qp->q.last_in |= FIRST_IN;
 
 	write_lock(&ipfrag_lock);
-	list_move_tail(&qp->lru_list, &ipq_lru_list);
+	list_move_tail(&qp->q.lru_list, &ipq_lru_list);
 	write_unlock(&ipfrag_lock);
 
 	return;
@@ -614,7 +603,7 @@ err:
 static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev)
 {
 	struct iphdr *iph;
-	struct sk_buff *fp, *head = qp->fragments;
+	struct sk_buff *fp, *head = qp->q.fragments;
 	int len;
 	int ihlen;
 
@@ -625,7 +614,7 @@ static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev)
 
 	/* Allocate a new buffer for the datagram. */
 	ihlen = ip_hdrlen(head);
-	len = ihlen + qp->len;
+	len = ihlen + qp->q.len;
 
 	if (len > 65535)
 		goto out_oversize;
@@ -674,13 +663,13 @@ static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev)
 
 	head->next = NULL;
 	head->dev = dev;
-	head->tstamp = qp->stamp;
+	head->tstamp = qp->q.stamp;
 
 	iph = ip_hdr(head);
 	iph->frag_off = 0;
 	iph->tot_len = htons(len);
 	IP_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
-	qp->fragments = NULL;
+	qp->q.fragments = NULL;
 	return head;
 
 out_nomem:
@@ -715,15 +704,15 @@ struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user)
 	if ((qp = ip_find(ip_hdr(skb), user)) != NULL) {
 		struct sk_buff *ret = NULL;
 
-		spin_lock(&qp->lock);
+		spin_lock(&qp->q.lock);
 
 		ip_frag_queue(qp, skb);
 
-		if (qp->last_in == (FIRST_IN|LAST_IN) &&
-		    qp->meat == qp->len)
+		if (qp->q.last_in == (FIRST_IN|LAST_IN) &&
+		    qp->q.meat == qp->q.len)
 			ret = ip_frag_reasm(qp, dev);
 
-		spin_unlock(&qp->lock);
+		spin_unlock(&qp->q.lock);
 		ipq_put(qp, NULL);
 		return ret;
 	}
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 25442a8..52e9f6a 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -31,6 +31,7 @@
 
 #include <net/sock.h>
 #include <net/snmp.h>
+#include <net/inet_frag.h>
 
 #include <net/ipv6.h>
 #include <net/protocol.h>
@@ -63,25 +64,13 @@ struct nf_ct_frag6_skb_cb
 
 struct nf_ct_frag6_queue
 {
-	struct hlist_node	list;
-	struct list_head	lru_list;	/* lru list member	*/
+	struct inet_frag_queue	q;
 
 	__be32			id;		/* fragment id		*/
 	struct in6_addr		saddr;
 	struct in6_addr		daddr;
 
-	spinlock_t		lock;
-	atomic_t		refcnt;
-	struct timer_list	timer;		/* expire timer		*/
-	struct sk_buff		*fragments;
-	int			len;
-	int			meat;
-	ktime_t			stamp;
 	unsigned int		csum;
-	__u8			last_in;	/* has first/last segment arrived? */
-#define COMPLETE		4
-#define FIRST_IN		2
-#define LAST_IN			1
 	__u16			nhoffset;
 };
 
@@ -97,8 +86,8 @@ int nf_ct_frag6_nqueues = 0;
 
 static __inline__ void __fq_unlink(struct nf_ct_frag6_queue *fq)
 {
-	hlist_del(&fq->list);
-	list_del(&fq->lru_list);
+	hlist_del(&fq->q.list);
+	list_del(&fq->q.lru_list);
 	nf_ct_frag6_nqueues--;
 }
 
@@ -150,14 +139,14 @@ static void nf_ct_frag6_secret_rebuild(unsigned long dummy)
 		struct nf_ct_frag6_queue *q;
 		struct hlist_node *p, *n;
 
-		hlist_for_each_entry_safe(q, p, n, &nf_ct_frag6_hash[i], list) {
+		hlist_for_each_entry_safe(q, p, n, &nf_ct_frag6_hash[i], q.list) {
 			unsigned int hval = ip6qhashfn(q->id,
 						       &q->saddr,
 						       &q->daddr);
 			if (hval != i) {
-				hlist_del(&q->list);
+				hlist_del(&q->q.list);
 				/* Relink to new hash chain. */
-				hlist_add_head(&q->list,
+				hlist_add_head(&q->q.list,
 					       &nf_ct_frag6_hash[hval]);
 			}
 		}
@@ -208,11 +197,11 @@ static void nf_ct_frag6_destroy(struct nf_ct_frag6_queue *fq,
 {
 	struct sk_buff *fp;
 
-	BUG_TRAP(fq->last_in&COMPLETE);
-	BUG_TRAP(del_timer(&fq->timer) == 0);
+	BUG_TRAP(fq->q.last_in&COMPLETE);
+	BUG_TRAP(del_timer(&fq->q.timer) == 0);
 
 	/* Release all fragment data. */
-	fp = fq->fragments;
+	fp = fq->q.fragments;
 	while (fp) {
 		struct sk_buff *xp = fp->next;
 
@@ -225,7 +214,7 @@ static void nf_ct_frag6_destroy(struct nf_ct_frag6_queue *fq,
 
 static __inline__ void fq_put(struct nf_ct_frag6_queue *fq, unsigned int *work)
 {
-	if (atomic_dec_and_test(&fq->refcnt))
+	if (atomic_dec_and_test(&fq->q.refcnt))
 		nf_ct_frag6_destroy(fq, work);
 }
 
@@ -234,13 +223,13 @@ static __inline__ void fq_put(struct nf_ct_frag6_queue *fq, unsigned int *work)
  */
 static __inline__ void fq_kill(struct nf_ct_frag6_queue *fq)
 {
-	if (del_timer(&fq->timer))
-		atomic_dec(&fq->refcnt);
+	if (del_timer(&fq->q.timer))
+		atomic_dec(&fq->q.refcnt);
 
-	if (!(fq->last_in & COMPLETE)) {
+	if (!(fq->q.last_in & COMPLETE)) {
 		fq_unlink(fq);
-		atomic_dec(&fq->refcnt);
-		fq->last_in |= COMPLETE;
+		atomic_dec(&fq->q.refcnt);
+		fq->q.last_in |= COMPLETE;
 	}
 }
 
@@ -263,14 +252,14 @@ static void nf_ct_frag6_evictor(void)
 		}
 		tmp = nf_ct_frag6_lru_list.next;
 		BUG_ON(tmp == NULL);
-		fq = list_entry(tmp, struct nf_ct_frag6_queue, lru_list);
-		atomic_inc(&fq->refcnt);
+		fq = list_entry(tmp, struct nf_ct_frag6_queue, q.lru_list);
+		atomic_inc(&fq->q.refcnt);
 		read_unlock(&nf_ct_frag6_lock);
 
-		spin_lock(&fq->lock);
-		if (!(fq->last_in&COMPLETE))
+		spin_lock(&fq->q.lock);
+		if (!(fq->q.last_in&COMPLETE))
 			fq_kill(fq);
-		spin_unlock(&fq->lock);
+		spin_unlock(&fq->q.lock);
 
 		fq_put(fq, &work);
 	}
@@ -280,15 +269,15 @@ static void nf_ct_frag6_expire(unsigned long data)
 {
 	struct nf_ct_frag6_queue *fq = (struct nf_ct_frag6_queue *) data;
 
-	spin_lock(&fq->lock);
+	spin_lock(&fq->q.lock);
 
-	if (fq->last_in & COMPLETE)
+	if (fq->q.last_in & COMPLETE)
 		goto out;
 
 	fq_kill(fq);
 
 out:
-	spin_unlock(&fq->lock);
+	spin_unlock(&fq->q.lock);
 	fq_put(fq, NULL);
 }
 
@@ -304,13 +293,13 @@ static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash,
 
 	write_lock(&nf_ct_frag6_lock);
 #ifdef CONFIG_SMP
-	hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) {
+	hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], q.list) {
 		if (fq->id == fq_in->id &&
 		    ipv6_addr_equal(&fq_in->saddr, &fq->saddr) &&
 		    ipv6_addr_equal(&fq_in->daddr, &fq->daddr)) {
-			atomic_inc(&fq->refcnt);
+			atomic_inc(&fq->q.refcnt);
 			write_unlock(&nf_ct_frag6_lock);
-			fq_in->last_in |= COMPLETE;
+			fq_in->q.last_in |= COMPLETE;
 			fq_put(fq_in, NULL);
 			return fq;
 		}
@@ -318,13 +307,13 @@ static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash,
 #endif
 	fq = fq_in;
 
-	if (!mod_timer(&fq->timer, jiffies + nf_ct_frag6_timeout))
-		atomic_inc(&fq->refcnt);
+	if (!mod_timer(&fq->q.timer, jiffies + nf_ct_frag6_timeout))
+		atomic_inc(&fq->q.refcnt);
 
-	atomic_inc(&fq->refcnt);
-	hlist_add_head(&fq->list, &nf_ct_frag6_hash[hash]);
-	INIT_LIST_HEAD(&fq->lru_list);
-	list_add_tail(&fq->lru_list, &nf_ct_frag6_lru_list);
+	atomic_inc(&fq->q.refcnt);
+	hlist_add_head(&fq->q.list, &nf_ct_frag6_hash[hash]);
+	INIT_LIST_HEAD(&fq->q.lru_list);
+	list_add_tail(&fq->q.lru_list, &nf_ct_frag6_lru_list);
 	nf_ct_frag6_nqueues++;
 	write_unlock(&nf_ct_frag6_lock);
 	return fq;
@@ -347,9 +336,9 @@ nf_ct_frag6_create(unsigned int hash, __be32 id, struct in6_addr *src,				   str
 	ipv6_addr_copy(&fq->saddr, src);
 	ipv6_addr_copy(&fq->daddr, dst);
 
-	setup_timer(&fq->timer, nf_ct_frag6_expire, (unsigned long)fq);
-	spin_lock_init(&fq->lock);
-	atomic_set(&fq->refcnt, 1);
+	setup_timer(&fq->q.timer, nf_ct_frag6_expire, (unsigned long)fq);
+	spin_lock_init(&fq->q.lock);
+	atomic_set(&fq->q.refcnt, 1);
 
 	return nf_ct_frag6_intern(hash, fq);
 
@@ -365,11 +354,11 @@ fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst)
 	unsigned int hash = ip6qhashfn(id, src, dst);
 
 	read_lock(&nf_ct_frag6_lock);
-	hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], list) {
+	hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], q.list) {
 		if (fq->id == id &&
 		    ipv6_addr_equal(src, &fq->saddr) &&
 		    ipv6_addr_equal(dst, &fq->daddr)) {
-			atomic_inc(&fq->refcnt);
+			atomic_inc(&fq->q.refcnt);
 			read_unlock(&nf_ct_frag6_lock);
 			return fq;
 		}
@@ -386,7 +375,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 	struct sk_buff *prev, *next;
 	int offset, end;
 
-	if (fq->last_in & COMPLETE) {
+	if (fq->q.last_in & COMPLETE) {
 		pr_debug("Allready completed\n");
 		goto err;
 	}
@@ -412,13 +401,13 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 		/* If we already have some bits beyond end
 		 * or have different end, the segment is corrupted.
 		 */
-		if (end < fq->len ||
-		    ((fq->last_in & LAST_IN) && end != fq->len)) {
+		if (end < fq->q.len ||
+		    ((fq->q.last_in & LAST_IN) && end != fq->q.len)) {
 			pr_debug("already received last fragment\n");
 			goto err;
 		}
-		fq->last_in |= LAST_IN;
-		fq->len = end;
+		fq->q.last_in |= LAST_IN;
+		fq->q.len = end;
 	} else {
 		/* Check if the fragment is rounded to 8 bytes.
 		 * Required by the RFC.
@@ -430,13 +419,13 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 			pr_debug("end of fragment not rounded to 8 bytes.\n");
 			return -1;
 		}
-		if (end > fq->len) {
+		if (end > fq->q.len) {
 			/* Some bits beyond end -> corruption. */
-			if (fq->last_in & LAST_IN) {
+			if (fq->q.last_in & LAST_IN) {
 				pr_debug("last packet already reached.\n");
 				goto err;
 			}
-			fq->len = end;
+			fq->q.len = end;
 		}
 	}
 
@@ -458,7 +447,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 	 * this fragment, right?
 	 */
 	prev = NULL;
-	for (next = fq->fragments; next != NULL; next = next->next) {
+	for (next = fq->q.fragments; next != NULL; next = next->next) {
 		if (NFCT_FRAG6_CB(next)->offset >= offset)
 			break;	/* bingo! */
 		prev = next;
@@ -503,7 +492,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 
 			/* next fragment */
 			NFCT_FRAG6_CB(next)->offset += i;
-			fq->meat -= i;
+			fq->q.meat -= i;
 			if (next->ip_summed != CHECKSUM_UNNECESSARY)
 				next->ip_summed = CHECKSUM_NONE;
 			break;
@@ -518,9 +507,9 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 			if (prev)
 				prev->next = next;
 			else
-				fq->fragments = next;
+				fq->q.fragments = next;
 
-			fq->meat -= free_it->len;
+			fq->q.meat -= free_it->len;
 			frag_kfree_skb(free_it, NULL);
 		}
 	}
@@ -532,11 +521,11 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 	if (prev)
 		prev->next = skb;
 	else
-		fq->fragments = skb;
+		fq->q.fragments = skb;
 
 	skb->dev = NULL;
-	fq->stamp = skb->tstamp;
-	fq->meat += skb->len;
+	fq->q.stamp = skb->tstamp;
+	fq->q.meat += skb->len;
 	atomic_add(skb->truesize, &nf_ct_frag6_mem);
 
 	/* The first fragment.
@@ -544,10 +533,10 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 	 */
 	if (offset == 0) {
 		fq->nhoffset = nhoff;
-		fq->last_in |= FIRST_IN;
+		fq->q.last_in |= FIRST_IN;
 	}
 	write_lock(&nf_ct_frag6_lock);
-	list_move_tail(&fq->lru_list, &nf_ct_frag6_lru_list);
+	list_move_tail(&fq->q.lru_list, &nf_ct_frag6_lru_list);
 	write_unlock(&nf_ct_frag6_lock);
 	return 0;
 
@@ -567,7 +556,7 @@ err:
 static struct sk_buff *
 nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
 {
-	struct sk_buff *fp, *op, *head = fq->fragments;
+	struct sk_buff *fp, *op, *head = fq->q.fragments;
 	int    payload_len;
 
 	fq_kill(fq);
@@ -577,7 +566,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
 
 	/* Unfragmented part is taken from the first segment. */
 	payload_len = ((head->data - skb_network_header(head)) -
-		       sizeof(struct ipv6hdr) + fq->len -
+		       sizeof(struct ipv6hdr) + fq->q.len -
 		       sizeof(struct frag_hdr));
 	if (payload_len > IPV6_MAXPLEN) {
 		pr_debug("payload len is too large.\n");
@@ -643,7 +632,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
 
 	head->next = NULL;
 	head->dev = dev;
-	head->tstamp = fq->stamp;
+	head->tstamp = fq->q.stamp;
 	ipv6_hdr(head)->payload_len = htons(payload_len);
 
 	/* Yes, and fold redundant checksum back. 8) */
@@ -652,7 +641,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
 					  skb_network_header_len(head),
 					  head->csum);
 
-	fq->fragments = NULL;
+	fq->q.fragments = NULL;
 
 	/* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */
 	fp = skb_shinfo(head)->frag_list;
@@ -797,21 +786,21 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
 		goto ret_orig;
 	}
 
-	spin_lock(&fq->lock);
+	spin_lock(&fq->q.lock);
 
 	if (nf_ct_frag6_queue(fq, clone, fhdr, nhoff) < 0) {
-		spin_unlock(&fq->lock);
+		spin_unlock(&fq->q.lock);
 		pr_debug("Can't insert skb to queue\n");
 		fq_put(fq, NULL);
 		goto ret_orig;
 	}
 
-	if (fq->last_in == (FIRST_IN|LAST_IN) && fq->meat == fq->len) {
+	if (fq->q.last_in == (FIRST_IN|LAST_IN) && fq->q.meat == fq->q.len) {
 		ret_skb = nf_ct_frag6_reasm(fq, dev);
 		if (ret_skb == NULL)
 			pr_debug("Can't reassemble fragmented packets\n");
 	}
-	spin_unlock(&fq->lock);
+	spin_unlock(&fq->q.lock);
 
 	fq_put(fq, NULL);
 	return ret_skb;
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 31601c9..f48ecc6 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -53,6 +53,7 @@
 #include <net/rawv6.h>
 #include <net/ndisc.h>
 #include <net/addrconf.h>
+#include <net/inet_frag.h>
 
 int sysctl_ip6frag_high_thresh __read_mostly = 256*1024;
 int sysctl_ip6frag_low_thresh __read_mostly = 192*1024;
@@ -74,26 +75,14 @@ struct ip6frag_skb_cb
 
 struct frag_queue
 {
-	struct hlist_node	list;
-	struct list_head lru_list;		/* lru list member	*/
+	struct inet_frag_queue	q;
 
 	__be32			id;		/* fragment id		*/
 	struct in6_addr		saddr;
 	struct in6_addr		daddr;
 
-	spinlock_t		lock;
-	atomic_t		refcnt;
-	struct timer_list	timer;		/* expire timer		*/
-	struct sk_buff		*fragments;
-	int			len;
-	int			meat;
 	int			iif;
-	ktime_t			stamp;
 	unsigned int		csum;
-	__u8			last_in;	/* has first/last segment arrived? */
-#define COMPLETE		4
-#define FIRST_IN		2
-#define LAST_IN			1
 	__u16			nhoffset;
 };
 
@@ -109,8 +98,8 @@ int ip6_frag_nqueues = 0;
 
 static __inline__ void __fq_unlink(struct frag_queue *fq)
 {
-	hlist_del(&fq->list);
-	list_del(&fq->lru_list);
+	hlist_del(&fq->q.list);
+	list_del(&fq->q.lru_list);
 	ip6_frag_nqueues--;
 }
 
@@ -166,16 +155,16 @@ static void ip6_frag_secret_rebuild(unsigned long dummy)
 		struct frag_queue *q;
 		struct hlist_node *p, *n;
 
-		hlist_for_each_entry_safe(q, p, n, &ip6_frag_hash[i], list) {
+		hlist_for_each_entry_safe(q, p, n, &ip6_frag_hash[i], q.list) {
 			unsigned int hval = ip6qhashfn(q->id,
 						       &q->saddr,
 						       &q->daddr);
 
 			if (hval != i) {
-				hlist_del(&q->list);
+				hlist_del(&q->q.list);
 
 				/* Relink to new hash chain. */
-				hlist_add_head(&q->list,
+				hlist_add_head(&q->q.list,
 					       &ip6_frag_hash[hval]);
 
 			}
@@ -222,11 +211,11 @@ static void ip6_frag_destroy(struct frag_queue *fq, int *work)
 {
 	struct sk_buff *fp;
 
-	BUG_TRAP(fq->last_in&COMPLETE);
-	BUG_TRAP(del_timer(&fq->timer) == 0);
+	BUG_TRAP(fq->q.last_in&COMPLETE);
+	BUG_TRAP(del_timer(&fq->q.timer) == 0);
 
 	/* Release all fragment data. */
-	fp = fq->fragments;
+	fp = fq->q.fragments;
 	while (fp) {
 		struct sk_buff *xp = fp->next;
 
@@ -239,7 +228,7 @@ static void ip6_frag_destroy(struct frag_queue *fq, int *work)
 
 static __inline__ void fq_put(struct frag_queue *fq, int *work)
 {
-	if (atomic_dec_and_test(&fq->refcnt))
+	if (atomic_dec_and_test(&fq->q.refcnt))
 		ip6_frag_destroy(fq, work);
 }
 
@@ -248,13 +237,13 @@ static __inline__ void fq_put(struct frag_queue *fq, int *work)
  */
 static __inline__ void fq_kill(struct frag_queue *fq)
 {
-	if (del_timer(&fq->timer))
-		atomic_dec(&fq->refcnt);
+	if (del_timer(&fq->q.timer))
+		atomic_dec(&fq->q.refcnt);
 
-	if (!(fq->last_in & COMPLETE)) {
+	if (!(fq->q.last_in & COMPLETE)) {
 		fq_unlink(fq);
-		atomic_dec(&fq->refcnt);
-		fq->last_in |= COMPLETE;
+		atomic_dec(&fq->q.refcnt);
+		fq->q.last_in |= COMPLETE;
 	}
 }
 
@@ -275,14 +264,14 @@ static void ip6_evictor(struct inet6_dev *idev)
 			return;
 		}
 		tmp = ip6_frag_lru_list.next;
-		fq = list_entry(tmp, struct frag_queue, lru_list);
-		atomic_inc(&fq->refcnt);
+		fq = list_entry(tmp, struct frag_queue, q.lru_list);
+		atomic_inc(&fq->q.refcnt);
 		read_unlock(&ip6_frag_lock);
 
-		spin_lock(&fq->lock);
-		if (!(fq->last_in&COMPLETE))
+		spin_lock(&fq->q.lock);
+		if (!(fq->q.last_in&COMPLETE))
 			fq_kill(fq);
-		spin_unlock(&fq->lock);
+		spin_unlock(&fq->q.lock);
 
 		fq_put(fq, &work);
 		IP6_INC_STATS_BH(idev, IPSTATS_MIB_REASMFAILS);
@@ -294,9 +283,9 @@ static void ip6_frag_expire(unsigned long data)
 	struct frag_queue *fq = (struct frag_queue *) data;
 	struct net_device *dev = NULL;
 
-	spin_lock(&fq->lock);
+	spin_lock(&fq->q.lock);
 
-	if (fq->last_in & COMPLETE)
+	if (fq->q.last_in & COMPLETE)
 		goto out;
 
 	fq_kill(fq);
@@ -311,7 +300,7 @@ static void ip6_frag_expire(unsigned long data)
 	rcu_read_unlock();
 
 	/* Don't send error if the first segment did not arrive. */
-	if (!(fq->last_in&FIRST_IN) || !fq->fragments)
+	if (!(fq->q.last_in&FIRST_IN) || !fq->q.fragments)
 		goto out;
 
 	/*
@@ -319,12 +308,12 @@ static void ip6_frag_expire(unsigned long data)
 	   segment was received. And do not use fq->dev
 	   pointer directly, device might already disappeared.
 	 */
-	fq->fragments->dev = dev;
-	icmpv6_send(fq->fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev);
+	fq->q.fragments->dev = dev;
+	icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev);
 out:
 	if (dev)
 		dev_put(dev);
-	spin_unlock(&fq->lock);
+	spin_unlock(&fq->q.lock);
 	fq_put(fq, NULL);
 }
 
@@ -342,13 +331,13 @@ static struct frag_queue *ip6_frag_intern(struct frag_queue *fq_in)
 	write_lock(&ip6_frag_lock);
 	hash = ip6qhashfn(fq_in->id, &fq_in->saddr, &fq_in->daddr);
 #ifdef CONFIG_SMP
-	hlist_for_each_entry(fq, n, &ip6_frag_hash[hash], list) {
+	hlist_for_each_entry(fq, n, &ip6_frag_hash[hash], q.list) {
 		if (fq->id == fq_in->id &&
 		    ipv6_addr_equal(&fq_in->saddr, &fq->saddr) &&
 		    ipv6_addr_equal(&fq_in->daddr, &fq->daddr)) {
-			atomic_inc(&fq->refcnt);
+			atomic_inc(&fq->q.refcnt);
 			write_unlock(&ip6_frag_lock);
-			fq_in->last_in |= COMPLETE;
+			fq_in->q.last_in |= COMPLETE;
 			fq_put(fq_in, NULL);
 			return fq;
 		}
@@ -356,13 +345,13 @@ static struct frag_queue *ip6_frag_intern(struct frag_queue *fq_in)
 #endif
 	fq = fq_in;
 
-	if (!mod_timer(&fq->timer, jiffies + sysctl_ip6frag_time))
-		atomic_inc(&fq->refcnt);
+	if (!mod_timer(&fq->q.timer, jiffies + sysctl_ip6frag_time))
+		atomic_inc(&fq->q.refcnt);
 
-	atomic_inc(&fq->refcnt);
-	hlist_add_head(&fq->list, &ip6_frag_hash[hash]);
-	INIT_LIST_HEAD(&fq->lru_list);
-	list_add_tail(&fq->lru_list, &ip6_frag_lru_list);
+	atomic_inc(&fq->q.refcnt);
+	hlist_add_head(&fq->q.list, &ip6_frag_hash[hash]);
+	INIT_LIST_HEAD(&fq->q.lru_list);
+	list_add_tail(&fq->q.lru_list, &ip6_frag_lru_list);
 	ip6_frag_nqueues++;
 	write_unlock(&ip6_frag_lock);
 	return fq;
@@ -382,11 +371,11 @@ ip6_frag_create(__be32 id, struct in6_addr *src, struct in6_addr *dst,
 	ipv6_addr_copy(&fq->saddr, src);
 	ipv6_addr_copy(&fq->daddr, dst);
 
-	init_timer(&fq->timer);
-	fq->timer.function = ip6_frag_expire;
-	fq->timer.data = (long) fq;
-	spin_lock_init(&fq->lock);
-	atomic_set(&fq->refcnt, 1);
+	init_timer(&fq->q.timer);
+	fq->q.timer.function = ip6_frag_expire;
+	fq->q.timer.data = (long) fq;
+	spin_lock_init(&fq->q.lock);
+	atomic_set(&fq->q.refcnt, 1);
 
 	return ip6_frag_intern(fq);
 
@@ -405,11 +394,11 @@ fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst,
 
 	read_lock(&ip6_frag_lock);
 	hash = ip6qhashfn(id, src, dst);
-	hlist_for_each_entry(fq, n, &ip6_frag_hash[hash], list) {
+	hlist_for_each_entry(fq, n, &ip6_frag_hash[hash], q.list) {
 		if (fq->id == id &&
 		    ipv6_addr_equal(src, &fq->saddr) &&
 		    ipv6_addr_equal(dst, &fq->daddr)) {
-			atomic_inc(&fq->refcnt);
+			atomic_inc(&fq->q.refcnt);
 			read_unlock(&ip6_frag_lock);
 			return fq;
 		}
@@ -426,7 +415,7 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
 	struct sk_buff *prev, *next;
 	int offset, end;
 
-	if (fq->last_in & COMPLETE)
+	if (fq->q.last_in & COMPLETE)
 		goto err;
 
 	offset = ntohs(fhdr->frag_off) & ~0x7;
@@ -454,11 +443,11 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
 		/* If we already have some bits beyond end
 		 * or have different end, the segment is corrupted.
 		 */
-		if (end < fq->len ||
-		    ((fq->last_in & LAST_IN) && end != fq->len))
+		if (end < fq->q.len ||
+		    ((fq->q.last_in & LAST_IN) && end != fq->q.len))
 			goto err;
-		fq->last_in |= LAST_IN;
-		fq->len = end;
+		fq->q.last_in |= LAST_IN;
+		fq->q.len = end;
 	} else {
 		/* Check if the fragment is rounded to 8 bytes.
 		 * Required by the RFC.
@@ -473,11 +462,11 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
 					  offsetof(struct ipv6hdr, payload_len));
 			return;
 		}
-		if (end > fq->len) {
+		if (end > fq->q.len) {
 			/* Some bits beyond end -> corruption. */
-			if (fq->last_in & LAST_IN)
+			if (fq->q.last_in & LAST_IN)
 				goto err;
-			fq->len = end;
+			fq->q.len = end;
 		}
 	}
 
@@ -496,7 +485,7 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
 	 * this fragment, right?
 	 */
 	prev = NULL;
-	for(next = fq->fragments; next != NULL; next = next->next) {
+	for(next = fq->q.fragments; next != NULL; next = next->next) {
 		if (FRAG6_CB(next)->offset >= offset)
 			break;	/* bingo! */
 		prev = next;
@@ -533,7 +522,7 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
 			if (!pskb_pull(next, i))
 				goto err;
 			FRAG6_CB(next)->offset += i;	/* next fragment */
-			fq->meat -= i;
+			fq->q.meat -= i;
 			if (next->ip_summed != CHECKSUM_UNNECESSARY)
 				next->ip_summed = CHECKSUM_NONE;
 			break;
@@ -548,9 +537,9 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
 			if (prev)
 				prev->next = next;
 			else
-				fq->fragments = next;
+				fq->q.fragments = next;
 
-			fq->meat -= free_it->len;
+			fq->q.meat -= free_it->len;
 			frag_kfree_skb(free_it, NULL);
 		}
 	}
@@ -562,13 +551,13 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
 	if (prev)
 		prev->next = skb;
 	else
-		fq->fragments = skb;
+		fq->q.fragments = skb;
 
 	if (skb->dev)
 		fq->iif = skb->dev->ifindex;
 	skb->dev = NULL;
-	fq->stamp = skb->tstamp;
-	fq->meat += skb->len;
+	fq->q.stamp = skb->tstamp;
+	fq->q.meat += skb->len;
 	atomic_add(skb->truesize, &ip6_frag_mem);
 
 	/* The first fragment.
@@ -576,10 +565,10 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
 	 */
 	if (offset == 0) {
 		fq->nhoffset = nhoff;
-		fq->last_in |= FIRST_IN;
+		fq->q.last_in |= FIRST_IN;
 	}
 	write_lock(&ip6_frag_lock);
-	list_move_tail(&fq->lru_list, &ip6_frag_lru_list);
+	list_move_tail(&fq->q.lru_list, &ip6_frag_lru_list);
 	write_unlock(&ip6_frag_lock);
 	return;
 
@@ -600,7 +589,7 @@ err:
 static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
 			  struct net_device *dev)
 {
-	struct sk_buff *fp, *head = fq->fragments;
+	struct sk_buff *fp, *head = fq->q.fragments;
 	int    payload_len;
 	unsigned int nhoff;
 
@@ -611,7 +600,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
 
 	/* Unfragmented part is taken from the first segment. */
 	payload_len = ((head->data - skb_network_header(head)) -
-		       sizeof(struct ipv6hdr) + fq->len -
+		       sizeof(struct ipv6hdr) + fq->q.len -
 		       sizeof(struct frag_hdr));
 	if (payload_len > IPV6_MAXPLEN)
 		goto out_oversize;
@@ -670,7 +659,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
 
 	head->next = NULL;
 	head->dev = dev;
-	head->tstamp = fq->stamp;
+	head->tstamp = fq->q.stamp;
 	ipv6_hdr(head)->payload_len = htons(payload_len);
 	IP6CB(head)->nhoff = nhoff;
 
@@ -685,7 +674,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
 	rcu_read_lock();
 	IP6_INC_STATS_BH(__in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
 	rcu_read_unlock();
-	fq->fragments = NULL;
+	fq->q.fragments = NULL;
 	return 1;
 
 out_oversize:
@@ -746,15 +735,15 @@ static int ipv6_frag_rcv(struct sk_buff **skbp)
 			  ip6_dst_idev(skb->dst))) != NULL) {
 		int ret = -1;
 
-		spin_lock(&fq->lock);
+		spin_lock(&fq->q.lock);
 
 		ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff);
 
-		if (fq->last_in == (FIRST_IN|LAST_IN) &&
-		    fq->meat == fq->len)
+		if (fq->q.last_in == (FIRST_IN|LAST_IN) &&
+		    fq->q.meat == fq->q.len)
 			ret = ip6_frag_reasm(fq, skbp, dev);
 
-		spin_unlock(&fq->lock);
+		spin_unlock(&fq->q.lock);
 		fq_put(fq, NULL);
 		return ret;
 	}
-- 
1.5.3.4


^ permalink raw reply related

* [PATCH] NEW EMAC Fix RGMII build error: use of_device_is_compatible
From: Valentine Barshak @ 2007-10-12 13:04 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: netdev

Fix build RGMII error: use of_device_is_compatible()
insteadof now deprecated device_is_compatible() function.

Signed-off-by: Valentine Barshak <vbarshak@ru.mvista.com>
---
 drivers/net/ibm_newemac/rgmii.c |    2 +-
 1 files changed, 1 insertion(+), 1 deletion(-)

diff -pruN linux-2.6.orig/drivers/net/ibm_newemac/rgmii.c linux-2.6/drivers/net/ibm_newemac/rgmii.c
--- linux-2.6.orig/drivers/net/ibm_newemac/rgmii.c	2007-10-12 16:02:41.000000000 +0400
+++ linux-2.6/drivers/net/ibm_newemac/rgmii.c	2007-10-12 16:49:07.000000000 +0400
@@ -251,7 +251,7 @@ static int __devinit rgmii_probe(struct 
 	}
 
 	/* Check for RGMII type */
-	if (device_is_compatible(ofdev->node, "ibm,rgmii-axon"))
+	if (of_device_is_compatible(ofdev->node, "ibm,rgmii-axon"))
 		dev->type = RGMII_AXON;
 	else
 		dev->type = RGMII_STANDARD;

^ permalink raw reply

* [PATCH 2/9] Collect frag queues management objects together
From: Pavel Emelyanov @ 2007-10-12 13:06 UTC (permalink / raw)
  To: David Miller; +Cc: Patrick McHardy, Linux Netdev List, devel
In-Reply-To: <470F6EAE.60308@openvz.org>

There are some objects that are common in all the places
which are used to keep track of frag queues, they are:

 * hash table
 * LRU list
 * rw lock
 * rnd number for hash function
 * the number of queues
 * the amount of memory occupied by queues
 * secret timer

Move all this stuff into one structure (struct inet_frags)
to make it possible use them uniformly in the future. Like
with the previous patch this mostly consists of hunks like

-    write_lock(&ipfrag_lock);
+    write_lock(&ip4_frags.lock);

To address the issue with exporting the number of queues and 
the amount of memory occupied by queues outside the .c file
they are declared in, I introduce a couple of helpers.

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>

---

diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index 74e9cb9..d51f238 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -18,4 +18,19 @@ struct inet_frag_queue {
 #define LAST_IN			1
 };
 
+#define INETFRAGS_HASHSZ		64
+
+struct inet_frags {
+	struct list_head	lru_list;
+	struct hlist_head	hash[INETFRAGS_HASHSZ];
+	rwlock_t		lock;
+	u32			rnd;
+	int			nqueues;
+	atomic_t		mem;
+	struct timer_list	secret_timer;
+};
+
+void inet_frags_init(struct inet_frags *);
+void inet_frags_fini(struct inet_frags *);
+
 #endif
diff --git a/include/net/ip.h b/include/net/ip.h
index 3af3ed9..a18dcec 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -333,8 +333,8 @@ enum ip_defrag_users
 };
 
 struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user);
-extern int ip_frag_nqueues;
-extern atomic_t ip_frag_mem;
+int ip_frag_mem(void);
+int ip_frag_nqueues(void);
 
 /*
  *	Functions provided by ip_forward.c
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 31b3f1b..77cdab3 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -252,8 +252,8 @@ struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
 
 extern int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb);
 
-extern int ip6_frag_nqueues;
-extern atomic_t ip6_frag_mem;
+int ip6_frag_nqueues(void);
+int ip6_frag_mem(void);
 
 #define IPV6_FRAG_TIMEOUT	(60*HZ)		/* 60 seconds */
 
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index a02c36d..93fe396 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -10,7 +10,8 @@ obj-y     := route.o inetpeer.o protocol.o \
 	     tcp_minisocks.o tcp_cong.o \
 	     datagram.o raw.o udp.o udplite.o \
 	     arp.o icmp.o devinet.o af_inet.o  igmp.o \
-	     sysctl_net_ipv4.o fib_frontend.o fib_semantics.o
+	     sysctl_net_ipv4.o fib_frontend.o fib_semantics.o \
+	     inet_fragment.o
 
 obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o
 obj-$(CONFIG_IP_FIB_TRIE) += fib_trie.o
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
new file mode 100644
index 0000000..69623ff
--- /dev/null
+++ b/net/ipv4/inet_fragment.c
@@ -0,0 +1,44 @@
+/*
+ * inet fragments management
+ *
+ *		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.
+ *
+ * 		Authors:	Pavel Emelyanov <xemul@openvz.org>
+ *				Started as consolidation of ipv4/ip_fragment.c,
+ *				ipv6/reassembly. and ipv6 nf conntrack reassembly
+ */
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+
+#include <net/inet_frag.h>
+
+void inet_frags_init(struct inet_frags *f)
+{
+	int i;
+
+	for (i = 0; i < INETFRAGS_HASHSZ; i++)
+		INIT_HLIST_HEAD(&f->hash[i]);
+
+	INIT_LIST_HEAD(&f->lru_list);
+	rwlock_init(&f->lock);
+
+	f->rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
+				   (jiffies ^ (jiffies >> 6)));
+
+	f->nqueues = 0;
+	atomic_set(&f->mem, 0);
+
+}
+EXPORT_SYMBOL(inet_frags_init);
+
+void inet_frags_fini(struct inet_frags *f)
+{
+}
+EXPORT_SYMBOL(inet_frags_fini);
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 3eb1b6d..5e1667e 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -87,39 +87,39 @@ struct ipq {
 	struct inet_peer *peer;
 };
 
-/* Hash table. */
+static struct inet_frags ip4_frags;
 
-#define IPQ_HASHSZ	64
+int ip_frag_nqueues(void)
+{
+	return ip4_frags.nqueues;
+}
 
-/* Per-bucket lock is easy to add now. */
-static struct hlist_head ipq_hash[IPQ_HASHSZ];
-static DEFINE_RWLOCK(ipfrag_lock);
-static u32 ipfrag_hash_rnd;
-static LIST_HEAD(ipq_lru_list);
-int ip_frag_nqueues = 0;
+int ip_frag_mem(void)
+{
+	return atomic_read(&ip4_frags.mem);
+}
 
 static __inline__ void __ipq_unlink(struct ipq *qp)
 {
 	hlist_del(&qp->q.list);
 	list_del(&qp->q.lru_list);
-	ip_frag_nqueues--;
+	ip4_frags.nqueues--;
 }
 
 static __inline__ void ipq_unlink(struct ipq *ipq)
 {
-	write_lock(&ipfrag_lock);
+	write_lock(&ip4_frags.lock);
 	__ipq_unlink(ipq);
-	write_unlock(&ipfrag_lock);
+	write_unlock(&ip4_frags.lock);
 }
 
 static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot)
 {
 	return jhash_3words((__force u32)id << 16 | prot,
 			    (__force u32)saddr, (__force u32)daddr,
-			    ipfrag_hash_rnd) & (IPQ_HASHSZ - 1);
+			    ip4_frags.rnd) & (INETFRAGS_HASHSZ - 1);
 }
 
-static struct timer_list ipfrag_secret_timer;
 int sysctl_ipfrag_secret_interval __read_mostly = 10 * 60 * HZ;
 
 static void ipfrag_secret_rebuild(unsigned long dummy)
@@ -127,13 +127,13 @@ static void ipfrag_secret_rebuild(unsigned long dummy)
 	unsigned long now = jiffies;
 	int i;
 
-	write_lock(&ipfrag_lock);
-	get_random_bytes(&ipfrag_hash_rnd, sizeof(u32));
-	for (i = 0; i < IPQ_HASHSZ; i++) {
+	write_lock(&ip4_frags.lock);
+	get_random_bytes(&ip4_frags.rnd, sizeof(u32));
+	for (i = 0; i < INETFRAGS_HASHSZ; i++) {
 		struct ipq *q;
 		struct hlist_node *p, *n;
 
-		hlist_for_each_entry_safe(q, p, n, &ipq_hash[i], q.list) {
+		hlist_for_each_entry_safe(q, p, n, &ip4_frags.hash[i], q.list) {
 			unsigned int hval = ipqhashfn(q->id, q->saddr,
 						      q->daddr, q->protocol);
 
@@ -141,23 +141,21 @@ static void ipfrag_secret_rebuild(unsigned long dummy)
 				hlist_del(&q->q.list);
 
 				/* Relink to new hash chain. */
-				hlist_add_head(&q->q.list, &ipq_hash[hval]);
+				hlist_add_head(&q->q.list, &ip4_frags.hash[hval]);
 			}
 		}
 	}
-	write_unlock(&ipfrag_lock);
+	write_unlock(&ip4_frags.lock);
 
-	mod_timer(&ipfrag_secret_timer, now + sysctl_ipfrag_secret_interval);
+	mod_timer(&ip4_frags.secret_timer, now + sysctl_ipfrag_secret_interval);
 }
 
-atomic_t ip_frag_mem = ATOMIC_INIT(0);	/* Memory used for fragments */
-
 /* Memory Tracking Functions. */
 static __inline__ void frag_kfree_skb(struct sk_buff *skb, int *work)
 {
 	if (work)
 		*work -= skb->truesize;
-	atomic_sub(skb->truesize, &ip_frag_mem);
+	atomic_sub(skb->truesize, &ip4_frags.mem);
 	kfree_skb(skb);
 }
 
@@ -165,7 +163,7 @@ static __inline__ void frag_free_queue(struct ipq *qp, int *work)
 {
 	if (work)
 		*work -= sizeof(struct ipq);
-	atomic_sub(sizeof(struct ipq), &ip_frag_mem);
+	atomic_sub(sizeof(struct ipq), &ip4_frags.mem);
 	kfree(qp);
 }
 
@@ -175,7 +173,7 @@ static __inline__ struct ipq *frag_alloc_queue(void)
 
 	if (!qp)
 		return NULL;
-	atomic_add(sizeof(struct ipq), &ip_frag_mem);
+	atomic_add(sizeof(struct ipq), &ip4_frags.mem);
 	return qp;
 }
 
@@ -236,20 +234,20 @@ static void ip_evictor(void)
 	struct list_head *tmp;
 	int work;
 
-	work = atomic_read(&ip_frag_mem) - sysctl_ipfrag_low_thresh;
+	work = atomic_read(&ip4_frags.mem) - sysctl_ipfrag_low_thresh;
 	if (work <= 0)
 		return;
 
 	while (work > 0) {
-		read_lock(&ipfrag_lock);
-		if (list_empty(&ipq_lru_list)) {
-			read_unlock(&ipfrag_lock);
+		read_lock(&ip4_frags.lock);
+		if (list_empty(&ip4_frags.lru_list)) {
+			read_unlock(&ip4_frags.lock);
 			return;
 		}
-		tmp = ipq_lru_list.next;
+		tmp = ip4_frags.lru_list.next;
 		qp = list_entry(tmp, struct ipq, q.lru_list);
 		atomic_inc(&qp->q.refcnt);
-		read_unlock(&ipfrag_lock);
+		read_unlock(&ip4_frags.lock);
 
 		spin_lock(&qp->q.lock);
 		if (!(qp->q.last_in&COMPLETE))
@@ -301,7 +299,7 @@ static struct ipq *ip_frag_intern(struct ipq *qp_in)
 #endif
 	unsigned int hash;
 
-	write_lock(&ipfrag_lock);
+	write_lock(&ip4_frags.lock);
 	hash = ipqhashfn(qp_in->id, qp_in->saddr, qp_in->daddr,
 			 qp_in->protocol);
 #ifdef CONFIG_SMP
@@ -309,14 +307,14 @@ static struct ipq *ip_frag_intern(struct ipq *qp_in)
 	 * such entry could be created on other cpu, while we
 	 * promoted read lock to write lock.
 	 */
-	hlist_for_each_entry(qp, n, &ipq_hash[hash], q.list) {
+	hlist_for_each_entry(qp, n, &ip4_frags.hash[hash], q.list) {
 		if (qp->id == qp_in->id		&&
 		    qp->saddr == qp_in->saddr	&&
 		    qp->daddr == qp_in->daddr	&&
 		    qp->protocol == qp_in->protocol &&
 		    qp->user == qp_in->user) {
 			atomic_inc(&qp->q.refcnt);
-			write_unlock(&ipfrag_lock);
+			write_unlock(&ip4_frags.lock);
 			qp_in->q.last_in |= COMPLETE;
 			ipq_put(qp_in, NULL);
 			return qp;
@@ -329,11 +327,11 @@ static struct ipq *ip_frag_intern(struct ipq *qp_in)
 		atomic_inc(&qp->q.refcnt);
 
 	atomic_inc(&qp->q.refcnt);
-	hlist_add_head(&qp->q.list, &ipq_hash[hash]);
+	hlist_add_head(&qp->q.list, &ip4_frags.hash[hash]);
 	INIT_LIST_HEAD(&qp->q.lru_list);
-	list_add_tail(&qp->q.lru_list, &ipq_lru_list);
-	ip_frag_nqueues++;
-	write_unlock(&ipfrag_lock);
+	list_add_tail(&qp->q.lru_list, &ip4_frags.lru_list);
+	ip4_frags.nqueues++;
+	write_unlock(&ip4_frags.lock);
 	return qp;
 }
 
@@ -384,20 +382,20 @@ static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
 	struct ipq *qp;
 	struct hlist_node *n;
 
-	read_lock(&ipfrag_lock);
+	read_lock(&ip4_frags.lock);
 	hash = ipqhashfn(id, saddr, daddr, protocol);
-	hlist_for_each_entry(qp, n, &ipq_hash[hash], q.list) {
+	hlist_for_each_entry(qp, n, &ip4_frags.hash[hash], q.list) {
 		if (qp->id == id		&&
 		    qp->saddr == saddr	&&
 		    qp->daddr == daddr	&&
 		    qp->protocol == protocol &&
 		    qp->user == user) {
 			atomic_inc(&qp->q.refcnt);
-			read_unlock(&ipfrag_lock);
+			read_unlock(&ip4_frags.lock);
 			return qp;
 		}
 	}
-	read_unlock(&ipfrag_lock);
+	read_unlock(&ip4_frags.lock);
 
 	return ip_frag_create(iph, user);
 }
@@ -583,13 +581,13 @@ static void ip_frag_queue(struct ipq *qp, struct sk_buff *skb)
 	skb->dev = NULL;
 	qp->q.stamp = skb->tstamp;
 	qp->q.meat += skb->len;
-	atomic_add(skb->truesize, &ip_frag_mem);
+	atomic_add(skb->truesize, &ip4_frags.mem);
 	if (offset == 0)
 		qp->q.last_in |= FIRST_IN;
 
-	write_lock(&ipfrag_lock);
-	list_move_tail(&qp->q.lru_list, &ipq_lru_list);
-	write_unlock(&ipfrag_lock);
+	write_lock(&ip4_frags.lock);
+	list_move_tail(&qp->q.lru_list, &ip4_frags.lru_list);
+	write_unlock(&ip4_frags.lock);
 
 	return;
 
@@ -643,12 +641,12 @@ static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev)
 		head->len -= clone->len;
 		clone->csum = 0;
 		clone->ip_summed = head->ip_summed;
-		atomic_add(clone->truesize, &ip_frag_mem);
+		atomic_add(clone->truesize, &ip4_frags.mem);
 	}
 
 	skb_shinfo(head)->frag_list = head->next;
 	skb_push(head, head->data - skb_network_header(head));
-	atomic_sub(head->truesize, &ip_frag_mem);
+	atomic_sub(head->truesize, &ip4_frags.mem);
 
 	for (fp=head->next; fp; fp = fp->next) {
 		head->data_len += fp->len;
@@ -658,7 +656,7 @@ static struct sk_buff *ip_frag_reasm(struct ipq *qp, struct net_device *dev)
 		else if (head->ip_summed == CHECKSUM_COMPLETE)
 			head->csum = csum_add(head->csum, fp->csum);
 		head->truesize += fp->truesize;
-		atomic_sub(fp->truesize, &ip_frag_mem);
+		atomic_sub(fp->truesize, &ip4_frags.mem);
 	}
 
 	head->next = NULL;
@@ -695,7 +693,7 @@ struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user)
 	IP_INC_STATS_BH(IPSTATS_MIB_REASMREQDS);
 
 	/* Start by cleaning up the memory. */
-	if (atomic_read(&ip_frag_mem) > sysctl_ipfrag_high_thresh)
+	if (atomic_read(&ip4_frags.mem) > sysctl_ipfrag_high_thresh)
 		ip_evictor();
 
 	dev = skb->dev;
@@ -724,13 +722,12 @@ struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user)
 
 void __init ipfrag_init(void)
 {
-	ipfrag_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
-				 (jiffies ^ (jiffies >> 6)));
+	init_timer(&ip4_frags.secret_timer);
+	ip4_frags.secret_timer.function = ipfrag_secret_rebuild;
+	ip4_frags.secret_timer.expires = jiffies + sysctl_ipfrag_secret_interval;
+	add_timer(&ip4_frags.secret_timer);
 
-	init_timer(&ipfrag_secret_timer);
-	ipfrag_secret_timer.function = ipfrag_secret_rebuild;
-	ipfrag_secret_timer.expires = jiffies + sysctl_ipfrag_secret_interval;
-	add_timer(&ipfrag_secret_timer);
+	inet_frags_init(&ip4_frags);
 }
 
 EXPORT_SYMBOL(ip_defrag);
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index e5b05b0..fd16cb8 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -70,8 +70,8 @@ static int sockstat_seq_show(struct seq_file *seq, void *v)
 	seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot));
 	seq_printf(seq, "UDPLITE: inuse %d\n", fold_prot_inuse(&udplite_prot));
 	seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot));
-	seq_printf(seq,  "FRAG: inuse %d memory %d\n", ip_frag_nqueues,
-		   atomic_read(&ip_frag_mem));
+	seq_printf(seq,  "FRAG: inuse %d memory %d\n",
+			ip_frag_nqueues(), ip_frag_mem());
 	return 0;
 }
 
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 52e9f6a..eb2ca1b 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -74,28 +74,20 @@ struct nf_ct_frag6_queue
 	__u16			nhoffset;
 };
 
-/* Hash table. */
-
-#define FRAG6Q_HASHSZ	64
-
-static struct hlist_head nf_ct_frag6_hash[FRAG6Q_HASHSZ];
-static DEFINE_RWLOCK(nf_ct_frag6_lock);
-static u32 nf_ct_frag6_hash_rnd;
-static LIST_HEAD(nf_ct_frag6_lru_list);
-int nf_ct_frag6_nqueues = 0;
+static struct inet_frags nf_frags;
 
 static __inline__ void __fq_unlink(struct nf_ct_frag6_queue *fq)
 {
 	hlist_del(&fq->q.list);
 	list_del(&fq->q.lru_list);
-	nf_ct_frag6_nqueues--;
+	nf_frags.nqueues--;
 }
 
 static __inline__ void fq_unlink(struct nf_ct_frag6_queue *fq)
 {
-	write_lock(&nf_ct_frag6_lock);
+	write_lock(&nf_frags.lock);
 	__fq_unlink(fq);
-	write_unlock(&nf_ct_frag6_lock);
+	write_unlock(&nf_frags.lock);
 }
 
 static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr,
@@ -109,7 +101,7 @@ static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr,
 
 	a += JHASH_GOLDEN_RATIO;
 	b += JHASH_GOLDEN_RATIO;
-	c += nf_ct_frag6_hash_rnd;
+	c += nf_frags.rnd;
 	__jhash_mix(a, b, c);
 
 	a += (__force u32)saddr->s6_addr32[3];
@@ -122,10 +114,9 @@ static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr,
 	c += (__force u32)id;
 	__jhash_mix(a, b, c);
 
-	return c & (FRAG6Q_HASHSZ - 1);
+	return c & (INETFRAGS_HASHSZ - 1);
 }
 
-static struct timer_list nf_ct_frag6_secret_timer;
 int nf_ct_frag6_secret_interval = 10 * 60 * HZ;
 
 static void nf_ct_frag6_secret_rebuild(unsigned long dummy)
@@ -133,13 +124,13 @@ static void nf_ct_frag6_secret_rebuild(unsigned long dummy)
 	unsigned long now = jiffies;
 	int i;
 
-	write_lock(&nf_ct_frag6_lock);
-	get_random_bytes(&nf_ct_frag6_hash_rnd, sizeof(u32));
-	for (i = 0; i < FRAG6Q_HASHSZ; i++) {
+	write_lock(&nf_frags.lock);
+	get_random_bytes(&nf_frags.rnd, sizeof(u32));
+	for (i = 0; i < INETFRAGS_HASHSZ; i++) {
 		struct nf_ct_frag6_queue *q;
 		struct hlist_node *p, *n;
 
-		hlist_for_each_entry_safe(q, p, n, &nf_ct_frag6_hash[i], q.list) {
+		hlist_for_each_entry_safe(q, p, n, &nf_frags.hash[i], q.list) {
 			unsigned int hval = ip6qhashfn(q->id,
 						       &q->saddr,
 						       &q->daddr);
@@ -147,23 +138,21 @@ static void nf_ct_frag6_secret_rebuild(unsigned long dummy)
 				hlist_del(&q->q.list);
 				/* Relink to new hash chain. */
 				hlist_add_head(&q->q.list,
-					       &nf_ct_frag6_hash[hval]);
+					       &nf_frags.hash[hval]);
 			}
 		}
 	}
-	write_unlock(&nf_ct_frag6_lock);
+	write_unlock(&nf_frags.lock);
 
-	mod_timer(&nf_ct_frag6_secret_timer, now + nf_ct_frag6_secret_interval);
+	mod_timer(&nf_frags.secret_timer, now + nf_ct_frag6_secret_interval);
 }
 
-atomic_t nf_ct_frag6_mem = ATOMIC_INIT(0);
-
 /* Memory Tracking Functions. */
 static inline void frag_kfree_skb(struct sk_buff *skb, unsigned int *work)
 {
 	if (work)
 		*work -= skb->truesize;
-	atomic_sub(skb->truesize, &nf_ct_frag6_mem);
+	atomic_sub(skb->truesize, &nf_frags.mem);
 	if (NFCT_FRAG6_CB(skb)->orig)
 		kfree_skb(NFCT_FRAG6_CB(skb)->orig);
 
@@ -175,7 +164,7 @@ static inline void frag_free_queue(struct nf_ct_frag6_queue *fq,
 {
 	if (work)
 		*work -= sizeof(struct nf_ct_frag6_queue);
-	atomic_sub(sizeof(struct nf_ct_frag6_queue), &nf_ct_frag6_mem);
+	atomic_sub(sizeof(struct nf_ct_frag6_queue), &nf_frags.mem);
 	kfree(fq);
 }
 
@@ -185,7 +174,7 @@ static inline struct nf_ct_frag6_queue *frag_alloc_queue(void)
 
 	if (!fq)
 		return NULL;
-	atomic_add(sizeof(struct nf_ct_frag6_queue), &nf_ct_frag6_mem);
+	atomic_add(sizeof(struct nf_ct_frag6_queue), &nf_frags.mem);
 	return fq;
 }
 
@@ -239,22 +228,22 @@ static void nf_ct_frag6_evictor(void)
 	struct list_head *tmp;
 	unsigned int work;
 
-	work = atomic_read(&nf_ct_frag6_mem);
+	work = atomic_read(&nf_frags.mem);
 	if (work <= nf_ct_frag6_low_thresh)
 		return;
 
 	work -= nf_ct_frag6_low_thresh;
 	while (work > 0) {
-		read_lock(&nf_ct_frag6_lock);
-		if (list_empty(&nf_ct_frag6_lru_list)) {
-			read_unlock(&nf_ct_frag6_lock);
+		read_lock(&nf_frags.lock);
+		if (list_empty(&nf_frags.lru_list)) {
+			read_unlock(&nf_frags.lock);
 			return;
 		}
-		tmp = nf_ct_frag6_lru_list.next;
+		tmp = nf_frags.lru_list.next;
 		BUG_ON(tmp == NULL);
 		fq = list_entry(tmp, struct nf_ct_frag6_queue, q.lru_list);
 		atomic_inc(&fq->q.refcnt);
-		read_unlock(&nf_ct_frag6_lock);
+		read_unlock(&nf_frags.lock);
 
 		spin_lock(&fq->q.lock);
 		if (!(fq->q.last_in&COMPLETE))
@@ -291,14 +280,14 @@ static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash,
 	struct hlist_node *n;
 #endif
 
-	write_lock(&nf_ct_frag6_lock);
+	write_lock(&nf_frags.lock);
 #ifdef CONFIG_SMP
-	hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], q.list) {
+	hlist_for_each_entry(fq, n, &nf_frags.hash[hash], q.list) {
 		if (fq->id == fq_in->id &&
 		    ipv6_addr_equal(&fq_in->saddr, &fq->saddr) &&
 		    ipv6_addr_equal(&fq_in->daddr, &fq->daddr)) {
 			atomic_inc(&fq->q.refcnt);
-			write_unlock(&nf_ct_frag6_lock);
+			write_unlock(&nf_frags.lock);
 			fq_in->q.last_in |= COMPLETE;
 			fq_put(fq_in, NULL);
 			return fq;
@@ -311,11 +300,11 @@ static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash,
 		atomic_inc(&fq->q.refcnt);
 
 	atomic_inc(&fq->q.refcnt);
-	hlist_add_head(&fq->q.list, &nf_ct_frag6_hash[hash]);
+	hlist_add_head(&fq->q.list, &nf_frags.hash[hash]);
 	INIT_LIST_HEAD(&fq->q.lru_list);
-	list_add_tail(&fq->q.lru_list, &nf_ct_frag6_lru_list);
-	nf_ct_frag6_nqueues++;
-	write_unlock(&nf_ct_frag6_lock);
+	list_add_tail(&fq->q.lru_list, &nf_frags.lru_list);
+	nf_frags.nqueues++;
+	write_unlock(&nf_frags.lock);
 	return fq;
 }
 
@@ -353,17 +342,17 @@ fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst)
 	struct hlist_node *n;
 	unsigned int hash = ip6qhashfn(id, src, dst);
 
-	read_lock(&nf_ct_frag6_lock);
-	hlist_for_each_entry(fq, n, &nf_ct_frag6_hash[hash], q.list) {
+	read_lock(&nf_frags.lock);
+	hlist_for_each_entry(fq, n, &nf_frags.hash[hash], q.list) {
 		if (fq->id == id &&
 		    ipv6_addr_equal(src, &fq->saddr) &&
 		    ipv6_addr_equal(dst, &fq->daddr)) {
 			atomic_inc(&fq->q.refcnt);
-			read_unlock(&nf_ct_frag6_lock);
+			read_unlock(&nf_frags.lock);
 			return fq;
 		}
 	}
-	read_unlock(&nf_ct_frag6_lock);
+	read_unlock(&nf_frags.lock);
 
 	return nf_ct_frag6_create(hash, id, src, dst);
 }
@@ -526,7 +515,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 	skb->dev = NULL;
 	fq->q.stamp = skb->tstamp;
 	fq->q.meat += skb->len;
-	atomic_add(skb->truesize, &nf_ct_frag6_mem);
+	atomic_add(skb->truesize, &nf_frags.mem);
 
 	/* The first fragment.
 	 * nhoffset is obtained from the first fragment, of course.
@@ -535,9 +524,9 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
 		fq->nhoffset = nhoff;
 		fq->q.last_in |= FIRST_IN;
 	}
-	write_lock(&nf_ct_frag6_lock);
-	list_move_tail(&fq->q.lru_list, &nf_ct_frag6_lru_list);
-	write_unlock(&nf_ct_frag6_lock);
+	write_lock(&nf_frags.lock);
+	list_move_tail(&fq->q.lru_list, &nf_frags.lru_list);
+	write_unlock(&nf_frags.lock);
 	return 0;
 
 err:
@@ -603,7 +592,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
 		clone->ip_summed = head->ip_summed;
 
 		NFCT_FRAG6_CB(clone)->orig = NULL;
-		atomic_add(clone->truesize, &nf_ct_frag6_mem);
+		atomic_add(clone->truesize, &nf_frags.mem);
 	}
 
 	/* We have to remove fragment header from datagram and to relocate
@@ -617,7 +606,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
 	skb_shinfo(head)->frag_list = head->next;
 	skb_reset_transport_header(head);
 	skb_push(head, head->data - skb_network_header(head));
-	atomic_sub(head->truesize, &nf_ct_frag6_mem);
+	atomic_sub(head->truesize, &nf_frags.mem);
 
 	for (fp=head->next; fp; fp = fp->next) {
 		head->data_len += fp->len;
@@ -627,7 +616,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
 		else if (head->ip_summed == CHECKSUM_COMPLETE)
 			head->csum = csum_add(head->csum, fp->csum);
 		head->truesize += fp->truesize;
-		atomic_sub(fp->truesize, &nf_ct_frag6_mem);
+		atomic_sub(fp->truesize, &nf_frags.mem);
 	}
 
 	head->next = NULL;
@@ -777,7 +766,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
 		goto ret_orig;
 	}
 
-	if (atomic_read(&nf_ct_frag6_mem) > nf_ct_frag6_high_thresh)
+	if (atomic_read(&nf_frags.mem) > nf_ct_frag6_high_thresh)
 		nf_ct_frag6_evictor();
 
 	fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr);
@@ -848,20 +837,21 @@ int nf_ct_frag6_kfree_frags(struct sk_buff *skb)
 
 int nf_ct_frag6_init(void)
 {
-	nf_ct_frag6_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
-				   (jiffies ^ (jiffies >> 6)));
-
-	setup_timer(&nf_ct_frag6_secret_timer, nf_ct_frag6_secret_rebuild, 0);
-	nf_ct_frag6_secret_timer.expires = jiffies
+	setup_timer(&nf_frags.secret_timer, nf_ct_frag6_secret_rebuild, 0);
+	nf_frags.secret_timer.expires = jiffies
 					   + nf_ct_frag6_secret_interval;
-	add_timer(&nf_ct_frag6_secret_timer);
+	add_timer(&nf_frags.secret_timer);
+
+	inet_frags_init(&nf_frags);
 
 	return 0;
 }
 
 void nf_ct_frag6_cleanup(void)
 {
-	del_timer(&nf_ct_frag6_secret_timer);
+	inet_frags_fini(&nf_frags);
+
+	del_timer(&nf_frags.secret_timer);
 	nf_ct_frag6_low_thresh = 0;
 	nf_ct_frag6_evictor();
 }
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index db94501..be526ad 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -54,7 +54,7 @@ static int sockstat6_seq_show(struct seq_file *seq, void *v)
 	seq_printf(seq, "RAW6: inuse %d\n",
 		       fold_prot_inuse(&rawv6_prot));
 	seq_printf(seq, "FRAG6: inuse %d memory %d\n",
-		       ip6_frag_nqueues, atomic_read(&ip6_frag_mem));
+		       ip6_frag_nqueues(), ip6_frag_mem());
 	return 0;
 }
 
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index f48ecc6..7b6315f 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -86,28 +86,30 @@ struct frag_queue
 	__u16			nhoffset;
 };
 
-/* Hash table. */
+static struct inet_frags ip6_frags;
 
-#define IP6Q_HASHSZ	64
+int ip6_frag_nqueues(void)
+{
+	return ip6_frags.nqueues;
+}
 
-static struct hlist_head ip6_frag_hash[IP6Q_HASHSZ];
-static DEFINE_RWLOCK(ip6_frag_lock);
-static u32 ip6_frag_hash_rnd;
-static LIST_HEAD(ip6_frag_lru_list);
-int ip6_frag_nqueues = 0;
+int ip6_frag_mem(void)
+{
+	return atomic_read(&ip6_frags.mem);
+}
 
 static __inline__ void __fq_unlink(struct frag_queue *fq)
 {
 	hlist_del(&fq->q.list);
 	list_del(&fq->q.lru_list);
-	ip6_frag_nqueues--;
+	ip6_frags.nqueues--;
 }
 
 static __inline__ void fq_unlink(struct frag_queue *fq)
 {
-	write_lock(&ip6_frag_lock);
+	write_lock(&ip6_frags.lock);
 	__fq_unlink(fq);
-	write_unlock(&ip6_frag_lock);
+	write_unlock(&ip6_frags.lock);
 }
 
 /*
@@ -125,7 +127,7 @@ static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr,
 
 	a += JHASH_GOLDEN_RATIO;
 	b += JHASH_GOLDEN_RATIO;
-	c += ip6_frag_hash_rnd;
+	c += ip6_frags.rnd;
 	__jhash_mix(a, b, c);
 
 	a += (__force u32)saddr->s6_addr32[3];
@@ -138,10 +140,9 @@ static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr,
 	c += (__force u32)id;
 	__jhash_mix(a, b, c);
 
-	return c & (IP6Q_HASHSZ - 1);
+	return c & (INETFRAGS_HASHSZ - 1);
 }
 
-static struct timer_list ip6_frag_secret_timer;
 int sysctl_ip6frag_secret_interval __read_mostly = 10 * 60 * HZ;
 
 static void ip6_frag_secret_rebuild(unsigned long dummy)
@@ -149,13 +150,13 @@ static void ip6_frag_secret_rebuild(unsigned long dummy)
 	unsigned long now = jiffies;
 	int i;
 
-	write_lock(&ip6_frag_lock);
-	get_random_bytes(&ip6_frag_hash_rnd, sizeof(u32));
-	for (i = 0; i < IP6Q_HASHSZ; i++) {
+	write_lock(&ip6_frags.lock);
+	get_random_bytes(&ip6_frags.rnd, sizeof(u32));
+	for (i = 0; i < INETFRAGS_HASHSZ; i++) {
 		struct frag_queue *q;
 		struct hlist_node *p, *n;
 
-		hlist_for_each_entry_safe(q, p, n, &ip6_frag_hash[i], q.list) {
+		hlist_for_each_entry_safe(q, p, n, &ip6_frags.hash[i], q.list) {
 			unsigned int hval = ip6qhashfn(q->id,
 						       &q->saddr,
 						       &q->daddr);
@@ -165,24 +166,22 @@ static void ip6_frag_secret_rebuild(unsigned long dummy)
 
 				/* Relink to new hash chain. */
 				hlist_add_head(&q->q.list,
-					       &ip6_frag_hash[hval]);
+					       &ip6_frags.hash[hval]);
 
 			}
 		}
 	}
-	write_unlock(&ip6_frag_lock);
+	write_unlock(&ip6_frags.lock);
 
-	mod_timer(&ip6_frag_secret_timer, now + sysctl_ip6frag_secret_interval);
+	mod_timer(&ip6_frags.secret_timer, now + sysctl_ip6frag_secret_interval);
 }
 
-atomic_t ip6_frag_mem = ATOMIC_INIT(0);
-
 /* Memory Tracking Functions. */
 static inline void frag_kfree_skb(struct sk_buff *skb, int *work)
 {
 	if (work)
 		*work -= skb->truesize;
-	atomic_sub(skb->truesize, &ip6_frag_mem);
+	atomic_sub(skb->truesize, &ip6_frags.mem);
 	kfree_skb(skb);
 }
 
@@ -190,7 +189,7 @@ static inline void frag_free_queue(struct frag_queue *fq, int *work)
 {
 	if (work)
 		*work -= sizeof(struct frag_queue);
-	atomic_sub(sizeof(struct frag_queue), &ip6_frag_mem);
+	atomic_sub(sizeof(struct frag_queue), &ip6_frags.mem);
 	kfree(fq);
 }
 
@@ -200,7 +199,7 @@ static inline struct frag_queue *frag_alloc_queue(void)
 
 	if(!fq)
 		return NULL;
-	atomic_add(sizeof(struct frag_queue), &ip6_frag_mem);
+	atomic_add(sizeof(struct frag_queue), &ip6_frags.mem);
 	return fq;
 }
 
@@ -253,20 +252,20 @@ static void ip6_evictor(struct inet6_dev *idev)
 	struct list_head *tmp;
 	int work;
 
-	work = atomic_read(&ip6_frag_mem) - sysctl_ip6frag_low_thresh;
+	work = atomic_read(&ip6_frags.mem) - sysctl_ip6frag_low_thresh;
 	if (work <= 0)
 		return;
 
 	while(work > 0) {
-		read_lock(&ip6_frag_lock);
-		if (list_empty(&ip6_frag_lru_list)) {
-			read_unlock(&ip6_frag_lock);
+		read_lock(&ip6_frags.lock);
+		if (list_empty(&ip6_frags.lru_list)) {
+			read_unlock(&ip6_frags.lock);
 			return;
 		}
-		tmp = ip6_frag_lru_list.next;
+		tmp = ip6_frags.lru_list.next;
 		fq = list_entry(tmp, struct frag_queue, q.lru_list);
 		atomic_inc(&fq->q.refcnt);
-		read_unlock(&ip6_frag_lock);
+		read_unlock(&ip6_frags.lock);
 
 		spin_lock(&fq->q.lock);
 		if (!(fq->q.last_in&COMPLETE))
@@ -328,15 +327,15 @@ static struct frag_queue *ip6_frag_intern(struct frag_queue *fq_in)
 	struct hlist_node *n;
 #endif
 
-	write_lock(&ip6_frag_lock);
+	write_lock(&ip6_frags.lock);
 	hash = ip6qhashfn(fq_in->id, &fq_in->saddr, &fq_in->daddr);
 #ifdef CONFIG_SMP
-	hlist_for_each_entry(fq, n, &ip6_frag_hash[hash], q.list) {
+	hlist_for_each_entry(fq, n, &ip6_frags.hash[hash], q.list) {
 		if (fq->id == fq_in->id &&
 		    ipv6_addr_equal(&fq_in->saddr, &fq->saddr) &&
 		    ipv6_addr_equal(&fq_in->daddr, &fq->daddr)) {
 			atomic_inc(&fq->q.refcnt);
-			write_unlock(&ip6_frag_lock);
+			write_unlock(&ip6_frags.lock);
 			fq_in->q.last_in |= COMPLETE;
 			fq_put(fq_in, NULL);
 			return fq;
@@ -349,11 +348,11 @@ static struct frag_queue *ip6_frag_intern(struct frag_queue *fq_in)
 		atomic_inc(&fq->q.refcnt);
 
 	atomic_inc(&fq->q.refcnt);
-	hlist_add_head(&fq->q.list, &ip6_frag_hash[hash]);
+	hlist_add_head(&fq->q.list, &ip6_frags.hash[hash]);
 	INIT_LIST_HEAD(&fq->q.lru_list);
-	list_add_tail(&fq->q.lru_list, &ip6_frag_lru_list);
-	ip6_frag_nqueues++;
-	write_unlock(&ip6_frag_lock);
+	list_add_tail(&fq->q.lru_list, &ip6_frags.lru_list);
+	ip6_frags.nqueues++;
+	write_unlock(&ip6_frags.lock);
 	return fq;
 }
 
@@ -392,18 +391,18 @@ fq_find(__be32 id, struct in6_addr *src, struct in6_addr *dst,
 	struct hlist_node *n;
 	unsigned int hash;
 
-	read_lock(&ip6_frag_lock);
+	read_lock(&ip6_frags.lock);
 	hash = ip6qhashfn(id, src, dst);
-	hlist_for_each_entry(fq, n, &ip6_frag_hash[hash], q.list) {
+	hlist_for_each_entry(fq, n, &ip6_frags.hash[hash], q.list) {
 		if (fq->id == id &&
 		    ipv6_addr_equal(src, &fq->saddr) &&
 		    ipv6_addr_equal(dst, &fq->daddr)) {
 			atomic_inc(&fq->q.refcnt);
-			read_unlock(&ip6_frag_lock);
+			read_unlock(&ip6_frags.lock);
 			return fq;
 		}
 	}
-	read_unlock(&ip6_frag_lock);
+	read_unlock(&ip6_frags.lock);
 
 	return ip6_frag_create(id, src, dst, idev);
 }
@@ -558,7 +557,7 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
 	skb->dev = NULL;
 	fq->q.stamp = skb->tstamp;
 	fq->q.meat += skb->len;
-	atomic_add(skb->truesize, &ip6_frag_mem);
+	atomic_add(skb->truesize, &ip6_frags.mem);
 
 	/* The first fragment.
 	 * nhoffset is obtained from the first fragment, of course.
@@ -567,9 +566,9 @@ static void ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb,
 		fq->nhoffset = nhoff;
 		fq->q.last_in |= FIRST_IN;
 	}
-	write_lock(&ip6_frag_lock);
-	list_move_tail(&fq->q.lru_list, &ip6_frag_lru_list);
-	write_unlock(&ip6_frag_lock);
+	write_lock(&ip6_frags.lock);
+	list_move_tail(&fq->q.lru_list, &ip6_frags.lru_list);
+	write_unlock(&ip6_frags.lock);
 	return;
 
 err:
@@ -629,7 +628,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
 		head->len -= clone->len;
 		clone->csum = 0;
 		clone->ip_summed = head->ip_summed;
-		atomic_add(clone->truesize, &ip6_frag_mem);
+		atomic_add(clone->truesize, &ip6_frags.mem);
 	}
 
 	/* We have to remove fragment header from datagram and to relocate
@@ -644,7 +643,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
 	skb_shinfo(head)->frag_list = head->next;
 	skb_reset_transport_header(head);
 	skb_push(head, head->data - skb_network_header(head));
-	atomic_sub(head->truesize, &ip6_frag_mem);
+	atomic_sub(head->truesize, &ip6_frags.mem);
 
 	for (fp=head->next; fp; fp = fp->next) {
 		head->data_len += fp->len;
@@ -654,7 +653,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
 		else if (head->ip_summed == CHECKSUM_COMPLETE)
 			head->csum = csum_add(head->csum, fp->csum);
 		head->truesize += fp->truesize;
-		atomic_sub(fp->truesize, &ip6_frag_mem);
+		atomic_sub(fp->truesize, &ip6_frags.mem);
 	}
 
 	head->next = NULL;
@@ -728,7 +727,7 @@ static int ipv6_frag_rcv(struct sk_buff **skbp)
 		return 1;
 	}
 
-	if (atomic_read(&ip6_frag_mem) > sysctl_ip6frag_high_thresh)
+	if (atomic_read(&ip6_frags.mem) > sysctl_ip6frag_high_thresh)
 		ip6_evictor(ip6_dst_idev(skb->dst));
 
 	if ((fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr,
@@ -764,11 +763,10 @@ void __init ipv6_frag_init(void)
 	if (inet6_add_protocol(&frag_protocol, IPPROTO_FRAGMENT) < 0)
 		printk(KERN_ERR "ipv6_frag_init: Could not register protocol\n");
 
-	ip6_frag_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^
-				   (jiffies ^ (jiffies >> 6)));
+	init_timer(&ip6_frags.secret_timer);
+	ip6_frags.secret_timer.function = ip6_frag_secret_rebuild;
+	ip6_frags.secret_timer.expires = jiffies + sysctl_ip6frag_secret_interval;
+	add_timer(&ip6_frags.secret_timer);
 
-	init_timer(&ip6_frag_secret_timer);
-	ip6_frag_secret_timer.function = ip6_frag_secret_rebuild;
-	ip6_frag_secret_timer.expires = jiffies + sysctl_ip6frag_secret_interval;
-	add_timer(&ip6_frag_secret_timer);
+	inet_frags_init(&ip6_frags);
 }
-- 
1.5.3.4


^ permalink raw reply related

* [PATCH 3/9] Collect common sysctl variables together
From: Pavel Emelyanov @ 2007-10-12 13:10 UTC (permalink / raw)
  To: David Miller; +Cc: Patrick McHardy, Linux Netdev List, devel
In-Reply-To: <470F6EAE.60308@openvz.org>

Some sysctl variables are used to tune the frag queues
management and it will be useful to work with them in
a common way in the future, so move them into one
structure, moreover they are the same for all the frag
management codes.

I don't place them in the existing inet_frags object,
introduced in the previous patch for two reasons:

 1. to keep them in the __read_mostly section;
 2. not to export the whole inet_frags objects outside.

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>

---

diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index d51f238..ada03ba 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -20,6 +20,13 @@ struct inet_frag_queue {
 
 #define INETFRAGS_HASHSZ		64
 
+struct inet_frags_ctl {
+	int high_thresh;
+	int low_thresh;
+	int timeout;
+	int secret_interval;
+};
+
 struct inet_frags {
 	struct list_head	lru_list;
 	struct hlist_head	hash[INETFRAGS_HASHSZ];
@@ -28,6 +35,7 @@ struct inet_frags {
 	int			nqueues;
 	atomic_t		mem;
 	struct timer_list	secret_timer;
+	struct inet_frags_ctl	*ctl;
 };
 
 void inet_frags_init(struct inet_frags *);
diff --git a/include/net/ip.h b/include/net/ip.h
index a18dcec..e7b0feb 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -177,10 +177,8 @@ extern int sysctl_ip_default_ttl;
 extern int sysctl_ip_nonlocal_bind;
 
 /* From ip_fragment.c */
-extern int sysctl_ipfrag_high_thresh; 
-extern int sysctl_ipfrag_low_thresh;
-extern int sysctl_ipfrag_time;
-extern int sysctl_ipfrag_secret_interval;
+struct inet_frags_ctl;
+extern struct inet_frags_ctl ip4_frags_ctl;
 extern int sysctl_ipfrag_max_dist;
 
 /* From inetpeer.c */
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 77cdab3..b29d76c 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -565,10 +565,8 @@ extern int inet6_hash_connect(struct inet_timewait_death_row *death_row,
 /*
  * reassembly.c
  */
-extern int sysctl_ip6frag_high_thresh;
-extern int sysctl_ip6frag_low_thresh;
-extern int sysctl_ip6frag_time;
-extern int sysctl_ip6frag_secret_interval;
+struct inet_frags_ctl;
+extern struct inet_frags_ctl ip6_frags_ctl;
 
 extern const struct proto_ops inet6_stream_ops;
 extern const struct proto_ops inet6_dgram_ops;
diff --git a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
index 070d12c..f703533 100644
--- a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
+++ b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
@@ -15,8 +15,7 @@ extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
 			       struct net_device *out,
 			       int (*okfn)(struct sk_buff *));
 
-extern unsigned int nf_ct_frag6_timeout;
-extern unsigned int nf_ct_frag6_low_thresh;
-extern unsigned int nf_ct_frag6_high_thresh;
+struct inet_frags_ctl;
+extern struct inet_frags_ctl nf_frags_ctl;
 
 #endif /* _NF_CONNTRACK_IPV6_H*/
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 5e1667e..61035a8 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -50,21 +50,8 @@
  * as well. Or notify me, at least. --ANK
  */
 
-/* Fragment cache limits. We will commit 256K at one time. Should we
- * cross that limit we will prune down to 192K. This should cope with
- * even the most extreme cases without allowing an attacker to measurably
- * harm machine performance.
- */
-int sysctl_ipfrag_high_thresh __read_mostly = 256*1024;
-int sysctl_ipfrag_low_thresh __read_mostly = 192*1024;
-
 int sysctl_ipfrag_max_dist __read_mostly = 64;
 
-/* Important NOTE! Fragment queue must be destroyed before MSL expires.
- * RFC791 is wrong proposing to prolongate timer each fragment arrival by TTL.
- */
-int sysctl_ipfrag_time __read_mostly = IP_FRAG_TIME;
-
 struct ipfrag_skb_cb
 {
 	struct inet_skb_parm	h;
@@ -87,6 +74,25 @@ struct ipq {
 	struct inet_peer *peer;
 };
 
+struct inet_frags_ctl ip4_frags_ctl __read_mostly = {
+	/*
+	 * Fragment cache limits. We will commit 256K at one time. Should we
+	 * cross that limit we will prune down to 192K. This should cope with
+	 * even the most extreme cases without allowing an attacker to
+	 * measurably harm machine performance.
+	 */
+	.high_thresh	 = 256 * 1024,
+	.low_thresh	 = 192 * 1024,
+
+	/*
+	 * Important NOTE! Fragment queue must be destroyed before MSL expires.
+	 * RFC791 is wrong proposing to prolongate timer each fragment arrival
+	 * by TTL.
+	 */
+	.timeout	 = IP_FRAG_TIME,
+	.secret_interval = 10 * 60 * HZ,
+};
+
 static struct inet_frags ip4_frags;
 
 int ip_frag_nqueues(void)
@@ -120,8 +126,6 @@ static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot)
 			    ip4_frags.rnd) & (INETFRAGS_HASHSZ - 1);
 }
 
-int sysctl_ipfrag_secret_interval __read_mostly = 10 * 60 * HZ;
-
 static void ipfrag_secret_rebuild(unsigned long dummy)
 {
 	unsigned long now = jiffies;
@@ -147,7 +151,7 @@ static void ipfrag_secret_rebuild(unsigned long dummy)
 	}
 	write_unlock(&ip4_frags.lock);
 
-	mod_timer(&ip4_frags.secret_timer, now + sysctl_ipfrag_secret_interval);
+	mod_timer(&ip4_frags.secret_timer, now + ip4_frags_ctl.secret_interval);
 }
 
 /* Memory Tracking Functions. */
@@ -234,7 +238,7 @@ static void ip_evictor(void)
 	struct list_head *tmp;
 	int work;
 
-	work = atomic_read(&ip4_frags.mem) - sysctl_ipfrag_low_thresh;
+	work = atomic_read(&ip4_frags.mem) - ip4_frags_ctl.low_thresh;
 	if (work <= 0)
 		return;
 
@@ -323,7 +327,7 @@ static struct ipq *ip_frag_intern(struct ipq *qp_in)
 #endif
 	qp = qp_in;
 
-	if (!mod_timer(&qp->q.timer, jiffies + sysctl_ipfrag_time))
+	if (!mod_timer(&qp->q.timer, jiffies + ip4_frags_ctl.timeout))
 		atomic_inc(&qp->q.refcnt);
 
 	atomic_inc(&qp->q.refcnt);
@@ -429,7 +433,7 @@ static int ip_frag_reinit(struct ipq *qp)
 {
 	struct sk_buff *fp;
 
-	if (!mod_timer(&qp->q.timer, jiffies + sysctl_ipfrag_time)) {
+	if (!mod_timer(&qp->q.timer, jiffies + ip4_frags_ctl.timeout)) {
 		atomic_inc(&qp->q.refcnt);
 		return -ETIMEDOUT;
 	}
@@ -693,7 +697,7 @@ struct sk_buff *ip_defrag(struct sk_buff *skb, u32 user)
 	IP_INC_STATS_BH(IPSTATS_MIB_REASMREQDS);
 
 	/* Start by cleaning up the memory. */
-	if (atomic_read(&ip4_frags.mem) > sysctl_ipfrag_high_thresh)
+	if (atomic_read(&ip4_frags.mem) > ip4_frags_ctl.high_thresh)
 		ip_evictor();
 
 	dev = skb->dev;
@@ -724,9 +728,10 @@ void __init ipfrag_init(void)
 {
 	init_timer(&ip4_frags.secret_timer);
 	ip4_frags.secret_timer.function = ipfrag_secret_rebuild;
-	ip4_frags.secret_timer.expires = jiffies + sysctl_ipfrag_secret_interval;
+	ip4_frags.secret_timer.expires = jiffies + ip4_frags_ctl.secret_interval;
 	add_timer(&ip4_frags.secret_timer);
 
+	ip4_frags.ctl = &ip4_frags_ctl;
 	inet_frags_init(&ip4_frags);
 }
 
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index eb286ab..c98ef16 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -19,6 +19,7 @@
 #include <net/route.h>
 #include <net/tcp.h>
 #include <net/cipso_ipv4.h>
+#include <net/inet_frag.h>
 
 /* From af_inet.c */
 extern int sysctl_ip_nonlocal_bind;
@@ -357,7 +358,7 @@ ctl_table ipv4_table[] = {
 	{
 		.ctl_name	= NET_IPV4_IPFRAG_HIGH_THRESH,
 		.procname	= "ipfrag_high_thresh",
-		.data		= &sysctl_ipfrag_high_thresh,
+		.data		= &ip4_frags_ctl.high_thresh,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec
@@ -365,7 +366,7 @@ ctl_table ipv4_table[] = {
 	{
 		.ctl_name	= NET_IPV4_IPFRAG_LOW_THRESH,
 		.procname	= "ipfrag_low_thresh",
-		.data		= &sysctl_ipfrag_low_thresh,
+		.data		= &ip4_frags_ctl.low_thresh,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec
@@ -381,7 +382,7 @@ ctl_table ipv4_table[] = {
 	{
 		.ctl_name	= NET_IPV4_IPFRAG_TIME,
 		.procname	= "ipfrag_time",
-		.data		= &sysctl_ipfrag_time,
+		.data		= &ip4_frags_ctl.timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec_jiffies,
@@ -732,7 +733,7 @@ ctl_table ipv4_table[] = {
 	{
 		.ctl_name	= NET_IPV4_IPFRAG_SECRET_INTERVAL,
 		.procname	= "ipfrag_secret_interval",
-		.data		= &sysctl_ipfrag_secret_interval,
+		.data		= &ip4_frags_ctl.secret_interval,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec_jiffies,
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 37a3db9..572c0bc 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -18,6 +18,7 @@
 #include <linux/icmp.h>
 #include <linux/sysctl.h>
 #include <net/ipv6.h>
+#include <net/inet_frag.h>
 
 #include <linux/netfilter_ipv6.h>
 #include <net/netfilter/nf_conntrack.h>
@@ -307,7 +308,7 @@ static ctl_table nf_ct_ipv6_sysctl_table[] = {
 	{
 		.ctl_name	= NET_NF_CONNTRACK_FRAG6_TIMEOUT,
 		.procname	= "nf_conntrack_frag6_timeout",
-		.data		= &nf_ct_frag6_timeout,
+		.data		= &nf_frags_ctl.timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec_jiffies,
@@ -315,7 +316,7 @@ static ctl_table nf_ct_ipv6_sysctl_table[] = {
 	{
 		.ctl_name	= NET_NF_CONNTRACK_FRAG6_LOW_THRESH,
 		.procname	= "nf_conntrack_frag6_low_thresh",
-		.data		= &nf_ct_frag6_low_thresh,
+		.data		= &nf_frags_ctl.low_thresh,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec,
@@ -323,7 +324,7 @@ static ctl_table nf_ct_ipv6_sysctl_table[] = {
 	{
 		.ctl_name	= NET_NF_CONNTRACK_FRAG6_HIGH_THRESH,
 		.procname	= "nf_conntrack_frag6_high_thresh",
-		.data		= &nf_ct_frag6_high_thresh,
+		.data		= &nf_frags_ctl.high_thresh,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec,
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index eb2ca1b..966a888 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -49,10 +49,6 @@
 #define NF_CT_FRAG6_LOW_THRESH 196608  /* == 192*1024 */
 #define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT
 
-unsigned int nf_ct_frag6_high_thresh __read_mostly = 256*1024;
-unsigned int nf_ct_frag6_low_thresh __read_mostly = 192*1024;
-unsigned long nf_ct_frag6_timeout __read_mostly = IPV6_FRAG_TIMEOUT;
-
 struct nf_ct_frag6_skb_cb
 {
 	struct inet6_skb_parm	h;
@@ -74,6 +70,13 @@ struct nf_ct_frag6_queue
 	__u16			nhoffset;
 };
 
+struct inet_frags_ctl nf_frags_ctl __read_mostly = {
+	.high_thresh	 = 256 * 1024,
+	.low_thresh	 = 192 * 1024,
+	.timeout	 = IPV6_FRAG_TIMEOUT,
+	.secret_interval = 10 * 60 * HZ,
+};
+
 static struct inet_frags nf_frags;
 
 static __inline__ void __fq_unlink(struct nf_ct_frag6_queue *fq)
@@ -117,8 +120,6 @@ static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr,
 	return c & (INETFRAGS_HASHSZ - 1);
 }
 
-int nf_ct_frag6_secret_interval = 10 * 60 * HZ;
-
 static void nf_ct_frag6_secret_rebuild(unsigned long dummy)
 {
 	unsigned long now = jiffies;
@@ -144,7 +145,7 @@ static void nf_ct_frag6_secret_rebuild(unsigned long dummy)
 	}
 	write_unlock(&nf_frags.lock);
 
-	mod_timer(&nf_frags.secret_timer, now + nf_ct_frag6_secret_interval);
+	mod_timer(&nf_frags.secret_timer, now + nf_frags_ctl.secret_interval);
 }
 
 /* Memory Tracking Functions. */
@@ -229,10 +230,10 @@ static void nf_ct_frag6_evictor(void)
 	unsigned int work;
 
 	work = atomic_read(&nf_frags.mem);
-	if (work <= nf_ct_frag6_low_thresh)
+	if (work <= nf_frags_ctl.low_thresh)
 		return;
 
-	work -= nf_ct_frag6_low_thresh;
+	work -= nf_frags_ctl.low_thresh;
 	while (work > 0) {
 		read_lock(&nf_frags.lock);
 		if (list_empty(&nf_frags.lru_list)) {
@@ -296,7 +297,7 @@ static struct nf_ct_frag6_queue *nf_ct_frag6_intern(unsigned int hash,
 #endif
 	fq = fq_in;
 
-	if (!mod_timer(&fq->q.timer, jiffies + nf_ct_frag6_timeout))
+	if (!mod_timer(&fq->q.timer, jiffies + nf_frags_ctl.timeout))
 		atomic_inc(&fq->q.refcnt);
 
 	atomic_inc(&fq->q.refcnt);
@@ -766,7 +767,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
 		goto ret_orig;
 	}
 
-	if (atomic_read(&nf_frags.mem) > nf_ct_frag6_high_thresh)
+	if (atomic_read(&nf_frags.mem) > nf_frags_ctl.high_thresh)
 		nf_ct_frag6_evictor();
 
 	fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr);
@@ -838,10 +839,10 @@ int nf_ct_frag6_kfree_frags(struct sk_buff *skb)
 int nf_ct_frag6_init(void)
 {
 	setup_timer(&nf_frags.secret_timer, nf_ct_frag6_secret_rebuild, 0);
-	nf_frags.secret_timer.expires = jiffies
-					   + nf_ct_frag6_secret_interval;
+	nf_frags.secret_timer.expires = jiffies + nf_frags_ctl.secret_interval;
 	add_timer(&nf_frags.secret_timer);
 
+	nf_frags.ctl = &nf_frags_ctl;
 	inet_frags_init(&nf_frags);
 
 	return 0;
@@ -852,6 +853,6 @@ void nf_ct_frag6_cleanup(void)
 	inet_frags_fini(&nf_frags);
 
 	del_timer(&nf_frags.secret_timer);
-	nf_ct_frag6_low_thresh = 0;
+	nf_frags_ctl.low_thresh = 0;
 	nf_ct_frag6_evictor();
 }
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 7b6315f..f0e22be 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -55,11 +55,6 @@
 #include <net/addrconf.h>
 #include <net/inet_frag.h>
 
-int sysctl_ip6frag_high_thresh __read_mostly = 256*1024;
-int sysctl_ip6frag_low_thresh __read_mostly = 192*1024;
-
-int sysctl_ip6frag_time __read_mostly = IPV6_FRAG_TIMEOUT;
-
 struct ip6frag_skb_cb
 {
 	struct inet6_skb_parm	h;
@@ -86,6 +81,13 @@ struct frag_queue
 	__u16			nhoffset;
 };
 
+struct inet_frags_ctl ip6_frags_ctl __read_mostly = {
+	.high_thresh 	 = 256 * 1024,
+	.low_thresh	 = 192 * 1024,
+	.timeout	 = IPV6_FRAG_TIMEOUT,
+	.secret_interval = 10 * 60 * HZ,
+};
+
 static struct inet_frags ip6_frags;
 
 int ip6_frag_nqueues(void)
@@ -143,8 +145,6 @@ static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr,
 	return c & (INETFRAGS_HASHSZ - 1);
 }
 
-int sysctl_ip6frag_secret_interval __read_mostly = 10 * 60 * HZ;
-
 static void ip6_frag_secret_rebuild(unsigned long dummy)
 {
 	unsigned long now = jiffies;
@@ -173,7 +173,7 @@ static void ip6_frag_secret_rebuild(unsigned long dummy)
 	}
 	write_unlock(&ip6_frags.lock);
 
-	mod_timer(&ip6_frags.secret_timer, now + sysctl_ip6frag_secret_interval);
+	mod_timer(&ip6_frags.secret_timer, now + ip6_frags_ctl.secret_interval);
 }
 
 /* Memory Tracking Functions. */
@@ -252,7 +252,7 @@ static void ip6_evictor(struct inet6_dev *idev)
 	struct list_head *tmp;
 	int work;
 
-	work = atomic_read(&ip6_frags.mem) - sysctl_ip6frag_low_thresh;
+	work = atomic_read(&ip6_frags.mem) - ip6_frags_ctl.low_thresh;
 	if (work <= 0)
 		return;
 
@@ -344,7 +344,7 @@ static struct frag_queue *ip6_frag_intern(struct frag_queue *fq_in)
 #endif
 	fq = fq_in;
 
-	if (!mod_timer(&fq->q.timer, jiffies + sysctl_ip6frag_time))
+	if (!mod_timer(&fq->q.timer, jiffies + ip6_frags_ctl.timeout))
 		atomic_inc(&fq->q.refcnt);
 
 	atomic_inc(&fq->q.refcnt);
@@ -727,7 +727,7 @@ static int ipv6_frag_rcv(struct sk_buff **skbp)
 		return 1;
 	}
 
-	if (atomic_read(&ip6_frags.mem) > sysctl_ip6frag_high_thresh)
+	if (atomic_read(&ip6_frags.mem) > ip6_frags_ctl.high_thresh)
 		ip6_evictor(ip6_dst_idev(skb->dst));
 
 	if ((fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr,
@@ -765,8 +765,9 @@ void __init ipv6_frag_init(void)
 
 	init_timer(&ip6_frags.secret_timer);
 	ip6_frags.secret_timer.function = ip6_frag_secret_rebuild;
-	ip6_frags.secret_timer.expires = jiffies + sysctl_ip6frag_secret_interval;
+	ip6_frags.secret_timer.expires = jiffies + ip6_frags_ctl.secret_interval;
 	add_timer(&ip6_frags.secret_timer);
 
+	ip6_frags.ctl = &ip6_frags_ctl;
 	inet_frags_init(&ip6_frags);
 }
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index 3fb4427..97c425f 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -12,6 +12,7 @@
 #include <net/ndisc.h>
 #include <net/ipv6.h>
 #include <net/addrconf.h>
+#include <net/inet_frag.h>
 
 #ifdef CONFIG_SYSCTL
 
@@ -41,7 +42,7 @@ static ctl_table ipv6_table[] = {
 	{
 		.ctl_name	= NET_IPV6_IP6FRAG_HIGH_THRESH,
 		.procname	= "ip6frag_high_thresh",
-		.data		= &sysctl_ip6frag_high_thresh,
+		.data		= &ip6_frags_ctl.high_thresh,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec
@@ -49,7 +50,7 @@ static ctl_table ipv6_table[] = {
 	{
 		.ctl_name	= NET_IPV6_IP6FRAG_LOW_THRESH,
 		.procname	= "ip6frag_low_thresh",
-		.data		= &sysctl_ip6frag_low_thresh,
+		.data		= &ip6_frags_ctl.low_thresh,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec
@@ -57,7 +58,7 @@ static ctl_table ipv6_table[] = {
 	{
 		.ctl_name	= NET_IPV6_IP6FRAG_TIME,
 		.procname	= "ip6frag_time",
-		.data		= &sysctl_ip6frag_time,
+		.data		= &ip6_frags_ctl.timeout,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec_jiffies,
@@ -66,7 +67,7 @@ static ctl_table ipv6_table[] = {
 	{
 		.ctl_name	= NET_IPV6_IP6FRAG_SECRET_INTERVAL,
 		.procname	= "ip6frag_secret_interval",
-		.data		= &sysctl_ip6frag_secret_interval,
+		.data		= &ip6_frags_ctl.secret_interval,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
 		.proc_handler	= &proc_dointvec_jiffies,
-- 
1.5.3.4


^ permalink raw reply related


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