Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net-next] net: cleanups in sock_setsockopt()
From: Eric Dumazet @ 2012-04-27  6:02 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20120427.014848.764959411706970704.davem@davemloft.net>

On Fri, 2012-04-27 at 01:48 -0400, David Miller wrote:
> From: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Fri, 27 Apr 2012 07:41:59 +0200
> 
> > From: Eric Dumazet <edumazet@google.com>
> > 
> > Use min()/max() macros, reformat two comments, use !!test_bit() to
> > match !!sock_flag()
> > 
> > Signed-off-by: Eric Dumazet <edumazet@google.com>
> 
> Introduces warnings:
> 
> net/core/sock.c: In function ‘sock_setsockopt’:
> net/core/sock.c:584:9: warning: comparison of distinct pointer types lacks a cast [enabled by default]
> net/core/sock.c:605:9: warning: comparison of distinct pointer types lacks a cast [enabled by default]
> net/core/sock.c:623:19: warning: comparison of distinct pointer types lacks a cast [enabled by default]
> 
> and that makes sense since int is signed and __u32 is not.
> 
> Your compiler didn't spit that out too?

Hmm... I wonder how I missed these...

I'll fix this, thanks

^ permalink raw reply

* [PATCH v2 net-next] net: cleanups in sock_setsockopt()
From: Eric Dumazet @ 2012-04-27  6:07 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

From: Eric Dumazet <edumazet@google.com>

Use min_t()/max_t() macros, reformat two comments, use !!test_bit() to
match !!sock_flag()

Signed-off-by: Eric Dumazet <edumazet@google.com>
---
 net/core/sock.c |   42 +++++++++++++++---------------------------
 1 file changed, 15 insertions(+), 27 deletions(-)

diff --git a/net/core/sock.c b/net/core/sock.c
index 0431aaf..10605d2 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -577,23 +577,15 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
 		break;
 	case SO_SNDBUF:
 		/* Don't error on this BSD doesn't and if you think
-		   about it this is right. Otherwise apps have to
-		   play 'guess the biggest size' games. RCVBUF/SNDBUF
-		   are treated in BSD as hints */
-
-		if (val > sysctl_wmem_max)
-			val = sysctl_wmem_max;
+		 * about it this is right. Otherwise apps have to
+		 * play 'guess the biggest size' games. RCVBUF/SNDBUF
+		 * are treated in BSD as hints
+		 */
+		val = min_t(u32, val, sysctl_wmem_max);
 set_sndbuf:
 		sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
-		if ((val * 2) < SOCK_MIN_SNDBUF)
-			sk->sk_sndbuf = SOCK_MIN_SNDBUF;
-		else
-			sk->sk_sndbuf = val * 2;
-
-		/*
-		 *	Wake up sending tasks if we
-		 *	upped the value.
-		 */
+		sk->sk_sndbuf = max_t(u32, val * 2, SOCK_MIN_SNDBUF);
+		/* Wake up sending tasks if we upped the value. */
 		sk->sk_write_space(sk);
 		break;
 
@@ -606,12 +598,11 @@ set_sndbuf:
 
 	case SO_RCVBUF:
 		/* Don't error on this BSD doesn't and if you think
-		   about it this is right. Otherwise apps have to
-		   play 'guess the biggest size' games. RCVBUF/SNDBUF
-		   are treated in BSD as hints */
-
-		if (val > sysctl_rmem_max)
-			val = sysctl_rmem_max;
+		 * about it this is right. Otherwise apps have to
+		 * play 'guess the biggest size' games. RCVBUF/SNDBUF
+		 * are treated in BSD as hints
+		 */
+		val = min_t(u32, val, sysctl_rmem_max);
 set_rcvbuf:
 		sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
 		/*
@@ -629,10 +620,7 @@ set_rcvbuf:
 		 * returning the value we actually used in getsockopt
 		 * is the most desirable behavior.
 		 */
-		if ((val * 2) < SOCK_MIN_RCVBUF)
-			sk->sk_rcvbuf = SOCK_MIN_RCVBUF;
-		else
-			sk->sk_rcvbuf = val * 2;
+		sk->sk_rcvbuf = max_t(u32, val * 2, SOCK_MIN_RCVBUF);
 		break;
 
 	case SO_RCVBUFFORCE:
@@ -975,7 +963,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
 		break;
 
 	case SO_PASSCRED:
-		v.val = test_bit(SOCK_PASSCRED, &sock->flags) ? 1 : 0;
+		v.val = !!test_bit(SOCK_PASSCRED, &sock->flags);
 		break;
 
 	case SO_PEERCRED:
@@ -1010,7 +998,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
 		break;
 
 	case SO_PASSSEC:
-		v.val = test_bit(SOCK_PASSSEC, &sock->flags) ? 1 : 0;
+		v.val = !!test_bit(SOCK_PASSSEC, &sock->flags);
 		break;
 
 	case SO_PEERSEC:

^ permalink raw reply related

* Re: [PATCH v2 net-next] net: cleanups in sock_setsockopt()
From: David Miller @ 2012-04-27  6:14 UTC (permalink / raw)
  To: eric.dumazet; +Cc: netdev
In-Reply-To: <1335506879.2775.77.camel@edumazet-glaptop>

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Fri, 27 Apr 2012 08:07:59 +0200

> From: Eric Dumazet <edumazet@google.com>
> 
> Use min_t()/max_t() macros, reformat two comments, use !!test_bit() to
> match !!sock_flag()
> 
> Signed-off-by: Eric Dumazet <edumazet@google.com>

Much better, applied.

^ permalink raw reply

* RE: [PATCH net-next 3/5] be2net: Fix to apply duplex value as unknown when link is down.
From: Somnath.Kotur @ 2012-04-27  6:42 UTC (permalink / raw)
  To: bhutchings; +Cc: netdev
In-Reply-To: <1335461076.2712.20.camel@bwh-desktop.uk.solarflarecom.com>

 > I don't see any problem with reporting full-duplex all the time if you don't
> support any half-duplex link modes.  But we don't yet have consistency
> between drivers in speed/duplex reporting while the link is down, so I won't
> insist that that is the right thing to do.
> 
> However you should use DUPLEX_UNKNOWN rather than -1.
> 
> Ben.

Yes, Agreed. Thank you for your review/suggestion.

Will make the change and re-post.

-Som.

> --
> Ben Hutchings, Staff Engineer, Solarflare Not speaking for my employer;
> that's the marketing department's job.
> They asked us to note that Solarflare product names are trademarked.


^ permalink raw reply

* RE: [PATCH net-next 2/5] be2net: Fix to allow setting of debug levels in the firmware.
From: Somnath.Kotur @ 2012-04-27  6:46 UTC (permalink / raw)
  To: bhutchings; +Cc: netdev
In-Reply-To: <1335461388.2712.25.camel@bwh-desktop.uk.solarflarecom.com>

> > This operation is intended for controlling logging by the driver, and the flags
> are defined in <linux/netdevice.h>.  (Not exported to userland yet, but
> ethtool knows their names.)
> 
> If your firmware supports some kind of logging then it may be reasonable to
> have this control both driver and firmware, but not *just* the firmware.
Thanks for your comments Ben.

Currently the driver logs only a very few critical errors/warnings; so we felt it might be an overkill to 
define driver log levels.
On the other hand, the F/W has extensive logging and tracing facility and the ethtool 'msglevel' option seemed 
like a reasonable method for controlling the logging level.

> 
> You should also implement the get_msglevel operation at the same time.

Yes you are correct. We will implement the get_msglevel and re-post the patch.
> 
> Ben.
> 

Thanks
Som

^ permalink raw reply

* [PATCH net-next 1/2] drivers/net/oki-semi: Remove the definition of PCH_GBE_ETH_ALEN
From: roy.qing.li @ 2012-04-27  7:01 UTC (permalink / raw)
  To: netdev

From: RongQing.Li <roy.qing.li@gmail.com>

PCH_GBE_ETH_ALEN is equal to ETH_ALEN, so we can replace it with
ETH_ALEN.

If they are not equal, it must be a bug, since this is ethernet,
and the address has been already stored to mc_addr_list as ETH_ALEN
bytes when call pch_gbe_mac_mc_addr_list_update.

Signed-off-by: RongQing.Li <roy.qing.li@gmail.com>
---
 .../net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c   |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
index 89c6bcf..835e3bb 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
@@ -79,7 +79,6 @@ const char pch_driver_version[] = DRV_VERSION;
 #define	PCH_GBE_PAUSE_PKT4_VALUE    0x01000888
 #define	PCH_GBE_PAUSE_PKT5_VALUE    0x0000FFFF
 
-#define PCH_GBE_ETH_ALEN            6
 
 /* This defines the bits that are set in the Interrupt Mask
  * Set/Read Register.  Each bit is documented below:
@@ -519,7 +518,7 @@ static void pch_gbe_mac_mc_addr_list_update(struct pch_gbe_hw *hw,
 		if (mc_addr_count) {
 			pch_gbe_mac_mar_set(hw, mc_addr_list, i);
 			mc_addr_count--;
-			mc_addr_list += PCH_GBE_ETH_ALEN;
+			mc_addr_list += ETH_ALEN;
 		} else {
 			/* Clear MAC address mask */
 			adrmask = ioread32(&hw->reg->ADDR_MASK);
-- 
1.7.1

^ permalink raw reply related

* [PATCH net-next 2/2] drivers/net/oki-semi: Donot recompute IP header checksum
From: roy.qing.li @ 2012-04-27  7:01 UTC (permalink / raw)
  To: netdev
In-Reply-To: <1335510073-14018-1-git-send-email-roy.qing.li@gmail.com>

From: RongQing.Li <roy.qing.li@gmail.com>

If I understand correct, NETIF_F_IP_CSUM only means the hardware 
will compute the TCP/UDP checksum, IP checksum is always computed 
in software

So as a workround of hardware unable to compute small packages 
checksum, do not need to compute IP header checksum.

Signed-off-by: RongQing.Li <roy.qing.li@gmail.com>
---
 .../net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c   |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
index 835e3bb..107f41a 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
@@ -1240,8 +1240,6 @@ static void pch_gbe_tx_queue(struct pch_gbe_adapter *adapter,
 		if (skb->protocol == htons(ETH_P_IP)) {
 			struct iphdr *iph = ip_hdr(skb);
 			unsigned int offset;
-			iph->check = 0;
-			iph->check = ip_fast_csum((u8 *) iph, iph->ihl);
 			offset = skb_transport_offset(skb);
 			if (iph->protocol == IPPROTO_TCP) {
 				skb->csum = 0;
-- 
1.7.1

^ permalink raw reply related

* [PATCH BUG-FIX] igbvf: fix the bug when initializing the igbvf
From: Shan Wei @ 2012-04-27  8:58 UTC (permalink / raw)
  To: samuelliao, Jeffrey T Kirsher, Jesse Brandeburg, bruce.w.allan,
	carolyn.wyborny, donald.c.skidmore, gregory.v.rose,
	peter.p.waskiewicz.jr, alexander.h.duyck, John Ronciak,
	David Miller, mitch.a.williams, jpirko, danny.kukawka
  Cc: e1000-devel@lists.sourceforge.net, NetDev

From: Samuel Liao <samuelliao@tencent.com>


Maybe it's a typo, but it cause that igbvf can't be initialized successfully.
Set perm_addr value using valid dev_addr, although which is equal to hw.mac.addr.


Signed-off-by: Samuel Liao <samuelliao@tencent.com>
Signed-off-by: Shan Wei <davidshan@tencent.com>
---
 drivers/net/ethernet/intel/igbvf/netdev.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index d61ca2a..8ec74b0 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -2731,14 +2731,14 @@ static int __devinit igbvf_probe(struct pci_dev *pdev,
 			netdev->addr_len);
 	}
 
-	if (!is_valid_ether_addr(netdev->perm_addr)) {
+	if (!is_valid_ether_addr(netdev->dev_addr)) {
 		dev_err(&pdev->dev, "Invalid MAC Address: %pM\n",
 		        netdev->dev_addr);
 		err = -EIO;
 		goto err_hw_init;
 	}
 
-	memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
+	memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
 
 	setup_timer(&adapter->watchdog_timer, &igbvf_watchdog,
 	            (unsigned long) adapter);
-- 
1.7.1

^ permalink raw reply related

* Re: [PATCH BUG-FIX] igbvf: fix the bug when initializing the igbvf
From: Jeff Kirsher @ 2012-04-27  9:05 UTC (permalink / raw)
  To: Shan Wei
  Cc: samuelliao, Jesse Brandeburg, bruce.w.allan, carolyn.wyborny,
	donald.c.skidmore, gregory.v.rose, peter.p.waskiewicz.jr,
	alexander.h.duyck, John Ronciak, David Miller, mitch.a.williams,
	jpirko, danny.kukawka, e1000-devel@lists.sourceforge.net, NetDev
In-Reply-To: <4F9A5FBC.1060607@gmail.com>

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

On Fri, 2012-04-27 at 16:58 +0800, Shan Wei wrote:
> 
> From: Samuel Liao <samuelliao@tencent.com>
> 
> 
> Maybe it's a typo, but it cause that igbvf can't be initialized
> successfully.
> Set perm_addr value using valid dev_addr, although which is equal to
> hw.mac.addr.
> 
> 
> Signed-off-by: Samuel Liao <samuelliao@tencent.com>
> Signed-off-by: Shan Wei <davidshan@tencent.com>
> ---
>  drivers/net/ethernet/intel/igbvf/netdev.c |    4 ++--
>  1 files changed, 2 insertions(+), 2 deletions(-) 

Thanks Samuel, I will add the patch to my queue.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* [PATCH] mwl8k: Add 0x2a02 PCI device-id (Marvell 88W8361)
From: Sedat Dilek @ 2012-04-27  9:08 UTC (permalink / raw)
  To: Lennert Buytenhek, John W. Linville,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Sedat Dilek, stable-u79uwXL29TY76Z2rM5mHXA

User lautriv asked for belkin N-1 WLAN device support on IRC.

Further informations from lautriv:
* marvell 80W8031, card-id 11ab:2a02
* Debian/sid 3.2.x

On [1] I found a report by Jim Cromie concerning same PCI device-id:

00:0e.0 Ethernet controller [0200]: Marvell Technology Group Ltd.
88W8361 [TopDog] 802.11n Wireless [11ab:2a02] (rev 03)
	Subsystem: Marvell Technology Group Ltd. 88W8361 [TopDog] 802.11n Wireless [11ab:2a02]

So, let's add 0x2a02 to PCI device table.

[1] http://www.spinics.net/lists/newbies/msg46601.html

Cc: stable-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Signed-off-by: Sedat Dilek <sedat.dilek-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 drivers/net/wireless/mwl8k.c |    1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index b48674b..16f0a9a 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -5264,6 +5264,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw");
 MODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API));
 
 static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
+	{ PCI_VDEVICE(MARVELL, 0x2a02), .driver_data = MWL8363, },
 	{ PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, },
 	{ PCI_VDEVICE(MARVELL, 0x2a0c), .driver_data = MWL8363, },
 	{ PCI_VDEVICE(MARVELL, 0x2a24), .driver_data = MWL8363, },
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [PATCH] mwl8k: Add 0x2a02 PCI device-id (Marvell 88W8361)
From: Lennert Buytenhek @ 2012-04-27  9:14 UTC (permalink / raw)
  To: Sedat Dilek
  Cc: John W. Linville, linux-wireless, netdev, linux-kernel,
	Sedat Dilek, stable
In-Reply-To: <1335517711-6522-1-git-send-email-sedat.dilek@gmail.com>

On Fri, Apr 27, 2012 at 11:08:31AM +0200, Sedat Dilek wrote:

> User lautriv asked for belkin N-1 WLAN device support on IRC.
> 
> Further informations from lautriv:
> * marvell 80W8031, card-id 11ab:2a02
> * Debian/sid 3.2.x
> 
> On [1] I found a report by Jim Cromie concerning same PCI device-id:
> 
> 00:0e.0 Ethernet controller [0200]: Marvell Technology Group Ltd.
> 88W8361 [TopDog] 802.11n Wireless [11ab:2a02] (rev 03)
> 	Subsystem: Marvell Technology Group Ltd. 88W8361 [TopDog] 802.11n Wireless [11ab:2a02]
> 
> So, let's add 0x2a02 to PCI device table.

Let's not.  There's no firmware for the 8361 that implements the
firmware interface currently implemented by the mwl8k driver, so
this is pretty useless.


> [1] http://www.spinics.net/lists/newbies/msg46601.html

>From that link:

| I have a card which modprobes, despite a PCI-ID mismatch
|
| [...]
|
| Given the pci-id mismatch shouldnt this just fail to modprobe ?

No.  That's not a bug -- you are free to load drivers for hardware
not currently in your system.


>  static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
> +	{ PCI_VDEVICE(MARVELL, 0x2a02), .driver_data = MWL8363, },
>  	{ PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, },

A 8361 is certainly not a 8363.

^ permalink raw reply

* Re: [PATCH] mwl8k: Add 0x2a02 PCI device-id (Marvell 88W8361)
From: Sedat Dilek @ 2012-04-27  9:22 UTC (permalink / raw)
  To: Lennert Buytenhek
  Cc: John W. Linville, linux-wireless, netdev, linux-kernel, stable
In-Reply-To: <20120427091405.GS3157@wantstofly.org>

On Fri, Apr 27, 2012 at 11:14 AM, Lennert Buytenhek
<buytenh@wantstofly.org> wrote:
> On Fri, Apr 27, 2012 at 11:08:31AM +0200, Sedat Dilek wrote:
>
>> User lautriv asked for belkin N-1 WLAN device support on IRC.
>>
>> Further informations from lautriv:
>> * marvell 80W8031, card-id 11ab:2a02
>> * Debian/sid 3.2.x
>>
>> On [1] I found a report by Jim Cromie concerning same PCI device-id:
>>
>> 00:0e.0 Ethernet controller [0200]: Marvell Technology Group Ltd.
>> 88W8361 [TopDog] 802.11n Wireless [11ab:2a02] (rev 03)
>>       Subsystem: Marvell Technology Group Ltd. 88W8361 [TopDog] 802.11n Wireless [11ab:2a02]
>>
>> So, let's add 0x2a02 to PCI device table.
>
> Let's not.  There's no firmware for the 8361 that implements the
> firmware interface currently implemented by the mwl8k driver, so
> this is pretty useless.
>
>
>> [1] http://www.spinics.net/lists/newbies/msg46601.html
>
> From that link:
>
> | I have a card which modprobes, despite a PCI-ID mismatch
> |
> | [...]
> |
> | Given the pci-id mismatch shouldnt this just fail to modprobe ?
>
> No.  That's not a bug -- you are free to load drivers for hardware
> not currently in your system.
>
>
>>  static DEFINE_PCI_DEVICE_TABLE(mwl8k_pci_id_table) = {
>> +     { PCI_VDEVICE(MARVELL, 0x2a02), .driver_data = MWL8363, },
>>       { PCI_VDEVICE(MARVELL, 0x2a0a), .driver_data = MWL8363, },
>
> A 8361 is certainly not a 8363.

Damn, I got confused by all the numbers. More coffee.
Thanks for the clarification. I will inform the user on IRC.
Sorry, for the noise.

Are you planning to or even working on support (for) 8361 devices?

- Sedat -

^ permalink raw reply

* [BUG report] net.core.rmem_default is larger than net.core.rmem_max
From: Shan Wei @ 2012-04-27  9:31 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: NetDev


It's unconventional that "default" value  is greater than "max". :-(

net.core.rmem_max = 131071
net.core.rmem_default = 229376

net.core.wmem_max = 131071
net.core.wmem_default = 229376


And bisect the code to find the following commit caused this phenomenon.
This patch increase SK_WMEM_MAX and SK_RMEM_MAX which are used to 
initialize them.
But rmem_max and wmem_max value are still be covered according the RAM size
in sk_init().

87fb4b7b533073eeeaed0b6bf7c2328995f6c075 is the first bad commit
commit 87fb4b7b533073eeeaed0b6bf7c2328995f6c075
Author: Eric Dumazet <eric.dumazet@gmail.com>
Date:   Thu Oct 13 07:28:54 2011 +0000

    net: more accurate skb truesize

^ permalink raw reply

* [net-next 0/6][pull request] Intel Wired LAN Driver Updates
From: Jeff Kirsher @ 2012-04-27  9:36 UTC (permalink / raw)
  To: davem; +Cc: Jeff Kirsher, netdev, gospo, sassmann

This series of patches contains updates for e1000e, igb and
ixgbe.

The following are changes since commit 82981930125abfd39d7c8378a9cfdf5e1be2002b:
  net: cleanups in sock_setsockopt()
and are available in the git repository at:
  git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next master

Bruce Allan (2):
  e1000e: 82579 packet drop workaround
  e1000e: 82579 potential system hang on stress when ME enabled

Jacob Keller (1):
  ixgbe: check for WoL support in single function

Matthew Vick (3):
  e1000e: Disable Far-End LoopBack following reset on 80003ES2LAN.
  e1000e: Enable DMA Burst Mode on 82574 by default.
  igb: Force flow control off during reset when forcing speed.

 drivers/net/ethernet/intel/e1000e/80003es2lan.c  |    8 ++
 drivers/net/ethernet/intel/e1000e/82571.c        |    3 +-
 drivers/net/ethernet/intel/e1000e/e1000.h        |   37 +++++++++
 drivers/net/ethernet/intel/e1000e/hw.h           |   10 ---
 drivers/net/ethernet/intel/e1000e/ich8lan.c      |   11 +++
 drivers/net/ethernet/intel/e1000e/netdev.c       |   51 ++++---------
 drivers/net/ethernet/intel/igb/igb_main.c        |    7 ++
 drivers/net/ethernet/intel/ixgbe/ixgbe.h         |    2 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c |   51 +-----------
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c    |   88 ++++++++++++++--------
 10 files changed, 143 insertions(+), 125 deletions(-)

-- 
1.7.7.6

^ permalink raw reply

* [net-next 2/6] e1000e: Enable DMA Burst Mode on 82574 by default.
From: Jeff Kirsher @ 2012-04-27  9:36 UTC (permalink / raw)
  To: davem; +Cc: Matthew Vick, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1335519413-1892-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Matthew Vick <matthew.vick@intel.com>

Performance testing has shown that enabling DMA burst on 82574
improves performance on small packets, so enable it by default.

Signed-off-by: Matthew Vick <matthew.vick@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/e1000e/82571.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c
index 609c18c..d0ea316 100644
--- a/drivers/net/ethernet/intel/e1000e/82571.c
+++ b/drivers/net/ethernet/intel/e1000e/82571.c
@@ -2062,7 +2062,8 @@ const struct e1000_info e1000_82574_info = {
 				  | FLAG_HAS_CTRLEXT_ON_LOAD,
 	.flags2			  = FLAG2_CHECK_PHY_HANG
 				  | FLAG2_DISABLE_ASPM_L0S
-				  | FLAG2_NO_DISABLE_RX,
+				  | FLAG2_NO_DISABLE_RX
+				  | FLAG2_DMA_BURST,
 	.pba			= 32,
 	.max_hw_frame_size	= DEFAULT_JUMBO,
 	.get_variants		= e1000_get_variants_82571,
-- 
1.7.7.6

^ permalink raw reply related

* [net-next 3/6] e1000e: 82579 packet drop workaround
From: Jeff Kirsher @ 2012-04-27  9:36 UTC (permalink / raw)
  To: davem; +Cc: Bruce Allan, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1335519413-1892-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Bruce Allan <bruce.w.allan@intel.com>

In K1 mode (a MAC/PHY interconnect power mode), the 82579 device shuts down
the Phase Lock Loop (PLL) of the interconnect to save power.  When the PLL
starts working, the 82579 device may start to transfer the packet through
the interconnect before it is fully functional causing packet drops.  This
workaround disables shutting down the PLL in K1 mode for 1G link speed.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/e1000e/ich8lan.c |   11 +++++++++++
 1 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 14af3e2..d7fd1e8 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -135,6 +135,7 @@
 
 /* PHY Power Management Control */
 #define HV_PM_CTRL		PHY_REG(770, 17)
+#define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA	0x100
 
 /* PHY Low Power Idle Control */
 #define I82579_LPI_CTRL				PHY_REG(772, 20)
@@ -1708,8 +1709,18 @@ static s32 e1000_k1_workaround_lv(struct e1000_hw *hw)
 			return ret_val;
 
 		if (status_reg & HV_M_STATUS_SPEED_1000) {
+			u16 pm_phy_reg;
+
 			mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
 			phy_reg &= ~I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT;
+			/* LV 1G Packet drop issue wa  */
+			ret_val = e1e_rphy(hw, HV_PM_CTRL, &pm_phy_reg);
+			if (ret_val)
+				return ret_val;
+			pm_phy_reg &= ~HV_PM_CTRL_PLL_STOP_IN_K1_GIGA;
+			ret_val = e1e_wphy(hw, HV_PM_CTRL, pm_phy_reg);
+			if (ret_val)
+				return ret_val;
 		} else {
 			mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
 			phy_reg |= I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT;
-- 
1.7.7.6

^ permalink raw reply related

* [net-next 1/6] e1000e: Disable Far-End LoopBack following reset on 80003ES2LAN.
From: Jeff Kirsher @ 2012-04-27  9:36 UTC (permalink / raw)
  To: davem; +Cc: Matthew Vick, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1335519413-1892-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Matthew Vick <matthew.vick@intel.com>

80003ES2LAN has an errata such that far-end loopback may be activated by
bit errors producing a reserved symbol. In order to disable far-end
loopback quickly enough, disable it immediately following a reset.

Signed-off-by: Matthew Vick <matthew.vick@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/e1000e/80003es2lan.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.c b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
index fbc84d4..a212846 100644
--- a/drivers/net/ethernet/intel/e1000e/80003es2lan.c
+++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.c
@@ -764,6 +764,7 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
 {
 	u32 ctrl;
 	s32 ret_val;
+	u16 kum_reg_data;
 
 	/*
 	 * Prevent the PCI-E bus from sticking if there is no TLP connection
@@ -789,6 +790,13 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
 	ew32(CTRL, ctrl | E1000_CTRL_RST);
 	e1000_release_phy_80003es2lan(hw);
 
+	/* Disable IBIST slave mode (far-end loopback) */
+	e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
+					&kum_reg_data);
+	kum_reg_data |= E1000_KMRNCTRLSTA_IBIST_DISABLE;
+	e1000_write_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_INBAND_PARAM,
+					 kum_reg_data);
+
 	ret_val = e1000e_get_auto_rd_done(hw);
 	if (ret_val)
 		/* We don't want to continue accessing MAC registers. */
-- 
1.7.7.6

^ permalink raw reply related

* [net-next 4/6] e1000e: 82579 potential system hang on stress when ME enabled
From: Jeff Kirsher @ 2012-04-27  9:36 UTC (permalink / raw)
  To: davem; +Cc: Bruce Allan, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1335519413-1892-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Bruce Allan <bruce.w.allan@intel.com>

Previously, a workaround was added to address a hardware bug in the
PCIm2PCI arbiter where a write by the driver of the Transmit/Receive
Descriptor Tail register could happen concurrently with a write of any
MAC CSR register by the Manageability Engine (ME) which could cause the
Tail register to have an incorrect value.  The arbiter is supposed to
prevent the concurrent writes but there is a bug that can cause the Host
(driver) access to be acknowledged later than it should.
After further investigation, it was discovered that a driver write access
of any MAC CSR register after being idle for some time can be lost when
ME is accessing a MAC CSR register.  When this happens, no further target
access is claimed by the MAC which could hang the system.
The workaround to check bit 24 in the FWSM register (set only when ME is
accessing a MAC CSR register) and delay for a limited amount of time until
it is cleared is now done for all driver writes of MAC CSR registers on
82579 with ME enabled.  In the rare case when the driver is writing the
Tail register and ME is accessing any MAC CSR register for a duration
longer than the maximum delay, write the register and verify it has the
correct value before continuing, otherwise reset the device.

This patch also moves some pre-existing macros from the hardware-specific
header file to the more appropriate generic driver header file.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/e1000e/e1000.h  |   37 ++++++++++++++++++++
 drivers/net/ethernet/intel/e1000e/hw.h     |   10 -----
 drivers/net/ethernet/intel/e1000e/netdev.c |   51 +++++++++-------------------
 3 files changed, 53 insertions(+), 45 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index b83897f..1dc2067 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -735,9 +735,46 @@ static inline u32 __er32(struct e1000_hw *hw, unsigned long reg)
 	return readl(hw->hw_addr + reg);
 }
 
+#define er32(reg)	__er32(hw, E1000_##reg)
+
+/**
+ * __ew32_prepare - prepare to write to MAC CSR register on certain parts
+ * @hw: pointer to the HW structure
+ *
+ * When updating the MAC CSR registers, the Manageability Engine (ME) could
+ * be accessing the registers at the same time.  Normally, this is handled in
+ * h/w by an arbiter but on some parts there is a bug that acknowledges Host
+ * accesses later than it should which could result in the register to have
+ * an incorrect value.  Workaround this by checking the FWSM register which
+ * has bit 24 set while ME is accessing MAC CSR registers, wait if it is set
+ * and try again a number of times.
+ **/
+static inline s32 __ew32_prepare(struct e1000_hw *hw)
+{
+	s32 i = E1000_ICH_FWSM_PCIM2PCI_COUNT;
+
+	while ((er32(FWSM) & E1000_ICH_FWSM_PCIM2PCI) && --i)
+		udelay(50);
+
+	return i;
+}
+
 static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val)
 {
+	if (hw->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+		__ew32_prepare(hw);
+
 	writel(val, hw->hw_addr + reg);
 }
 
+#define ew32(reg, val)	__ew32(hw, E1000_##reg, (val))
+
+#define e1e_flush()	er32(STATUS)
+
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \
+	(__ew32((a), (reg + ((offset) << 2)), (value)))
+
+#define E1000_READ_REG_ARRAY(a, reg, offset) \
+	(readl((a)->hw_addr + reg + ((offset) << 2)))
+
 #endif /* _E1000_H_ */
diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h
index 923d3fd..7ca1b68 100644
--- a/drivers/net/ethernet/intel/e1000e/hw.h
+++ b/drivers/net/ethernet/intel/e1000e/hw.h
@@ -36,16 +36,6 @@ struct e1000_adapter;
 
 #include "defines.h"
 
-#define er32(reg)	__er32(hw, E1000_##reg)
-#define ew32(reg,val)	__ew32(hw, E1000_##reg, (val))
-#define e1e_flush()	er32(STATUS)
-
-#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \
-	(writel((value), ((a)->hw_addr + reg + ((offset) << 2))))
-
-#define E1000_READ_REG_ARRAY(a, reg, offset) \
-	(readl((a)->hw_addr + reg + ((offset) << 2)))
-
 enum e1e_registers {
 	E1000_CTRL     = 0x00000, /* Device Control - RW */
 	E1000_STATUS   = 0x00008, /* Device Status - RO */
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 851f793..cdfb1d6 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -538,43 +538,15 @@ static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
 	adapter->hw_csum_good++;
 }
 
-/**
- * e1000e_update_tail_wa - helper function for e1000e_update_[rt]dt_wa()
- * @hw: pointer to the HW structure
- * @tail: address of tail descriptor register
- * @i: value to write to tail descriptor register
- *
- * When updating the tail register, the ME could be accessing Host CSR
- * registers at the same time.  Normally, this is handled in h/w by an
- * arbiter but on some parts there is a bug that acknowledges Host accesses
- * later than it should which could result in the descriptor register to
- * have an incorrect value.  Workaround this by checking the FWSM register
- * which has bit 24 set while ME is accessing Host CSR registers, wait
- * if it is set and try again a number of times.
- **/
-static inline s32 e1000e_update_tail_wa(struct e1000_hw *hw, void __iomem *tail,
-					unsigned int i)
-{
-	unsigned int j = 0;
-
-	while ((j++ < E1000_ICH_FWSM_PCIM2PCI_COUNT) &&
-	       (er32(FWSM) & E1000_ICH_FWSM_PCIM2PCI))
-		udelay(50);
-
-	writel(i, tail);
-
-	if ((j == E1000_ICH_FWSM_PCIM2PCI_COUNT) && (i != readl(tail)))
-		return E1000_ERR_SWFW_SYNC;
-
-	return 0;
-}
-
 static void e1000e_update_rdt_wa(struct e1000_ring *rx_ring, unsigned int i)
 {
 	struct e1000_adapter *adapter = rx_ring->adapter;
 	struct e1000_hw *hw = &adapter->hw;
+	s32 ret_val = __ew32_prepare(hw);
+
+	writel(i, rx_ring->tail);
 
-	if (e1000e_update_tail_wa(hw, rx_ring->tail, i)) {
+	if (unlikely(!ret_val && (i != readl(rx_ring->tail)))) {
 		u32 rctl = er32(RCTL);
 		ew32(RCTL, rctl & ~E1000_RCTL_EN);
 		e_err("ME firmware caused invalid RDT - resetting\n");
@@ -586,8 +558,11 @@ static void e1000e_update_tdt_wa(struct e1000_ring *tx_ring, unsigned int i)
 {
 	struct e1000_adapter *adapter = tx_ring->adapter;
 	struct e1000_hw *hw = &adapter->hw;
+	s32 ret_val = __ew32_prepare(hw);
 
-	if (e1000e_update_tail_wa(hw, tx_ring->tail, i)) {
+	writel(i, tx_ring->tail);
+
+	if (unlikely(!ret_val && (i != readl(tx_ring->tail)))) {
 		u32 tctl = er32(TCTL);
 		ew32(TCTL, tctl & ~E1000_TCTL_EN);
 		e_err("ME firmware caused invalid TDT - resetting\n");
@@ -1646,7 +1621,10 @@ static void e1000_clean_rx_ring(struct e1000_ring *rx_ring)
 	adapter->flags2 &= ~FLAG2_IS_DISCARDING;
 
 	writel(0, rx_ring->head);
-	writel(0, rx_ring->tail);
+	if (rx_ring->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+		e1000e_update_rdt_wa(rx_ring, 0);
+	else
+		writel(0, rx_ring->tail);
 }
 
 static void e1000e_downshift_workaround(struct work_struct *work)
@@ -2319,7 +2297,10 @@ static void e1000_clean_tx_ring(struct e1000_ring *tx_ring)
 	tx_ring->next_to_clean = 0;
 
 	writel(0, tx_ring->head);
-	writel(0, tx_ring->tail);
+	if (tx_ring->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+		e1000e_update_tdt_wa(tx_ring, 0);
+	else
+		writel(0, tx_ring->tail);
 }
 
 /**
-- 
1.7.7.6

^ permalink raw reply related

* [net-next 5/6] igb: Force flow control off during reset when forcing speed.
From: Jeff Kirsher @ 2012-04-27  9:36 UTC (permalink / raw)
  To: davem; +Cc: Matthew Vick, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1335519413-1892-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Matthew Vick <matthew.vick@intel.com>

During igb_reset(), we initiate a hardware reset which will clear our
flow control settings. For auto-negotiation, we re-negotiate them when
linking up again, but we need to force them off properly for the forced
speed case.

Signed-off-by: Matthew Vick <matthew.vick@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/igb/igb_main.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 28a37bb..f40f388 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -1715,6 +1715,13 @@ void igb_reset(struct igb_adapter *adapter)
 	if (hw->mac.ops.init_hw(hw))
 		dev_err(&pdev->dev, "Hardware Error\n");
 
+	/*
+	 * Flow control settings reset on hardware reset, so guarantee flow
+	 * control is off when forcing speed.
+	 */
+	if (!hw->mac.autoneg)
+		igb_force_mac_fc(hw);
+
 	igb_init_dmac(adapter, pba);
 	if (!netif_running(adapter->netdev))
 		igb_power_down_link(adapter);
-- 
1.7.7.6

^ permalink raw reply related

* [net-next 6/6] ixgbe: check for WoL support in single function
From: Jeff Kirsher @ 2012-04-27  9:36 UTC (permalink / raw)
  To: davem; +Cc: Jacob Keller, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1335519413-1892-1-git-send-email-jeffrey.t.kirsher@intel.com>

From: Jacob Keller <jacob.e.keller@intel.com>

This patch consolidates the case logic for checking whether a device supports
WoL into a single place. Previously ethtool and probe used similar logic that
was copied and maintained separately. This patch encapsulates the core logic
into a function so that a user only has to update one place.

Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Stephen Ko <stephen.s.ko@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe.h         |    2 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c |   51 +-----------
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c    |   88 ++++++++++++++--------
 3 files changed, 62 insertions(+), 79 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 74e1921..8e082f2 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -600,6 +600,8 @@ extern void ixgbe_disable_rx_queue(struct ixgbe_adapter *adapter,
 				   struct ixgbe_ring *);
 extern void ixgbe_update_stats(struct ixgbe_adapter *adapter);
 extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter);
+extern int ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id,
+			       u16 subdevice_id);
 extern void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter);
 extern netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *,
 					 struct ixgbe_adapter *,
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
index 31a2bf7..27225ff 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
@@ -1969,53 +1969,12 @@ static int ixgbe_wol_exclusion(struct ixgbe_adapter *adapter,
                                struct ethtool_wolinfo *wol)
 {
 	struct ixgbe_hw *hw = &adapter->hw;
-	int retval = 1;
-	u16 wol_cap = adapter->eeprom_cap & IXGBE_DEVICE_CAPS_WOL_MASK;
-
-	/* WOL not supported except for the following */
-	switch(hw->device_id) {
-	case IXGBE_DEV_ID_82599_SFP:
-		/* Only these subdevices could supports WOL */
-		switch (hw->subsystem_device_id) {
-		case IXGBE_SUBDEV_ID_82599_560FLR:
-			/* only support first port */
-			if (hw->bus.func != 0) {
-				wol->supported = 0;
-				break;
-			}
-		case IXGBE_SUBDEV_ID_82599_SFP:
-			retval = 0;
-			break;
-		default:
-			wol->supported = 0;
-			break;
-		}
-		break;
-	case IXGBE_DEV_ID_82599_COMBO_BACKPLANE:
-		/* All except this subdevice support WOL */
-		if (hw->subsystem_device_id ==
-		    IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ) {
-			wol->supported = 0;
-			break;
-		}
-		retval = 0;
-		break;
-	case IXGBE_DEV_ID_82599_KX4:
-		retval = 0;
-		break;
-	case IXGBE_DEV_ID_X540T:
-		/* check eeprom to see if enabled wol */
-		if ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0_1) ||
-		    ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0) &&
-		     (hw->bus.func == 0))) {
-			retval = 0;
-			break;
-		}
+	int retval = 0;
 
-		/* All others not supported */
-		wol->supported = 0;
-		break;
-	default:
+	/* WOL not supported for all devices */
+	if (!ixgbe_wol_supported(adapter, hw->device_id,
+				 hw->subsystem_device_id)) {
+		retval = 1;
 		wol->supported = 0;
 	}
 
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 7c4325ec..aa29edb 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -6598,7 +6598,7 @@ static netdev_features_t ixgbe_fix_features(struct net_device *netdev,
 	/* Turn off LRO if not RSC capable */
 	if (!(adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE))
 		features &= ~NETIF_F_LRO;
-	
+
 
 	return features;
 }
@@ -6786,6 +6786,57 @@ static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter,
 }
 
 /**
+ * ixgbe_wol_supported - Check whether device supports WoL
+ * @hw: hw specific details
+ * @device_id: the device ID
+ * @subdev_id: the subsystem device ID
+ *
+ * This function is used by probe and ethtool to determine
+ * which devices have WoL support
+ *
+ **/
+int ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id,
+			u16 subdevice_id)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+	u16 wol_cap = adapter->eeprom_cap & IXGBE_DEVICE_CAPS_WOL_MASK;
+	int is_wol_supported = 0;
+
+	switch (device_id) {
+	case IXGBE_DEV_ID_82599_SFP:
+		/* Only these subdevices could supports WOL */
+		switch (subdevice_id) {
+		case IXGBE_SUBDEV_ID_82599_560FLR:
+			/* only support first port */
+			if (hw->bus.func != 0)
+				break;
+		case IXGBE_SUBDEV_ID_82599_SFP:
+			is_wol_supported = 1;
+			break;
+		}
+		break;
+	case IXGBE_DEV_ID_82599_COMBO_BACKPLANE:
+		/* All except this subdevice support WOL */
+		if (subdevice_id != IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ)
+			is_wol_supported = 1;
+		break;
+	case IXGBE_DEV_ID_82599_KX4:
+		is_wol_supported = 1;
+		break;
+	case IXGBE_DEV_ID_X540T:
+		/* check eeprom to see if enabled wol */
+		if ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0_1) ||
+		    ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0) &&
+		     (hw->bus.func == 0))) {
+			is_wol_supported = 1;
+		}
+		break;
+	}
+
+	return is_wol_supported;
+}
+
+/**
  * ixgbe_probe - Device Initialization Routine
  * @pdev: PCI device information struct
  * @ent: entry in ixgbe_pci_tbl
@@ -6811,7 +6862,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
 	u16 device_caps;
 #endif
 	u32 eec;
-	u16 wol_cap;
 
 	/* Catch broken hardware that put the wrong VF device ID in
 	 * the PCIe SR-IOV capability.
@@ -7075,40 +7125,12 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
 		netdev->features &= ~NETIF_F_RXHASH;
 	}
 
-	/* WOL not supported for all but the following */
+	/* WOL not supported for all devices */
 	adapter->wol = 0;
-	switch (pdev->device) {
-	case IXGBE_DEV_ID_82599_SFP:
-		/* Only these subdevice supports WOL */
-		switch (pdev->subsystem_device) {
-		case IXGBE_SUBDEV_ID_82599_560FLR:
-			/* only support first port */
-			if (hw->bus.func != 0)
-				break;
-		case IXGBE_SUBDEV_ID_82599_SFP:
-			adapter->wol = IXGBE_WUFC_MAG;
-			break;
-		}
-		break;
-	case IXGBE_DEV_ID_82599_COMBO_BACKPLANE:
-		/* All except this subdevice support WOL */
-		if (pdev->subsystem_device != IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ)
-			adapter->wol = IXGBE_WUFC_MAG;
-		break;
-	case IXGBE_DEV_ID_82599_KX4:
+	hw->eeprom.ops.read(hw, 0x2c, &adapter->eeprom_cap);
+	if (ixgbe_wol_supported(adapter, pdev->device, pdev->subsystem_device))
 		adapter->wol = IXGBE_WUFC_MAG;
-		break;
-	case IXGBE_DEV_ID_X540T:
-		/* Check eeprom to see if it is enabled */
-		hw->eeprom.ops.read(hw, 0x2c, &adapter->eeprom_cap);
-		wol_cap = adapter->eeprom_cap & IXGBE_DEVICE_CAPS_WOL_MASK;
 
-		if ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0_1) ||
-		    ((wol_cap == IXGBE_DEVICE_CAPS_WOL_PORT0) &&
-		     (hw->bus.func == 0)))
-			adapter->wol = IXGBE_WUFC_MAG;
-		break;
-	}
 	device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
 
 	/* save off EEPROM version number */
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH 01/17] netfilter: add struct nf_proto_net for register l4proto sysctl
From: Gao feng @ 2012-04-27  9:37 UTC (permalink / raw)
  To: pablo; +Cc: netfilter-devel, netdev, serge.hallyn, ebiederm, dlezcano,
	Gao feng
In-Reply-To: <1335519484-6089-1-git-send-email-gaofeng@cn.fujitsu.com>

From: Gao feng <gaofeng@cn.fujitus.com>

the struct nf_proto_net stroes proto's ctl_table_header and ctl_table,
nf_ct_l4proto_(un)register_sysctl use it to register sysctl.

there are some changes for struct nf_conntrack_l4proto:
- add field compat to identify if this proto should do compat.
- the net_id field is used to store the pernet_operations id
  that belones to l4proto.
- init_net will be used to initial the proto's pernet data

and add init_net for struct nf_conntrack_l3proto too.

Signed-off-by: Gao feng <gaofeng@cn.fujitus.com>
---
 include/net/netfilter/nf_conntrack_l3proto.h |    3 +++
 include/net/netfilter/nf_conntrack_l4proto.h |    6 ++++++
 include/net/netns/conntrack.h                |   12 ++++++++++++
 3 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h
index 9699c02..9766005 100644
--- a/include/net/netfilter/nf_conntrack_l3proto.h
+++ b/include/net/netfilter/nf_conntrack_l3proto.h
@@ -69,6 +69,9 @@ struct nf_conntrack_l3proto {
 	struct ctl_table	*ctl_table;
 #endif /* CONFIG_SYSCTL */
 
+	/* Init l3proto pernet data */
+	int (*init_net)(struct net *net);
+
 	/* Module (if any) which this is connected to. */
 	struct module *me;
 };
diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h
index 3b572bb..ad8ff89 100644
--- a/include/net/netfilter/nf_conntrack_l4proto.h
+++ b/include/net/netfilter/nf_conntrack_l4proto.h
@@ -21,6 +21,8 @@ struct nf_conntrack_l4proto {
 
 	/* L4 Protocol number. */
 	u_int8_t l4proto;
+
+	u_int8_t compat;
 
 	/* Try to fill in the third arg: dataoff is offset past network protocol
            hdr.  Return true if possible. */
@@ -103,6 +105,10 @@ struct nf_conntrack_l4proto {
 	struct ctl_table	*ctl_compat_table;
 #endif
 #endif
+	int	*net_id;
+	/* Init l4proto pernet data */
+	int (*init_net)(struct net *net, u_int8_t compat);
+
 	/* Protocol name */
 	const char *name;
 
diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h
index 7a911ec..59afb87 100644
--- a/include/net/netns/conntrack.h
+++ b/include/net/netns/conntrack.h
@@ -8,6 +8,18 @@
 struct ctl_table_header;
 struct nf_conntrack_ecache;
 
+struct nf_proto_net {
+#ifdef CONFIG_SYSCTL
+	struct ctl_table_header *ctl_table_header;
+	struct ctl_table        *ctl_table;
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+	struct ctl_table_header *ctl_compat_header;
+	struct ctl_table        *ctl_compat_table;
+#endif
+#endif
+	unsigned int		users;
+};
+
 struct netns_ct {
 	atomic_t		count;
 	unsigned int		expect_count;
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH v2 00/17] netfilter: add namespace support for netfilter protos
From: Gao feng @ 2012-04-27  9:37 UTC (permalink / raw)
  To: pablo; +Cc: netfilter-devel, netdev, serge.hallyn, ebiederm, dlezcano,
	Gao feng

Currently the sysctl of netfilter proto is not isolated, so when
changing proto's sysctl in container will cause the host's sysctl
be changed too. it's not expected.

This patch set adds the namespace support for netfilter protos.

impletement four pernet_operations to register sysctl and initial
pernet data for proto.

-ipv4_net_ops is used to register tcp4(compat),
 udp4(compat),icmp(compat),ipv4(compat).
-ipv6_net_ops is used to register tcp6,udp6 and icmpv6.
-sctp_net_ops is used to register sctp4(compat) and sctp6.
-udplite_net_ops is used to register udplite4 and udplite6

extern l[3,4]proto (sysctl) register functions to make them support
namespace.

finailly add namespace support for cttimeout.

Gao feng (17):
  netfilter: add struct nf_proto_net for register l4proto sysctl
  netfilter: add namespace support for l4proto
  netfilter: add namespace support for l3proto
  netfilter: add namespace support for l4proto_generic
  netfilter: add namespace support for l4proto_tcp
  netfilter: add namespace support for l4proto_udp
  netfilter: add namespace support for l4proto_icmp
  netfilter: add namespace support for l4proto_icmpv6
  netfilter: add namespace support for l3proto_ipv4
  netfilter: add namespace support for l3proto_ipv6
  netfilter: add namespace support for l4proto_sctp
  netfilter: add namespace support for l4proto_udplite
  netfilter: adjust l4proto_dccp to the nf_conntrack_l4proto_register
  netfilter: adjust l4proto_gre4 to the nf_conntrack_l4proto_register
  netfilter: cleanup sysctl for l4proto and l3proto
  netfilter: add namespace support for cttimeout
  netfilter: cttimeout use pernet data of l4proto

 include/net/netfilter/nf_conntrack_l3proto.h   |   11 +-
 include/net/netfilter/nf_conntrack_l4proto.h   |   32 ++-
 include/net/netns/conntrack.h                  |   55 ++++
 net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c |  127 ++++++---
 net/ipv4/netfilter/nf_conntrack_proto_icmp.c   |   55 +++-
 net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c |   88 ++++--
 net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c |   38 ++-
 net/netfilter/nf_conntrack_core.c              |    7 +-
 net/netfilter/nf_conntrack_proto.c             |  390 ++++++++++++++----------
 net/netfilter/nf_conntrack_proto_dccp.c        |  141 +++++----
 net/netfilter/nf_conntrack_proto_generic.c     |   69 ++++-
 net/netfilter/nf_conntrack_proto_gre.c         |   66 +++--
 net/netfilter/nf_conntrack_proto_sctp.c        |  157 +++++++---
 net/netfilter/nf_conntrack_proto_tcp.c         |  136 ++++++---
 net/netfilter/nf_conntrack_proto_udp.c         |   90 ++++--
 net/netfilter/nf_conntrack_proto_udplite.c     |  125 ++++++--
 net/netfilter/nfnetlink_cttimeout.c            |   13 +-
 17 files changed, 1068 insertions(+), 532 deletions(-)

-- 
1.7.7.6

^ permalink raw reply

* [PATCH 02/17] netfilter: add namespace support for l4proto
From: Gao feng @ 2012-04-27  9:37 UTC (permalink / raw)
  To: pablo; +Cc: netfilter-devel, netdev, serge.hallyn, ebiederm, dlezcano,
	Gao feng
In-Reply-To: <1335519484-6089-1-git-send-email-gaofeng@cn.fujitsu.com>

From: Gao feng <gaofeng@cn.fujitus.com>

-nf_ct_(un)register_sysctl are changed to support net namespace,
 use (un)register_net_sysctl_table replaces (un)register_sysctl_paths.
 and in nf_ct_unregister_sysctl,kfree table only when users is 0.

-Add the struct net as param of nf_conntrack_l4proto_(un)register.
 register or unregister the l4proto only when the net is init_net.

-nf_conntrack_l4proto_register call init_net to initial the pernet
 data of l4proto.

-nf_ct_l4proto_net is used to get the pernet data of l4proto.

Signed-off-by: Gao feng <gaofeng@cn.fujitus.com>
---
 include/net/netfilter/nf_conntrack_l4proto.h |   13 +-
 net/netfilter/nf_conntrack_proto.c           |  240 +++++++++++++++-----------
 2 files changed, 152 insertions(+), 101 deletions(-)

diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h
index ad8ff89..e4ea46f 100644
--- a/include/net/netfilter/nf_conntrack_l4proto.h
+++ b/include/net/netfilter/nf_conntrack_l4proto.h
@@ -12,7 +12,7 @@
 #include <linux/netlink.h>
 #include <net/netlink.h>
 #include <net/netfilter/nf_conntrack.h>
-
+#include <net/netns/generic.h>
 struct seq_file;
 
 struct nf_conntrack_l4proto {
@@ -129,8 +129,15 @@ nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto);
 extern void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p);
 
 /* Protocol registration. */
-extern int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *proto);
-extern void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *proto);
+extern int nf_conntrack_l4proto_register(struct net *net,
+					 struct nf_conntrack_l4proto *proto);
+extern void nf_conntrack_l4proto_unregister(struct net *net,
+					    struct nf_conntrack_l4proto *proto);
+
+extern int nf_ct_l4proto_register_sysctl(struct net *net,
+					 struct nf_conntrack_l4proto *l4proto);
+extern void nf_ct_l4proto_unregister_sysctl(struct net *net,
+					    struct nf_conntrack_l4proto *l4proto);
 
 /* Generic netlink helpers */
 extern int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb,
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index 8b631b0..85d71e0 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -35,30 +35,39 @@ EXPORT_SYMBOL_GPL(nf_ct_l3protos);
 static DEFINE_MUTEX(nf_ct_proto_mutex);
 
 #ifdef CONFIG_SYSCTL
-static int
-nf_ct_register_sysctl(struct ctl_table_header **header, const char *path,
-		      struct ctl_table *table, unsigned int *users)
+int
+nf_ct_register_sysctl(struct net *net,
+		      struct ctl_table_header **header,
+		      const char *path,
+		      struct ctl_table *table,
+		      unsigned int *users)
 {
 	if (*header == NULL) {
-		*header = register_net_sysctl(&init_net, path, table);
+		*header = register_net_sysctl(net, path, table);
 		if (*header == NULL)
 			return -ENOMEM;
 	}
 	if (users != NULL)
 		(*users)++;
+
 	return 0;
 }
+EXPORT_SYMBOL_GPL(nf_ct_register_sysctl);
 
-static void
+void
 nf_ct_unregister_sysctl(struct ctl_table_header **header,
-			struct ctl_table *table, unsigned int *users)
+			struct ctl_table **table,
+			unsigned int *users)
 {
 	if (users != NULL && --*users > 0)
 		return;
 
 	unregister_net_sysctl_table(*header);
+	kfree(*table);
 	*header = NULL;
+	*table = NULL;
 }
+EXPORT_SYMBOL_GPL(nf_ct_unregister_sysctl);
 #endif
 
 struct nf_conntrack_l4proto *
@@ -243,137 +252,172 @@ void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister);
 
-static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto)
+static struct nf_proto_net *nf_ct_l4proto_net(struct net *net,
+					      struct nf_conntrack_l4proto *l4proto)
 {
-	int err = 0;
+	if (l4proto->net_id)
+		return net_generic(net, *l4proto->net_id);
+	else
+		return NULL;
+}
 
+int nf_ct_l4proto_register_sysctl(struct net *net,
+				  struct nf_conntrack_l4proto *l4proto)
+{
+	int err = 0;
+	struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto);
+	if (pn == NULL)
+		return 0;
 #ifdef CONFIG_SYSCTL
-	if (l4proto->ctl_table != NULL) {
-		err = nf_ct_register_sysctl(l4proto->ctl_table_header,
+	if (pn->ctl_table != NULL) {
+		err = nf_ct_register_sysctl(net,
+					    &pn->ctl_table_header,
 					    "net/netfilter",
-					    l4proto->ctl_table,
-					    l4proto->ctl_table_users);
-		if (err < 0)
+					    pn->ctl_table,
+					    &pn->users);
+		if (err < 0) {
+			kfree(pn->ctl_table);
+			pn->ctl_table = NULL;
 			goto out;
+		}
 	}
 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-	if (l4proto->ctl_compat_table != NULL) {
-		err = nf_ct_register_sysctl(&l4proto->ctl_compat_table_header,
+	if (l4proto->compat && pn->ctl_compat_table != NULL) {
+		err = nf_ct_register_sysctl(net,
+					    &pn->ctl_compat_header,
 					    "net/ipv4/netfilter",
-					    l4proto->ctl_compat_table, NULL);
+					    pn->ctl_compat_table,
+					    NULL);
 		if (err == 0)
 			goto out;
-		nf_ct_unregister_sysctl(l4proto->ctl_table_header,
-					l4proto->ctl_table,
-					l4proto->ctl_table_users);
+
+		kfree(pn->ctl_compat_table);
+		pn->ctl_compat_table = NULL;
+		nf_ct_unregister_sysctl(&pn->ctl_table_header,
+					&pn->ctl_table,
+					&pn->users);
 	}
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 out:
 #endif /* CONFIG_SYSCTL */
 	return err;
 }
+EXPORT_SYMBOL_GPL(nf_ct_l4proto_register_sysctl);
 
-static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto)
+void nf_ct_l4proto_unregister_sysctl(struct net *net,
+				     struct nf_conntrack_l4proto *l4proto)
 {
+	struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto);
+	if (pn == NULL)
+		return;
 #ifdef CONFIG_SYSCTL
-	if (l4proto->ctl_table_header != NULL &&
-	    *l4proto->ctl_table_header != NULL)
-		nf_ct_unregister_sysctl(l4proto->ctl_table_header,
-					l4proto->ctl_table,
-					l4proto->ctl_table_users);
+	if (pn->ctl_table_header != NULL)
+		nf_ct_unregister_sysctl(&pn->ctl_table_header,
+					&pn->ctl_table,
+					&pn->users);
+
 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-	if (l4proto->ctl_compat_table_header != NULL)
-		nf_ct_unregister_sysctl(&l4proto->ctl_compat_table_header,
-					l4proto->ctl_compat_table, NULL);
+	if (l4proto->compat && pn->ctl_compat_header != NULL)
+		nf_ct_unregister_sysctl(&pn->ctl_compat_header,
+					&pn->ctl_compat_table,
+					NULL);
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
+#else
+	pn->users--;
 #endif /* CONFIG_SYSCTL */
 }
+EXPORT_SYMBOL_GPL(nf_ct_l4proto_unregister_sysctl);
 
 /* FIXME: Allow NULL functions and sub in pointers to generic for
    them. --RR */
-int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
+int nf_conntrack_l4proto_register(struct net *net,
+				  struct nf_conntrack_l4proto *l4proto)
 {
 	int ret = 0;
 
-	if (l4proto->l3proto >= PF_MAX)
-		return -EBUSY;
-
-	if ((l4proto->to_nlattr && !l4proto->nlattr_size)
-		|| (l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size))
-		return -EINVAL;
-
-	mutex_lock(&nf_ct_proto_mutex);
-	if (!nf_ct_protos[l4proto->l3proto]) {
-		/* l3proto may be loaded latter. */
-		struct nf_conntrack_l4proto __rcu **proto_array;
-		int i;
-
-		proto_array = kmalloc(MAX_NF_CT_PROTO *
-				      sizeof(struct nf_conntrack_l4proto *),
-				      GFP_KERNEL);
-		if (proto_array == NULL) {
-			ret = -ENOMEM;
+	if (net == &init_net) {
+		if (l4proto->l3proto >= PF_MAX)
+			return -EBUSY;
+
+		if ((l4proto->to_nlattr && !l4proto->nlattr_size)
+			|| (l4proto->tuple_to_nlattr && !l4proto->nlattr_tuple_size))
+			return -EINVAL;
+
+		mutex_lock(&nf_ct_proto_mutex);
+		if (!nf_ct_protos[l4proto->l3proto]) {
+			/* l3proto may be loaded latter. */
+			struct nf_conntrack_l4proto __rcu **proto_array;
+			int i;
+
+			proto_array = kmalloc(MAX_NF_CT_PROTO *
+					      sizeof(struct nf_conntrack_l4proto *),
+					      GFP_KERNEL);
+			if (proto_array == NULL) {
+				ret = -ENOMEM;
+				goto out_unlock;
+			}
+
+			for (i = 0; i < MAX_NF_CT_PROTO; i++)
+				RCU_INIT_POINTER(proto_array[i], &nf_conntrack_l4proto_generic);
+
+			/* Before making proto_array visible to lockless readers,
+			 * we must make sure its content is committed to memory.
+			 */
+			smp_wmb();
+
+			nf_ct_protos[l4proto->l3proto] = proto_array;
+		} else if (rcu_dereference_protected(
+				nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
+				lockdep_is_held(&nf_ct_proto_mutex)
+				) != &nf_conntrack_l4proto_generic) {
+			ret = -EBUSY;
 			goto out_unlock;
 		}
-
-		for (i = 0; i < MAX_NF_CT_PROTO; i++)
-			RCU_INIT_POINTER(proto_array[i], &nf_conntrack_l4proto_generic);
-
-		/* Before making proto_array visible to lockless readers,
-		 * we must make sure its content is committed to memory.
-		 */
-		smp_wmb();
-
-		nf_ct_protos[l4proto->l3proto] = proto_array;
-	} else if (rcu_dereference_protected(
-			nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
-			lockdep_is_held(&nf_ct_proto_mutex)
-			) != &nf_conntrack_l4proto_generic) {
-		ret = -EBUSY;
-		goto out_unlock;
-	}
-
-	ret = nf_ct_l4proto_register_sysctl(l4proto);
-	if (ret < 0)
-		goto out_unlock;
-
-	l4proto->nla_size = 0;
-	if (l4proto->nlattr_size)
-		l4proto->nla_size += l4proto->nlattr_size();
-	if (l4proto->nlattr_tuple_size)
-		l4proto->nla_size += 3 * l4proto->nlattr_tuple_size();
-
-	rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
-			   l4proto);
-
+
+		l4proto->nla_size = 0;
+		if (l4proto->nlattr_size)
+			l4proto->nla_size += l4proto->nlattr_size();
+		if (l4proto->nlattr_tuple_size)
+			l4proto->nla_size += 3 * l4proto->nlattr_tuple_size();
+
+		rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
+				   l4proto);
 out_unlock:
-	mutex_unlock(&nf_ct_proto_mutex);
-	return ret;
+		mutex_unlock(&nf_ct_proto_mutex);
+		if (ret < 0)
+			return ret;
+	}
+	if (l4proto->init_net) {
+		ret = l4proto->init_net(net, l4proto->compat);
+		if (ret < 0)
+			return ret;
+	}
+	return nf_ct_l4proto_register_sysctl(net, l4proto);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register);
 
-void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto)
+void nf_conntrack_l4proto_unregister(struct net *net,
+				     struct nf_conntrack_l4proto *l4proto)
 {
-	struct net *net;
-
-	BUG_ON(l4proto->l3proto >= PF_MAX);
-
-	mutex_lock(&nf_ct_proto_mutex);
-	BUG_ON(rcu_dereference_protected(
-			nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
-			lockdep_is_held(&nf_ct_proto_mutex)
-			) != l4proto);
-	rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
-			   &nf_conntrack_l4proto_generic);
-	nf_ct_l4proto_unregister_sysctl(l4proto);
-	mutex_unlock(&nf_ct_proto_mutex);
-
-	synchronize_rcu();
+	if (net == &init_net) {
+		BUG_ON(l4proto->l3proto >= PF_MAX);
+		mutex_lock(&nf_ct_proto_mutex);
+
+		BUG_ON(rcu_dereference_protected(
+				nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
+				lockdep_is_held(&nf_ct_proto_mutex)
+				) != l4proto);
+		rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
+				   &nf_conntrack_l4proto_generic);
+		mutex_unlock(&nf_ct_proto_mutex);
+
+		synchronize_rcu();
+	}
+	nf_ct_l4proto_unregister_sysctl(net, l4proto);
 
 	/* Remove all contrack entries for this protocol */
 	rtnl_lock();
-	for_each_net(net)
-		nf_ct_iterate_cleanup(net, kill_l4proto, l4proto);
+	nf_ct_iterate_cleanup(net, kill_l4proto, l4proto);
 	rtnl_unlock();
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_unregister);
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH 04/17] netfilter: add namespace support for l4proto_generic
From: Gao feng @ 2012-04-27  9:37 UTC (permalink / raw)
  To: pablo; +Cc: netfilter-devel, netdev, serge.hallyn, ebiederm, dlezcano,
	Gao feng
In-Reply-To: <1335519484-6089-1-git-send-email-gaofeng@cn.fujitsu.com>

From: Gao feng <gaofeng@cn.fujitus.com>

implement and export nf_conntrack_proto_generic_[init,fini],
nf_conntrack_[init,cleanup]_net call them to register or unregister
the sysctl of generic proto.

implement generic_net_init,it's used to initial the pernet
data for generic proto.

and use nf_generic_net.timeout to replace nf_ct_generic_timeout in
get_timeouts function.

Signed-off-by: Gao feng <gaofeng@cn.fujitus.com>
---
 include/net/netfilter/nf_conntrack_l4proto.h |    2 +
 include/net/netns/conntrack.h                |    6 +++
 net/netfilter/nf_conntrack_core.c            |    7 +++-
 net/netfilter/nf_conntrack_proto.c           |   20 ++++-----
 net/netfilter/nf_conntrack_proto_generic.c   |   55 ++++++++++++++++++++++++-
 5 files changed, 75 insertions(+), 15 deletions(-)

diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h
index e4ea46f..637c743 100644
--- a/include/net/netfilter/nf_conntrack_l4proto.h
+++ b/include/net/netfilter/nf_conntrack_l4proto.h
@@ -118,6 +118,8 @@ struct nf_conntrack_l4proto {
 
 /* Existing built-in generic protocol */
 extern struct nf_conntrack_l4proto nf_conntrack_l4proto_generic;
+extern int nf_conntrack_proto_generic_init(struct net *net);
+extern void nf_conntrack_proto_generic_fini(struct net *net);
 
 #define MAX_NF_CT_PROTO 256
 
diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h
index c329aad..f1728ed 100644
--- a/include/net/netns/conntrack.h
+++ b/include/net/netns/conntrack.h
@@ -20,7 +20,13 @@ struct nf_proto_net {
 	unsigned int		users;
 };
 
+struct nf_generic_net {
+	struct nf_proto_net pn;
+	unsigned int timeout;
+};
+
 struct nf_ip_net {
+	struct nf_generic_net   generic;
 #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
 	struct ctl_table_header *ctl_table_header;
 	struct ctl_table        *ctl_table;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index cf0747c..94eed7b 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1354,6 +1354,7 @@ static void nf_conntrack_cleanup_net(struct net *net)
 	}
 
 	nf_ct_free_hashtable(net->ct.hash, net->ct.htable_size);
+	nf_conntrack_proto_generic_fini(net);
 	nf_conntrack_timeout_fini(net);
 	nf_conntrack_ecache_fini(net);
 	nf_conntrack_tstamp_fini(net);
@@ -1589,9 +1590,13 @@ static int nf_conntrack_init_net(struct net *net)
 	ret = nf_conntrack_timeout_init(net);
 	if (ret < 0)
 		goto err_timeout;
+	ret = nf_conntrack_proto_generic_init(net);
+	if (ret < 0)
+		goto err_generic;
 
 	return 0;
-
+err_generic:
+	nf_conntrack_timeout_fini(net);
 err_timeout:
 	nf_conntrack_ecache_fini(net);
 err_ecache:
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index 065bff8..a0ec04d 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -287,10 +287,15 @@ EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister);
 static struct nf_proto_net *nf_ct_l4proto_net(struct net *net,
 					      struct nf_conntrack_l4proto *l4proto)
 {
-	if (l4proto->net_id)
-		return net_generic(net, *l4proto->net_id);
-	else
-		return NULL;
+	switch (l4proto->l4proto) {
+	case 255: /* l4proto_generic */
+		return (struct nf_proto_net *)&net->ct.proto.generic;
+	default:
+		if (l4proto->net_id)
+			return net_generic(net, *l4proto->net_id);
+		else
+			return NULL;
+	}
 }
 
 int nf_ct_l4proto_register_sysctl(struct net *net,
@@ -457,11 +462,6 @@ EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_unregister);
 int nf_conntrack_proto_init(void)
 {
 	unsigned int i;
-	int err;
-
-	err = nf_ct_l4proto_register_sysctl(&nf_conntrack_l4proto_generic);
-	if (err < 0)
-		return err;
 
 	for (i = 0; i < AF_MAX; i++)
 		rcu_assign_pointer(nf_ct_l3protos[i],
@@ -473,8 +473,6 @@ void nf_conntrack_proto_fini(void)
 {
 	unsigned int i;
 
-	nf_ct_l4proto_unregister_sysctl(&nf_conntrack_l4proto_generic);
-
 	/* free l3proto protocol tables */
 	for (i = 0; i < PF_MAX; i++)
 		kfree(nf_ct_protos[i]);
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
index d8923d5..cba718c 100644
--- a/net/netfilter/nf_conntrack_proto_generic.c
+++ b/net/netfilter/nf_conntrack_proto_generic.c
@@ -14,6 +14,11 @@
 
 static unsigned int nf_ct_generic_timeout __read_mostly = 600*HZ;
 
+static inline struct nf_generic_net *generic_pernet(struct net *net)
+{
+	return &net->ct.proto.generic;
+}
+
 static bool generic_pkt_to_tuple(const struct sk_buff *skb,
 				 unsigned int dataoff,
 				 struct nf_conntrack_tuple *tuple)
@@ -42,7 +47,7 @@ static int generic_print_tuple(struct seq_file *s,
 
 static unsigned int *generic_get_timeouts(struct net *net)
 {
-	return &nf_ct_generic_timeout;
+	return &(generic_pernet(net)->timeout);
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
@@ -110,7 +115,6 @@ static struct ctl_table_header *generic_sysctl_header;
 static struct ctl_table generic_sysctl_table[] = {
 	{
 		.procname	= "nf_conntrack_generic_timeout",
-		.data		= &nf_ct_generic_timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
@@ -121,7 +125,6 @@ static struct ctl_table generic_sysctl_table[] = {
 static struct ctl_table generic_compat_sysctl_table[] = {
 	{
 		.procname	= "ip_conntrack_generic_timeout",
-		.data		= &nf_ct_generic_timeout,
 		.maxlen		= sizeof(unsigned int),
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec_jiffies,
@@ -131,10 +134,39 @@ static struct ctl_table generic_compat_sysctl_table[] = {
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */
 
+static int generic_init_net(struct net *net, u_int8_t compat)
+{
+	struct nf_generic_net *gn = generic_pernet(net);
+	struct nf_proto_net *pn = (struct nf_proto_net *)gn;
+	gn->timeout = nf_ct_generic_timeout;
+#ifdef CONFIG_SYSCTL
+	pn->ctl_table = kmemdup(generic_sysctl_table,
+				sizeof(generic_sysctl_table),
+				GFP_KERNEL);
+	if (!pn->ctl_table)
+		return -ENOMEM;
+	pn->ctl_table[0].data = &gn->timeout;
+
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+	pn->ctl_compat_table = kmemdup(generic_compat_sysctl_table,
+				       sizeof(generic_compat_sysctl_table),
+				       GFP_KERNEL);
+	if (!pn->ctl_compat_table) {
+		kfree(pn->ctl_table);
+		pn->ctl_table = NULL;
+		return -ENOMEM;
+	}
+	pn->ctl_compat_table[0].data = &gn->timeout;
+#endif
+#endif
+	return 0;
+}
+
 struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
 {
 	.l3proto		= PF_UNSPEC,
 	.l4proto		= 255,
+	.compat			= 1,
 	.name			= "unknown",
 	.pkt_to_tuple		= generic_pkt_to_tuple,
 	.invert_tuple		= generic_invert_tuple,
@@ -158,4 +190,21 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
 	.ctl_compat_table	= generic_compat_sysctl_table,
 #endif
 #endif
+	.init_net		= generic_init_net,
 };
+
+int nf_conntrack_proto_generic_init(struct net *net)
+{
+	int ret = 0;
+	ret = generic_init_net(net, nf_conntrack_l4proto_generic.compat);
+	if (ret < 0)
+		return ret;
+	return nf_ct_l4proto_register_sysctl(net,
+					     &nf_conntrack_l4proto_generic);
+}
+
+void nf_conntrack_proto_generic_fini(struct net *net)
+{
+	nf_ct_l4proto_unregister_sysctl(net,
+					&nf_conntrack_l4proto_generic);
+}
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH 03/17] netfilter: add namespace support for l3proto
From: Gao feng @ 2012-04-27  9:37 UTC (permalink / raw)
  To: pablo; +Cc: netfilter-devel, netdev, serge.hallyn, ebiederm, dlezcano,
	Gao feng
In-Reply-To: <1335519484-6089-1-git-send-email-gaofeng@cn.fujitsu.com>

From: Gao feng <gaofeng@cn.fujitus.com>

-Add the struct net as param of nf_conntrack_l3proto_(un)register.
 register or unregister the l3proto only when the net is init_net.

-The new struct nf_ip_net is used to store the sysctl header and data
 of l3proto_ipv4,l4proto_tcp(6),l4proto_udp(6),l4proto_icmp(v6).
 because the protos such tcp and tcp6 use the same data,so making
 nf_ip_net as a field of netns_ct is the easiest way to manager it.

-nf_ct_l3proto_register_sysctl call init_net to initial the pernet data
 of l3proto.

-nf_ct_l3proto_net is used to get the pernet data of l3proto.

-export nf_conntrack_l3proto_(un)register

Signed-off-by: Gao feng <gaofeng@cn.fujitus.com>
---
 include/net/netfilter/nf_conntrack_l3proto.h |    6 +-
 include/net/netns/conntrack.h                |    8 ++
 net/netfilter/nf_conntrack_proto.c           |  130 ++++++++++++++++----------
 3 files changed, 93 insertions(+), 51 deletions(-)

diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h
index 9766005..d6df8c7 100644
--- a/include/net/netfilter/nf_conntrack_l3proto.h
+++ b/include/net/netfilter/nf_conntrack_l3proto.h
@@ -79,8 +79,10 @@ struct nf_conntrack_l3proto {
 extern struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[AF_MAX];
 
 /* Protocol registration. */
-extern int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto);
-extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto);
+extern int nf_conntrack_l3proto_register(struct net *net,
+					 struct nf_conntrack_l3proto *proto);
+extern void nf_conntrack_l3proto_unregister(struct net *net,
+					    struct nf_conntrack_l3proto *proto);
 extern struct nf_conntrack_l3proto *nf_ct_l3proto_find_get(u_int16_t l3proto);
 extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p);
 
diff --git a/include/net/netns/conntrack.h b/include/net/netns/conntrack.h
index 59afb87..c329aad 100644
--- a/include/net/netns/conntrack.h
+++ b/include/net/netns/conntrack.h
@@ -20,6 +20,13 @@ struct nf_proto_net {
 	unsigned int		users;
 };
 
+struct nf_ip_net {
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
+	struct ctl_table_header *ctl_table_header;
+	struct ctl_table        *ctl_table;
+#endif
+};
+
 struct netns_ct {
 	atomic_t		count;
 	unsigned int		expect_count;
@@ -38,6 +45,7 @@ struct netns_ct {
 	int			sysctl_tstamp;
 	int			sysctl_checksum;
 	unsigned int		sysctl_log_invalid; /* Log invalid packets */
+	struct nf_ip_net	proto;
 #ifdef CONFIG_SYSCTL
 	struct ctl_table_header	*sysctl_header;
 	struct ctl_table_header	*acct_sysctl_header;
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index 85d71e0..065bff8 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -170,84 +170,116 @@ static int kill_l4proto(struct nf_conn *i, void *data)
 	       nf_ct_l3num(i) == l4proto->l3proto;
 }
 
-static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto)
+static struct nf_ip_net *nf_ct_l3proto_net(struct net *net,
+					   struct nf_conntrack_l3proto *l3proto)
+{
+	if (l3proto->l3proto == PF_INET)
+		return &net->ct.proto;
+	else
+		return NULL;
+}
+
+static int nf_ct_l3proto_register_sysctl(struct net *net,
+					 struct nf_conntrack_l3proto *l3proto)
 {
 	int err = 0;
+	struct nf_ip_net *in = nf_ct_l3proto_net(net, l3proto);
 
-#ifdef CONFIG_SYSCTL
-	if (l3proto->ctl_table != NULL) {
-		err = nf_ct_register_sysctl(&l3proto->ctl_table_header,
+	if (in == NULL)
+		return 0;
+
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
+	if (in->ctl_table != NULL) {
+		err = nf_ct_register_sysctl(net,
+					    &in->ctl_table_header,
 					    l3proto->ctl_table_path,
-					    l3proto->ctl_table, NULL);
+					    in->ctl_table,
+					    NULL);
+		if (err < 0) {
+			kfree(in->ctl_table);
+			in->ctl_table = NULL;
+		}
 	}
 #endif
 	return err;
 }
 
-static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto)
+static void nf_ct_l3proto_unregister_sysctl(struct net *net,
+					    struct nf_conntrack_l3proto *l3proto)
 {
-#ifdef CONFIG_SYSCTL
-	if (l3proto->ctl_table_header != NULL)
-		nf_ct_unregister_sysctl(&l3proto->ctl_table_header,
-					l3proto->ctl_table, NULL);
+	struct nf_ip_net *in = nf_ct_l3proto_net(net, l3proto);
+
+	if (in == NULL)
+		return;
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
+	if (in->ctl_table_header != NULL)
+		nf_ct_unregister_sysctl(&in->ctl_table_header,
+					&in->ctl_table,
+					NULL);
 #endif
 }
 
-int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
+int nf_conntrack_l3proto_register(struct net *net,
+				  struct nf_conntrack_l3proto *proto)
 {
 	int ret = 0;
-	struct nf_conntrack_l3proto *old;
 
-	if (proto->l3proto >= AF_MAX)
-		return -EBUSY;
-
-	if (proto->tuple_to_nlattr && !proto->nlattr_tuple_size)
-		return -EINVAL;
-
-	mutex_lock(&nf_ct_proto_mutex);
-	old = rcu_dereference_protected(nf_ct_l3protos[proto->l3proto],
-					lockdep_is_held(&nf_ct_proto_mutex));
-	if (old != &nf_conntrack_l3proto_generic) {
-		ret = -EBUSY;
-		goto out_unlock;
-	}
+	if (net == &init_net) {
+		struct nf_conntrack_l3proto *old;
 
-	ret = nf_ct_l3proto_register_sysctl(proto);
-	if (ret < 0)
-		goto out_unlock;
+		if (proto->l3proto >= AF_MAX)
+			return -EBUSY;
+
+		if (proto->tuple_to_nlattr && !proto->nlattr_tuple_size)
+			return -EINVAL;
 
-	if (proto->nlattr_tuple_size)
-		proto->nla_size = 3 * proto->nlattr_tuple_size();
+		mutex_lock(&nf_ct_proto_mutex);
+		old = rcu_dereference_protected(nf_ct_l3protos[proto->l3proto],
+						lockdep_is_held(&nf_ct_proto_mutex));
+		if (old != &nf_conntrack_l3proto_generic) {
+			ret = -EBUSY;
+			goto out_unlock;
+		}
 
-	rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto);
+		if (proto->nlattr_tuple_size)
+			proto->nla_size = 3 * proto->nlattr_tuple_size();
 
+		rcu_assign_pointer(nf_ct_l3protos[proto->l3proto], proto);
 out_unlock:
-	mutex_unlock(&nf_ct_proto_mutex);
-	return ret;
+		mutex_unlock(&nf_ct_proto_mutex);
+		if (ret < 0)
+			return ret;
+	}
+	if (proto->init_net) {
+		ret = proto->init_net(net);
+		if (ret < 0)
+			return ret;
+	}
+	return nf_ct_l3proto_register_sysctl(net, proto);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register);
 
-void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
+void nf_conntrack_l3proto_unregister(struct net *net,
+				     struct nf_conntrack_l3proto *proto)
 {
-	struct net *net;
-
-	BUG_ON(proto->l3proto >= AF_MAX);
-
-	mutex_lock(&nf_ct_proto_mutex);
-	BUG_ON(rcu_dereference_protected(nf_ct_l3protos[proto->l3proto],
-					 lockdep_is_held(&nf_ct_proto_mutex)
-					 ) != proto);
-	rcu_assign_pointer(nf_ct_l3protos[proto->l3proto],
-			   &nf_conntrack_l3proto_generic);
-	nf_ct_l3proto_unregister_sysctl(proto);
-	mutex_unlock(&nf_ct_proto_mutex);
+	if (net == &init_net) {
+		BUG_ON(proto->l3proto >= AF_MAX);
+
+		mutex_lock(&nf_ct_proto_mutex);
+		BUG_ON(rcu_dereference_protected(nf_ct_l3protos[proto->l3proto],
+						 lockdep_is_held(&nf_ct_proto_mutex)
+						 ) != proto);
+		rcu_assign_pointer(nf_ct_l3protos[proto->l3proto],
+				   &nf_conntrack_l3proto_generic);
+		mutex_unlock(&nf_ct_proto_mutex);
 
-	synchronize_rcu();
+		synchronize_rcu();
+	}
+	nf_ct_l3proto_unregister_sysctl(net, proto);
 
 	/* Remove all contrack entries for this protocol */
 	rtnl_lock();
-	for_each_net(net)
-		nf_ct_iterate_cleanup(net, kill_l3proto, proto);
+	nf_ct_iterate_cleanup(net, kill_l3proto, proto);
 	rtnl_unlock();
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister);
-- 
1.7.7.6


^ 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