Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH] set fake_rtable's dst to NULL to avoid kernel Oops.
From: Stephen Hemminger @ 2012-04-17 15:52 UTC (permalink / raw)
  To: Peter Huang (Peng)
  Cc: 'David S. Miller', netdev, eric.dumazet, linux-kernel,
	ctrix+debianbugs, peter.huangpeng, harry.majun
In-Reply-To: <000001cd1c62$75d10de0$617329a0$%huangpeng@huawei.com>

On Tue, 17 Apr 2012 14:22:26 +0800
"Peter Huang (Peng)" <peter.huangpeng@huawei.com> wrote:

> When bridge is deleted before tap/vif device's delete, kernel may encounter an oops because of NULL reference to fake_rtable's dst.
> Set fake_rtable's dst to NULL before sending packets out can solve this problem.
> 
> 
> Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
> Signed-off-by: Peter Huang <peter.huangpeng@huawei.com>
> ---
> include/linux/netfilter_bridge.h |    8 ++++++++
>  net/bridge/br_forward.c          |    1 +
>  net/bridge/br_netfilter.c        |    6 +-----
>  3 files changed, 10 insertions(+), 5 deletions(-)
> 
> diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h
> index 0ddd161..70744fe 100644
> --- a/include/linux/netfilter_bridge.h
> +++ b/include/linux/netfilter_bridge.h
> @@ -104,9 +104,17 @@ struct bridge_skb_cb {
>  	} daddr;
>  };
>  
> +static inline void br_drop_fake_rtable(struct sk_buff *skb) {
> +	struct dst_entry *dst = skb_dst(skb);
> +	/* abuse fact that only fake_rtable has DST_NOPEER set */
> +	if (dst && (dst->flags & DST_NOPEER))
> +		skb_dst_drop(skb);
> +}

This check seems like a disaster waiting to happen when the next
change to DST table happens.

^ permalink raw reply

* Re: [patch] Fix handling of overlength pathname in AF_UNIX sun_path
From: Carlos O'Donell @ 2012-04-17 15:43 UTC (permalink / raw)
  To: Willy Tarreau
  Cc: Michael Kerrisk, netdev, Tetsuo Handa,
	linux-api-u79uwXL29TY76Z2rM5mHXA, yoshfuji-VfPWfsRibaP+Ru+s062T9g,
	David Miller, Jan Engelhardt, Alan Cox
In-Reply-To: <20120417105107.GA8614-K+wRfnb2/UA@public.gmane.org>

On Tue, Apr 17, 2012 at 6:51 AM, Willy Tarreau <w@1wt.eu> wrote:
> Hi Michael,
>
> On Tue, Apr 17, 2012 at 10:44:15PM +1200, Michael Kerrisk wrote:
> (...)
>> The accompanying patch changes unix_mkname() to ensure that a terminating
>> null byte is always located within the first 108 bytes of sun_path.
>> It does change the ABI for the former case where a pathname ran to 108
>> bytes without a null terminator: for that case, the call now fails with
>> the error -EINVAL. What are people's thoughts on applying this?
>
> My personal opinion is that (as you said), the risk of breaking existing
> apps is already fairly low, but we must not deliberately break existing
> apps. Eventhough there are currently a log, this is exactly what sysctls
> are made for. I would personally like to have a default limit to 107 chars
> + one zero, with a sysctl option to revert to current behaviour if ever it
> broke an application. In my opinion it's exactly comparable to the risk of
> breaking apps with mmap_min_addr : very low risk but must be covered by a
> workaround (sysctl).

To further the opinion that the risk is low:

The Open Solaris SUN_LEN macro uses strlen to compute the length.

The glibc SUN_LEN macro uses strlen to compute the length.

The Mac OS X libc SUN_LEN macro uses strlen to compute the length.

The linux man-pages project sets the user expectation that it is a
`null-terminated string' (circular argument).

I see every expectation from userspace/glibc that it should be 107 chars + '\0'.

Cheers,
Carlos.

^ permalink raw reply

* In tree firmware not kept up to date
From: Ian Campbell @ 2012-04-17 15:11 UTC (permalink / raw)
  To: netdev, linux-kernel
  Cc: Ian Jackson, Michael Chan, David Miller, Ben Hutchings

Hello,

What is the current policy wrt keeping the in-tree firmware updated
alongside the drivers?

I use CONFIG_FIRMWARE_IN_KERNEL but a couple of times[0] recently this
has failed me because the in-tree bnx2 driver requires
bnx2/bnx2-mips-09-6.2.1b.fw but the tree contains
firmware/bnx2/bnx2-mips-09-6.2.1a.fw.ihex and not 6.2.1b.

Is it a bug that bnx2 was updated without adding the new firmware or is
a bug that the obsolete firmware is still sitting in the tree?

Ian.

[0] It's possible the same thing and I've just tripped over it more than
once now.

^ permalink raw reply

* tg3 'No PHY devices' loading issue
From: Josh Boyer @ 2012-04-17 14:18 UTC (permalink / raw)
  To: Matt Carlson, Michael Chan; +Cc: netdev, linux-kernel

Hi Matt and Michael,

I'm seeing an odd issue with the tg3 driver on one of my development
machines.  I've tried kernels 3.2.10, 3.3.0, 3.3.1, 3.3.2 and 3.4-rc3
and they all seem to exhibit this issue now.  When the machine boots
and the tg3 driver is loaded, it fails to find a PHY and then reports
'Problem fetching invariants of chip'.  If I do a rmmod/modprobe of
tg3 after login, the probe seems to work fine and ethernet works as
expected.  You can see this in the dmesg below:

[jwboyer@vader ~]$ dmesg | grep tg3
[    2.084969] tg3.c:v3.122 (December 7, 2011)
[    2.093511] tg3 mdio bus: probed
[    2.093513] tg3 0000:03:00.0: No PHY devices
[    2.093531] tg3 0000:03:00.0: Problem fetching invariants of chip, aborting
[   90.824697] tg3.c:v3.122 (December 7, 2011)
[   90.857068] tg3 mdio bus: probed
[   90.862540] tg3 0000:03:00.0: eth0: Tigon3 [partno(BCM57788) rev 57780001] (PCI Express) MAC address 18:03:73:e6:01:88
[   90.862547] tg3 0000:03:00.0: eth0: attached PHY driver [Broadcom BCM57780] (mii_bus:phy_addr=300:01)
[   90.862552] tg3 0000:03:00.0: eth0: RXcsums[1] LinkChgREG[0] MIirq[0] ASF[0] TSOcap[1]
[   90.862557] tg3 0000:03:00.0: eth0: dma_rwctrl[76180000] dma_mask[64-bit]
[   90.919961] tg3 0000:03:00.0: irq 47 for MSI/MSI-X
[   91.863311] tg3 0000:03:00.0: p3p1: Link is down
[   92.864348] tg3 0000:03:00.0: p3p1: Link is up at 100 Mbps, full duplex
[   92.864352] tg3 0000:03:00.0: p3p1: Flow control is on for TX and on for RX

It has worked on some of the older kernels without the need for the
manual rmmod/modprobe step, so it seems to be somewhat timing related.
I'm not sure if there is a module load ordering issue, but that doesn't
seem to be the case.  I can't explain why a later modprobe would work
just fine though.

Do you have any thoughts on how to go about debugging/fixing this?  I'd
be happy to test and provide whatever information you need.

josh

^ permalink raw reply

* [PATCH 3/3] ehea: do not dereference possible NULL port
From: Thadeu Lima de Souza Cascardo @ 2012-04-17 14:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Thadeu Lima de Souza Cascardo, Joe Perches
In-Reply-To: <1334673715-16338-1-git-send-email-cascardo@linux.vnet.ibm.com>

port may be NULL when we receive an interrupt too early in the probe.

commit 8c4877a4128e7931077b024a891a4b284d8756a3, in particular, has
introduced this problem in the case of port state change interrupt.

This causes crashes in some situations:

[c000000f7ff7fd60] d000000008e223f0 .ehea_neq_tasklet+0x78/0x148 [ehea]
[c000000f7ff7fe00] c0000000000b6cac .tasklet_hi_action+0xdc/0x210
[c000000f7ff7fea0] c0000000000b7cc8 .__do_softirq+0x178/0x300
[c000000f7ff7ff90] c000000000022694 .call_do_softirq+0x14/0x24
[c000000f68ee7900] c000000000010e04 .do_softirq+0xec/0x110
[c000000f68ee79a0] c0000000000b789c .irq_exit+0xac/0xe0
[c000000f68ee7a20] c0000000000110bc .do_IRQ+0x114/0x2a8
[c000000f68ee7ae0] c00000000000553c hardware_interrupt_entry+0x18/0x1c
--- Exception: 501 (Hardware Interrupt) at c00000000000e6bc
.arch_local_irq_rest
ore+0x34/0x48
[link register   ] c000000000017a7c .cpu_idle+0x194/0x2f8
[c000000f68ee7dd0] c000000000017a70 .cpu_idle+0x188/0x2f8 (unreliable)
[c000000f68ee7e90] c00000000066b264 .start_secondary+0x3e4/0x524
[c000000f68ee7f90] c0000000000092e8 .start_secondary_prolog+0x10/0x14

cpu 0x8: Vector: 300 (Data Access) at [c000000f7ff7fa40]
    pc: d000000008e21fac: .ehea_parse_eqe+0x6c/0x438 [ehea]
    lr: d000000008e223f0: .ehea_neq_tasklet+0x78/0x148 [ehea]
    sp: c000000f7ff7fcc0
   msr: 8000000000009032
   dar: 8
 dsisr: 40000000
  current = 0xc000000f68efc0c0
  paca    = 0xc00000000ff41800
    pid   = 0, comm = kworker/0:1

Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com>
Cc: Joe Perches <joe@perches.com>
---
 drivers/net/ethernet/ibm/ehea/ehea_main.c |   13 +++++++------
 1 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index 35caeb5..5e64e66 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -1156,21 +1156,22 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
 	u8 ec;
 	u8 portnum;
 	struct ehea_port *port;
-	struct net_device *dev;
+	struct net_device *dev = NULL;
 
 	ec = EHEA_BMASK_GET(NEQE_EVENT_CODE, eqe);
 	portnum = EHEA_BMASK_GET(NEQE_PORTNUM, eqe);
 	port = ehea_get_port(adapter, portnum);
+	if (!port) {
+		pr_err("%s: unknown portnum %d, event %x\n",
+					adapter->ofdev->name, portnum, ec);
+		return;
+	}
+
 	dev = port->netdev;
 
 	switch (ec) {
 	case EHEA_EC_PORTSTATE_CHG:	/* port state change */
 
-		if (!port) {
-			netdev_err(dev, "unknown portnum %x\n", portnum);
-			break;
-		}
-
 		if (EHEA_BMASK_GET(NEQE_PORT_UP, eqe)) {
 			if (!netif_carrier_ok(dev)) {
 				ret = ehea_sense_port_attr(port);
-- 
1.7.4.4

^ permalink raw reply related

* [PATCH 2/3] ehea: fix promiscuous mode
From: Thadeu Lima de Souza Cascardo @ 2012-04-17 14:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Thadeu Lima de Souza Cascardo, Breno Leitao
In-Reply-To: <1334673715-16338-1-git-send-email-cascardo@linux.vnet.ibm.com>

commit a4910b744486254cfa61995954c118fb2283c4fd has broken promiscuous
mode, which is never set. port->promisc just reflects the last setting
of PROMISCUOUS mode to avoid doing an extra hypercall when it's already
set.

However, since it may fail because of hypervisor permissions, we should
still respect the multicast settings and not simply exit after setting
promiscuous mode.

Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com>
Cc: Breno Leitao <leitao@linux.vnet.ibm.com>
---
 drivers/net/ethernet/ibm/ehea/ehea_main.c |    6 +-----
 1 files changed, 1 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index 25d1258..35caeb5 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -1946,11 +1946,7 @@ static void ehea_set_multicast_list(struct net_device *dev)
 	struct netdev_hw_addr *ha;
 	int ret;
 
-	if (port->promisc) {
-		ehea_promiscuous(dev, 1);
-		return;
-	}
-	ehea_promiscuous(dev, 0);
+	ehea_promiscuous(dev, !!(dev->flags & IFF_PROMISC));
 
 	if (dev->flags & IFF_ALLMULTI) {
 		ehea_allmulti(dev, 1);
-- 
1.7.4.4

^ permalink raw reply related

* [PATCH 1/3] ehea: fix allmulticast support
From: Thadeu Lima de Souza Cascardo @ 2012-04-17 14:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Thadeu Lima de Souza Cascardo
In-Reply-To: <1334673715-16338-1-git-send-email-cascardo@linux.vnet.ibm.com>

There was a bug in the mask of regtype parameter for registering a
multicast filter. It was ignoring the scope bit, which was wrongly being
used for all filters. The SCOPE_ALL value adds a filter that allows all
multicast packets and ignores the MAC parameter, just what allmulticast
needs. The normals filters, however, should not use SCOPE_ALL.

Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@linux.vnet.ibm.com>
---
 drivers/net/ethernet/ibm/ehea/ehea_main.c |   24 +++++++++++++++---------
 drivers/net/ethernet/ibm/ehea/ehea_phyp.h |    2 +-
 2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index 3516e17..25d1258 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -290,16 +290,18 @@ static void ehea_update_bcmc_registrations(void)
 
 				arr[i].adh = adapter->handle;
 				arr[i].port_id = port->logical_port_id;
-				arr[i].reg_type = EHEA_BCMC_SCOPE_ALL |
-						  EHEA_BCMC_MULTICAST |
+				arr[i].reg_type = EHEA_BCMC_MULTICAST |
 						  EHEA_BCMC_UNTAGGED;
+				if (mc_entry->macaddr == 0)
+					arr[i].reg_type |= EHEA_BCMC_SCOPE_ALL;
 				arr[i++].macaddr = mc_entry->macaddr;
 
 				arr[i].adh = adapter->handle;
 				arr[i].port_id = port->logical_port_id;
-				arr[i].reg_type = EHEA_BCMC_SCOPE_ALL |
-						  EHEA_BCMC_MULTICAST |
+				arr[i].reg_type = EHEA_BCMC_MULTICAST |
 						  EHEA_BCMC_VLANID_ALL;
+				if (mc_entry->macaddr == 0)
+					arr[i].reg_type |= EHEA_BCMC_SCOPE_ALL;
 				arr[i++].macaddr = mc_entry->macaddr;
 				num_registrations -= 2;
 			}
@@ -1838,8 +1840,9 @@ static u64 ehea_multicast_reg_helper(struct ehea_port *port, u64 mc_mac_addr,
 	u64 hret;
 	u8 reg_type;
 
-	reg_type = EHEA_BCMC_SCOPE_ALL | EHEA_BCMC_MULTICAST
-		 | EHEA_BCMC_UNTAGGED;
+	reg_type = EHEA_BCMC_MULTICAST | EHEA_BCMC_UNTAGGED;
+	if (mc_mac_addr == 0)
+		reg_type |= EHEA_BCMC_SCOPE_ALL;
 
 	hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
 				     port->logical_port_id,
@@ -1847,8 +1850,9 @@ static u64 ehea_multicast_reg_helper(struct ehea_port *port, u64 mc_mac_addr,
 	if (hret)
 		goto out;
 
-	reg_type = EHEA_BCMC_SCOPE_ALL | EHEA_BCMC_MULTICAST
-		 | EHEA_BCMC_VLANID_ALL;
+	reg_type = EHEA_BCMC_MULTICAST | EHEA_BCMC_VLANID_ALL;
+	if (mc_mac_addr == 0)
+		reg_type |= EHEA_BCMC_SCOPE_ALL;
 
 	hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
 				     port->logical_port_id,
@@ -1898,7 +1902,7 @@ static void ehea_allmulti(struct net_device *dev, int enable)
 				netdev_err(dev,
 					   "failed enabling IFF_ALLMULTI\n");
 		}
-	} else
+	} else {
 		if (!enable) {
 			/* Disable ALLMULTI */
 			hret = ehea_multicast_reg_helper(port, 0, H_DEREG_BCMC);
@@ -1908,6 +1912,7 @@ static void ehea_allmulti(struct net_device *dev, int enable)
 				netdev_err(dev,
 					   "failed disabling IFF_ALLMULTI\n");
 		}
+	}
 }
 
 static void ehea_add_multicast_entry(struct ehea_port *port, u8 *mc_mac_addr)
@@ -2463,6 +2468,7 @@ static int ehea_down(struct net_device *dev)
 		return 0;
 
 	ehea_drop_multicast_list(dev);
+	ehea_allmulti(dev, 0);
 	ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
 
 	ehea_free_interrupts(dev);
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_phyp.h b/drivers/net/ethernet/ibm/ehea/ehea_phyp.h
index 52c456e..8364815 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_phyp.h
+++ b/drivers/net/ethernet/ibm/ehea/ehea_phyp.h
@@ -450,7 +450,7 @@ u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num,
 			    void *cb_addr);
 
 #define H_REGBCMC_PN            EHEA_BMASK_IBM(48, 63)
-#define H_REGBCMC_REGTYPE       EHEA_BMASK_IBM(61, 63)
+#define H_REGBCMC_REGTYPE       EHEA_BMASK_IBM(60, 63)
 #define H_REGBCMC_MACADDR       EHEA_BMASK_IBM(16, 63)
 #define H_REGBCMC_VLANID        EHEA_BMASK_IBM(52, 63)
 
-- 
1.7.4.4

^ permalink raw reply related

* [PATCH 0/3] ehea fixes for 3.4
From: Thadeu Lima de Souza Cascardo @ 2012-04-17 14:41 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Thadeu Lima de Souza Cascardo

Hi, Dave.

These are bug fixes for 3.4, including a crash and bad behaviour with
promiscuous and multicast.

Thanks.
Cascardo.

Thadeu Lima de Souza Cascardo (3):
  ehea: fix allmulticast support
  ehea: fix promiscuous mode
  ehea: do not dereference possible NULL port

 drivers/net/ethernet/ibm/ehea/ehea_main.c |   43 +++++++++++++++-------------
 drivers/net/ethernet/ibm/ehea/ehea_phyp.h |    2 +-
 2 files changed, 24 insertions(+), 21 deletions(-)

-- 
1.7.4.4

^ permalink raw reply

* Re: [PATCH 00/12] add namespace support for netfilter protos
From: Serge Hallyn @ 2012-04-17 14:35 UTC (permalink / raw)
  To: Gao feng; +Cc: pablo, netfilter-devel, netdev, ebiederm, dlezcano
In-Reply-To: <1334631383-12326-1-git-send-email-gaofeng@cn.fujitsu.com>

Quoting Gao feng (gaofeng@cn.fujitsu.com):
> 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.

Thanks for doing this, Gao, sounds good.

(The set has gotten better scrutiny than I could give it, so I'll
wait until at least the next submission to attempt a review)

-serge

^ permalink raw reply

* [PATCH] ethernet: fix checkpatch errors
From: Laura Vasilescu @ 2012-04-17 14:27 UTC (permalink / raw)
  To: linux-kernel; +Cc: netdev, eric.dumazet, nhorman, davem, Laura Vasilescu

Signed-off-by: Laura Vasilescu <laura@rosedu.org>
---
 net/ethernet/eth.c |   20 ++++++++++++--------
 1 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index bf10a31..5cca0ff 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -20,8 +20,8 @@
  *		Alan Cox	: eth_rebuild_header missing an htons and
  *				  minor other things.
  *		Tegge		: Arp bug fixes.
- *		Florian		: Removed many unnecessary functions, code cleanup
- *				  and changes for new arp and skbuff.
+ *		Florian		: Removed many unnecessary functions, code
+ *				  cleanup and changes for new arp and skbuff.
  *		Alan Cox	: Redid header building to reflect new format.
  *		Alan Cox	: ARP only when compiled with CONFIG_INET
  *		Greg Page	: 802.2 and SNAP stuff.
@@ -29,8 +29,9 @@
  *		Paul Gortmaker	: eth_copy_and_sum shouldn't csum padding.
  *		Alan Cox	: Protect against forwarding explosions with
  *				  older network drivers and IFF_ALLMULTI.
- *	Christer Weinigel	: Better rebuild header message.
- *             Andrew Morton    : 26Feb01: kill ether_setup() - use netdev_boot_setup().
+ *		Christer Weinigel: Better rebuild header message.
+ *		Andrew Morton   : 26Feb01: kill ether_setup() -
+ *				  use netdev_boot_setup().
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -178,8 +179,9 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
 	 *      seems to set IFF_PROMISC.
 	 */
 
-	else if (1 /*dev->flags&IFF_PROMISC */ ) {
-		if (unlikely(compare_ether_addr_64bits(eth->h_dest, dev->dev_addr)))
+	else if (1 /*dev->flags&IFF_PROMISC */) {
+		if (unlikely(compare_ether_addr_64bits(eth->h_dest,
+							dev->dev_addr)))
 			skb->pkt_type = PACKET_OTHERHOST;
 	}
 
@@ -233,7 +235,9 @@ EXPORT_SYMBOL(eth_header_parse);
  * @type: Ethernet type field
  * Create an Ethernet header template from the neighbour.
  */
-int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh, __be16 type)
+int eth_header_cache(const struct neighbour *neigh,
+			struct hh_cache *hh,
+			__be16 type)
 {
 	struct ethhdr *eth;
 	const struct net_device *dev = neigh->dev;
@@ -336,7 +340,7 @@ void ether_setup(struct net_device *dev)
 {
 	dev->header_ops		= &eth_header_ops;
 	dev->type		= ARPHRD_ETHER;
-	dev->hard_header_len 	= ETH_HLEN;
+	dev->hard_header_len	= ETH_HLEN;
 	dev->mtu		= ETH_DATA_LEN;
 	dev->addr_len		= ETH_ALEN;
 	dev->tx_queue_len	= 1000;	/* Ethernet wants good queues */
-- 
1.7.1

^ permalink raw reply related

* Re: [PATCH] SFC: Default to 'n' for Solarflare device.
From: Ben Hutchings @ 2012-04-17 14:18 UTC (permalink / raw)
  To: Tao Ma; +Cc: netdev, linux-net-drivers
In-Reply-To: <1334647992-6022-1-git-send-email-tm@tao.ma>

On Tue, 2012-04-17 at 15:33 +0800, Tao Ma wrote:
> From: Tao Ma <boyu.mt@taobao.com>
> 
> We make oldconfig every time when a new kernel arrives, but
> if we don't have such a device(I guess this is the most common
> case for a new device), the default value should be 'n' so
> that the kernel size we build doesn't grow up too much quickly.
> For anyone who has the device, it is OK for them to turn it on
> by themselves. And it goes with these Solarflare devices.
[...]

These are all sub-options of CONFIG_SFC, i.e. if you disable CONFIG_SFC
then they don't appear and if you set CONFIG_SFC=m then they only add
code to the module.

The default of y is correct.

Ben.

-- 
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: [RFC PATCH 2/2] l2tp: Introduce L2TPv3 IP encapsulation support for IPv6
From: James Chapman @ 2012-04-17 14:01 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: netdev, bcrl
In-Reply-To: <1334666934.2472.36.camel@edumazet-glaptop>

On 17/04/12 13:48, Eric Dumazet wrote:
> On Tue, 2012-04-17 at 13:29 +0100, James Chapman wrote:
>> L2TPv3 defines an IP encapsulation packet format where data is carried
>> directly over IP (no UDP). The kernel already has support for L2TP IP
>> encapsulation over IPv4 (l2tp_ip). This patch introduces support for L2TP
>> IP encapsulation over IPv6.
> 
> ...
>
>> +	/* Update stats */
>> +	if (err < 0) {
>> +		lsk->tx_errors++;
>> +	} else {
>> +		lsk->tx_packets++;
> 
> This is not SMP (especially on 32bit) safe, you dont own any lock

Thanks for catching this. This should be updating the stats in the l2tp
tunnel, not private data of the socket. We have the same SMP issues in
the l2tp tunnel/session stats code though. I'll submit a separate patch
to fix it.

Thanks for reviewing.


-- 
James Chapman
Katalix Systems Ltd
http://www.katalix.com
Catalysts for your Embedded Linux software development

^ permalink raw reply

* Re: [RFC PATCH 2/2] l2tp: Introduce L2TPv3 IP encapsulation support for IPv6
From: Eric Dumazet @ 2012-04-17 12:48 UTC (permalink / raw)
  To: James Chapman; +Cc: netdev, bcrl
In-Reply-To: <1334665766-11461-3-git-send-email-jchapman@katalix.com>

On Tue, 2012-04-17 at 13:29 +0100, James Chapman wrote:
> L2TPv3 defines an IP encapsulation packet format where data is carried
> directly over IP (no UDP). The kernel already has support for L2TP IP
> encapsulation over IPv4 (l2tp_ip). This patch introduces support for L2TP
> IP encapsulation over IPv6.

...

> +	/* Check if the address belongs to the host. */
> +	if (addr_type != IPV6_ADDR_ANY) {
> +		struct net_device *dev = NULL;
> +
> +		if (addr_type & IPV6_ADDR_LINKLOCAL) {
> +			if (addr_len >= sizeof(struct sockaddr_in6) &&
> +			    addr->l2tp_scope_id) {
> +				/* Override any existing binding, if another
> +				 * one is supplied by user.
> +				 */
> +				sk->sk_bound_dev_if = addr->l2tp_scope_id;
> +			}
> +
> +			/* Binding to link-local address requires an
> +			   interface */
> +			if (!sk->sk_bound_dev_if)
> +				goto out_unlock;
> +
> +			err = -ENODEV;
> +			rcu_read_lock();
> +			dev = dev_get_by_index_rcu(sock_net(sk),
> +						   sk->sk_bound_dev_if);
> +			rcu_read_unlock();

			Here you can not dereference dev, since it can disappear after
rcu_read_unlock()

> +			if (!dev)
> +				goto out_unlock;
> +		}
> +
> +		/* ipv4 addr of the socket is invalid.  Only the
> +		 * unspecified and mapped address have a v4 equivalent.
> +		 */
> +		v4addr = LOOPBACK4_IPV6;
> +		err = -EADDRNOTAVAIL;

	So I suspect a potential problem here :

> +		if (!ipv6_chk_addr(sock_net(sk), &addr->l2tp_addr, dev, 0))
> +			goto out_unlock;
> +	}
> +

...

> +back_from_confirm:
> +	lock_sock(sk);
> +	err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
> +			      ulen, transhdrlen, hlimit, tclass, opt,
> +			      &fl6, (struct rt6_info *)dst,
> +			      msg->msg_flags, dontfrag);
> +	if (err)
> +		ip6_flush_pending_frames(sk);
> +	else if (!(msg->msg_flags & MSG_MORE))
> +		err = l2tp_ip6_push_pending_frames(sk);
> +	release_sock(sk);
> +done:
> +	dst_release(dst);
> +out:
> +	fl6_sock_release(flowlabel);
> +
> +	/* Update stats */
> +	if (err < 0) {
> +		lsk->tx_errors++;
> +	} else {
> +		lsk->tx_packets++;

This is not SMP (especially on 32bit) safe, you dont own any lock

> +		lsk->tx_bytes += len;
> +	}
> +
> +	return err < 0 ? err : len;
> +
> +do_confirm:
> +	dst_confirm(dst);
> +	if (!(msg->msg_flags & MSG_PROBE) || len)
> +		goto back_from_confirm;
> +	err = 0;
> +	goto done;
> +}
> +

^ permalink raw reply

* rp_filter disabled (all = 0) and still get "martians"
From: Markku Savela @ 2012-04-17 12:28 UTC (permalink / raw)
  To: netdev

I've been trying to some IPsec with Click, and I thought
tunneling would be trivial: just enable forwarding
and disable rp_filters -- no such luck! I've

eth1: 192.168.0.14/24
tun0: 10.0.0.1/8

What tun0 basicly tries to do, is to add

dst 10.0.0.2 -> tun0 -> ...
   ... User space adds tunnel
   ...   dst=192.168.0.15
   ...   src=192.168.0.14
   ... and returns packet to tun0
-> tun0 -> expect it to be routed to eth1

But, I still get it dropped as martian, maybe
due to src address? (Routes fine if src is not
192.168.0.14, like 192.168.1.14).

[ 2801.224711] martian source 192.168.0.15 from 192.168.0.14, on dev tun0

Is there any way to disable this "feature"?

And, even better, it would be wonderful, if
specifying src=0.0.0.0 would automatically
fill in the correct source depending on the
final interface.

I'm doing this on

2.6.38-14-generic #58-Ubuntu SMP Tue Mar 27 18:48:46 UTC 2012 i686 i686 
i386 GNU/Linux

^ permalink raw reply

* Re: [PATCH 08/11] nfs: disable data cache revalidation for swapfiles
From: Mel Gorman @ 2012-04-17 12:40 UTC (permalink / raw)
  To: Fred Isaman
  Cc: Andrew Morton, Linux-MM, Linux-Netdev, Linux-NFS, LKML,
	David Miller, Trond Myklebust, Neil Brown, Christoph Hellwig,
	Peter Zijlstra, Mike Christie, Eric B Munson
In-Reply-To: <CADnza444dTr=JEtqpL5wxHRNkEc7vBz1qq9TL7Z+5h749vNawg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

> On Mon, Apr 16, 2012 at 9:44 AM, Mel Gorman <mgorman-l3A5Bk7waGM@public.gmane.org> wrote:
> > On Mon, Apr 16, 2012 at 09:10:04AM -0400, Fred Isaman wrote:
> >> > <SNIP>
> >> > -static struct nfs_page *nfs_page_find_request_locked(struct page *page)
> >> > +static struct nfs_page *
> >> > +nfs_page_find_request_locked(struct nfs_inode *nfsi, struct page *page)
> >> >  {
> >> >        struct nfs_page *req = NULL;
> >> >
> >> > -       if (PagePrivate(page)) {
> >> > +       if (PagePrivate(page))
> >> >                req = (struct nfs_page *)page_private(page);
> >> > -               if (req != NULL)
> >> > -                       kref_get(&req->wb_kref);
> >> > +       else if (unlikely(PageSwapCache(page))) {
> >> > +               struct nfs_page *freq, *t;
> >> > +
> >> > +               /* Linearly search the commit list for the correct req */
> >> > +               list_for_each_entry_safe(freq, t, &nfsi->commit_list, wb_list) {
> >> > +                       if (freq->wb_page == page) {
> >> > +                               req = freq;
> >> > +                               break;
> >> > +                       }
> >> > +               }
> >> > +
> >> > +               BUG_ON(req == NULL);
> >>
> >> I suspect I am missing something, but why is it guaranteed that the
> >> req is on the commit list?
> >>
> >
> > It's a fair question and a statement about what I expected to happen.
> > The commit list replaces the nfs_page_tree radix tree that used to exist
> > and my understanding was that the req would exist in the radix tree until
> > the swap IO was completed. I expected it to be the same for the commit
> > list and the BUG_ON was based on that expectation. Are there cases where
> > the req would not be found?
> >
> 
> A req is on the commit list only if it actually needs to be scheduled
> for COMMIT. In other words, only after it has been sent via WRITE and
> the server did not return NFS_FILE_SYNC.
> 
> Thus dirtying a page, then trying to touch it again before the WRITE
> is sent will not find the corresponding req on the commit_list.

Thanks for the explanation. I'll remove the BUG_ON

-- 
Mel Gorman
SUSE Labs
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" 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

* Re: [PATCH] tcp: fix tcp_grow_window() for large incoming frames
From: Neal Cardwell @ 2012-04-17 12:40 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: David Miller, Tom Herbert, netdev
In-Reply-To: <1334654887.2472.28.camel@edumazet-glaptop>

On Tue, Apr 17, 2012 at 5:28 AM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> tcp_grow_window() has to grow rcv_ssthresh up to window_clamp, allowing
> sender to increase its window.
>
> tcp_grow_window() still assumes a tcp frame is under MSS, but its no
> longer true with LRO/GRO.
>
> This patch fixes one of the performance issue we noticed with GRO on.
>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> Cc: Neal Cardwell <ncardwell@google.com>
> Cc: Tom Herbert <therbert@google.com>
> ---
> Sorry for the delay, this was discussed a long time ago.
>
>  net/ipv4/tcp_input.c |    1 +
>  1 file changed, 1 insertion(+)

Acked-by: Neal Cardwell <ncardwell@google.com>

^ permalink raw reply

* [RFC PATCH 0/2] l2tp: Introduce L2TPv3 IP encapsulation for IPv6
From: James Chapman @ 2012-04-17 12:29 UTC (permalink / raw)
  To: netdev; +Cc: bcrl

The following patch series adds support for L2TPv3 IP encapsulation
over IPv6. Support for L2TPv3 IP encap over IPv4 is already present in
the kernel (l2tp_ip). The new code is derived from l2tp_ip and
ipv6/raw. I'm posting as an RFC to get feedback on the approach being
used, because the implementation uses several ipv6 functions which are
not currently exported.

A patch series adding IPv6 support for L2TPv2 and L2TPv3 UDP
encapsulation is being worked on by Ben LaHaise and is independent of
these changes.

James Chapman (2):
  ipv6: Export ipv6 functions for use by other protocols
  l2tp: Introduce L2TPv3 IP encapsulation support for IPv6

 include/linux/l2tp.h     |   17 +
 net/ipv6/datagram.c      |    4 +
 net/ipv6/exthdrs.c       |    1 +
 net/ipv6/ip6_flowlabel.c |    1 +
 net/ipv6/ip6_output.c    |    3 +
 net/l2tp/Makefile        |    1 +
 net/l2tp/l2tp_ip6.c      |  808 ++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 835 insertions(+), 0 deletions(-)
 create mode 100644 net/l2tp/l2tp_ip6.c

^ permalink raw reply

* [RFC PATCH 1/2] ipv6: Export ipv6 functions for use by other protocols
From: James Chapman @ 2012-04-17 12:29 UTC (permalink / raw)
  To: netdev; +Cc: bcrl

For implementing other protocols on top of IPv6, such as L2TPv3's IP
encapsulation over ipv6, we'd like to call some IPv6 functions which
are not currently exported.
---
 net/ipv6/datagram.c      |    4 ++++
 net/ipv6/exthdrs.c       |    1 +
 net/ipv6/ip6_flowlabel.c |    1 +
 net/ipv6/ip6_output.c    |    3 +++
 4 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 7fba35a..b8b61ac 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -22,6 +22,7 @@
 #include <linux/ipv6.h>
 #include <linux/route.h>
 #include <linux/slab.h>
+#include <linux/export.h>
 
 #include <net/ipv6.h>
 #include <net/ndisc.h>
@@ -202,6 +203,7 @@ out:
 	fl6_sock_release(flowlabel);
 	return err;
 }
+EXPORT_SYMBOL_GPL(ip6_datagram_connect);
 
 void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
 		     __be16 port, u32 info, u8 *payload)
@@ -414,6 +416,7 @@ out_free_skb:
 out:
 	return err;
 }
+EXPORT_SYMBOL_GPL(ipv6_recv_error);
 
 /*
  *	Handle IPV6_RECVPATHMTU
@@ -868,3 +871,4 @@ int datagram_send_ctl(struct net *net, struct sock *sk,
 exit_f:
 	return err;
 }
+EXPORT_SYMBOL_GPL(datagram_send_ctl);
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index aa0a51e..a93bd23 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -883,6 +883,7 @@ struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
 
 	return opt;
 }
+EXPORT_SYMBOL_GPL(ipv6_fixup_options);
 
 /**
  * fl6_update_dst - update flowi destination address with info given
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 1dd6329..cb43df6 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -294,6 +294,7 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space,
 	opt_space->opt_flen = fopt->opt_flen;
 	return opt_space;
 }
+EXPORT_SYMBOL_GPL(fl6_merge_options);
 
 static unsigned long check_linger(unsigned long ttl)
 {
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index b7ca461..2a16aa9 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1535,6 +1535,7 @@ error:
 	IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
 	return err;
 }
+EXPORT_SYMBOL_GPL(ip6_append_data);
 
 static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np)
 {
@@ -1638,6 +1639,7 @@ error:
 	IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
 	goto out;
 }
+EXPORT_SYMBOL_GPL(ip6_push_pending_frames);
 
 void ip6_flush_pending_frames(struct sock *sk)
 {
@@ -1652,3 +1654,4 @@ void ip6_flush_pending_frames(struct sock *sk)
 
 	ip6_cork_release(inet_sk(sk), inet6_sk(sk));
 }
+EXPORT_SYMBOL_GPL(ip6_flush_pending_frames);
-- 
1.7.0.4

^ permalink raw reply related

* [RFC PATCH 2/2] l2tp: Introduce L2TPv3 IP encapsulation support for IPv6
From: James Chapman @ 2012-04-17 12:29 UTC (permalink / raw)
  To: netdev; +Cc: bcrl

L2TPv3 defines an IP encapsulation packet format where data is carried
directly over IP (no UDP). The kernel already has support for L2TP IP
encapsulation over IPv4 (l2tp_ip). This patch introduces support for L2TP
IP encapsulation over IPv6.

---
 include/linux/l2tp.h |   17 +
 net/l2tp/Makefile    |    1 +
 net/l2tp/l2tp_ip6.c  |  808 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 826 insertions(+), 0 deletions(-)
 create mode 100644 net/l2tp/l2tp_ip6.c

diff --git a/include/linux/l2tp.h b/include/linux/l2tp.h
index 16b8347..7eab668 100644
--- a/include/linux/l2tp.h
+++ b/include/linux/l2tp.h
@@ -11,6 +11,7 @@
 #include <linux/socket.h>
 #ifdef __KERNEL__
 #include <linux/in.h>
+#include <linux/in6.h>
 #else
 #include <netinet/in.h>
 #endif
@@ -39,6 +40,22 @@ struct sockaddr_l2tpip {
 			      sizeof(__u32)];
 };
 
+/**
+ * struct sockaddr_l2tpip6 - the sockaddr structure for L2TP-over-IPv6 sockets
+ * @l2tp_family:  address family number AF_L2TPIP.
+ * @l2tp_addr:    protocol specific address information
+ * @l2tp_conn_id: connection id of tunnel
+ */
+struct sockaddr_l2tpip6 {
+	/* The first fields must match struct sockaddr_in6 */
+	__kernel_sa_family_t l2tp_family; /* AF_INET6 */
+	__be16		l2tp_unused;	/* INET port number (unused) */
+	__be32		l2tp_flowinfo;	/* IPv6 flow information */
+	struct in6_addr	l2tp_addr;	/* IPv6 address */
+	__u32		l2tp_scope_id;	/* scope id (new in RFC2553) */
+	__u32		l2tp_conn_id;	/* Connection ID of tunnel */
+};
+
 /*****************************************************************************
  *  NETLINK_GENERIC netlink family.
  *****************************************************************************/
diff --git a/net/l2tp/Makefile b/net/l2tp/Makefile
index 110e7bc..a6378eb 100644
--- a/net/l2tp/Makefile
+++ b/net/l2tp/Makefile
@@ -10,3 +10,4 @@ obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_IP)) += l2tp_ip.o
 obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_V3)) += l2tp_netlink.o
 obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_ETH)) += l2tp_eth.o
 obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_DEBUGFS)) += l2tp_debugfs.o
+obj-$(subst y,$(CONFIG_L2TP),$(CONFIG_L2TP_IP)) += l2tp_ip6.o
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
new file mode 100644
index 0000000..4711014
--- /dev/null
+++ b/net/l2tp/l2tp_ip6.c
@@ -0,0 +1,808 @@
+/*
+ * L2TPv3 IP encapsulation support for IPv6
+ *
+ * Copyright (c) 2012 Katalix Systems Ltd
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/icmp.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/random.h>
+#include <linux/socket.h>
+#include <linux/l2tp.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <net/sock.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/udp.h>
+#include <net/inet_common.h>
+#include <net/inet_hashtables.h>
+#include <net/tcp_states.h>
+#include <net/protocol.h>
+#include <net/xfrm.h>
+
+#include <net/transp_v6.h>
+#include <net/addrconf.h>
+#include <net/ip6_route.h>
+
+#include "l2tp_core.h"
+
+struct l2tp_ip6_sock {
+	/* inet_sock has to be the first member of l2tp_ip6_sock */
+	struct inet_sock	inet;
+
+	__u32			conn_id;
+	__u32			peer_conn_id;
+
+	__u64			tx_packets;
+	__u64			tx_bytes;
+	__u64			tx_errors;
+	__u64			rx_packets;
+	__u64			rx_bytes;
+	__u64			rx_errors;
+
+	/* ipv6_pinfo has to be the last member of l2tp_ip6_sock, see
+	   inet6_sk_generic */
+	struct ipv6_pinfo	inet6;
+};
+
+static DEFINE_RWLOCK(l2tp_ip6_lock);
+static struct hlist_head l2tp_ip6_table;
+static struct hlist_head l2tp_ip6_bind_table;
+
+static inline struct l2tp_ip6_sock *l2tp_ip6_sk(const struct sock *sk)
+{
+	return (struct l2tp_ip6_sock *)sk;
+}
+
+static struct sock *__l2tp_ip6_bind_lookup(struct net *net, struct in6_addr *laddr,
+					   int dif, u32 tunnel_id)
+{
+	struct hlist_node *node;
+	struct sock *sk;
+
+	sk_for_each_bound(sk, node, &l2tp_ip6_bind_table) {
+		struct in6_addr *addr = inet6_rcv_saddr(sk);
+		struct l2tp_ip6_sock *l2tp = l2tp_ip6_sk(sk);
+
+		if (l2tp == NULL)
+			continue;
+
+		if ((l2tp->conn_id == tunnel_id) &&
+		    net_eq(sock_net(sk), net) &&
+		    !(addr && ipv6_addr_equal(addr, laddr)) &&
+		    !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif))
+			goto found;
+	}
+
+	sk = NULL;
+found:
+	return sk;
+}
+
+static inline struct sock *l2tp_ip6_bind_lookup(struct net *net, struct in6_addr *laddr,
+						int dif, u32 tunnel_id)
+{
+	struct sock *sk = __l2tp_ip6_bind_lookup(net, laddr, dif, tunnel_id);
+	if (sk)
+		sock_hold(sk);
+
+	return sk;
+}
+
+/* When processing receive frames, there are two cases to
+ * consider. Data frames consist of a non-zero session-id and an
+ * optional cookie. Control frames consist of a regular L2TP header
+ * preceded by 32-bits of zeros.
+ *
+ * L2TPv3 Session Header Over IP
+ *
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                           Session ID                          |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |               Cookie (optional, maximum 64 bits)...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *                                                                 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * L2TPv3 Control Message Header Over IP
+ *
+ *  0                   1                   2                   3
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                      (32 bits of zeros)                       |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |T|L|x|x|S|x|x|x|x|x|x|x|  Ver  |             Length            |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |                     Control Connection ID                     |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |               Ns              |               Nr              |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * All control frames are passed to userspace.
+ */
+static int l2tp_ip6_recv(struct sk_buff *skb)
+{
+	struct sock *sk;
+	u32 session_id;
+	u32 tunnel_id;
+	unsigned char *ptr, *optr;
+	struct l2tp_session *session;
+	struct l2tp_tunnel *tunnel = NULL;
+	int length;
+	int offset;
+
+	/* Point to L2TP header */
+	optr = ptr = skb->data;
+
+	if (!pskb_may_pull(skb, 4))
+		goto discard;
+
+	session_id = ntohl(*((__be32 *) ptr));
+	ptr += 4;
+
+	/* RFC3931: L2TP/IP packets have the first 4 bytes containing
+	 * the session_id. If it is 0, the packet is a L2TP control
+	 * frame and the session_id value can be discarded.
+	 */
+	if (session_id == 0) {
+		__skb_pull(skb, 4);
+		goto pass_up;
+	}
+
+	/* Ok, this is a data packet. Lookup the session. */
+	session = l2tp_session_find(&init_net, NULL, session_id);
+	if (session == NULL)
+		goto discard;
+
+	tunnel = session->tunnel;
+	if (tunnel == NULL)
+		goto discard;
+
+	/* Trace packet contents, if enabled */
+	if (tunnel->debug & L2TP_MSG_DATA) {
+		length = min(32u, skb->len);
+		if (!pskb_may_pull(skb, length))
+			goto discard;
+
+		printk(KERN_DEBUG "%s: ip recv: ", tunnel->name);
+
+		offset = 0;
+		do {
+			printk(" %02X", ptr[offset]);
+		} while (++offset < length);
+
+		printk("\n");
+	}
+
+	l2tp_recv_common(session, skb, ptr, optr, 0, skb->len,
+			 tunnel->recv_payload_hook);
+	return 0;
+
+pass_up:
+	/* Get the tunnel_id from the L2TP header */
+	if (!pskb_may_pull(skb, 12))
+		goto discard;
+
+	if ((skb->data[0] & 0xc0) != 0xc0)
+		goto discard;
+
+	tunnel_id = ntohl(*(__be32 *) &skb->data[4]);
+	tunnel = l2tp_tunnel_find(&init_net, tunnel_id);
+	if (tunnel != NULL)
+		sk = tunnel->sock;
+	else {
+		struct ipv6hdr *iph = ipv6_hdr(skb);
+
+		read_lock_bh(&l2tp_ip6_lock);
+		sk = __l2tp_ip6_bind_lookup(&init_net, &iph->daddr,
+					    0, tunnel_id);
+		read_unlock_bh(&l2tp_ip6_lock);
+	}
+
+	if (sk == NULL)
+		goto discard;
+
+	sock_hold(sk);
+
+	if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
+		goto discard_put;
+
+	nf_reset(skb);
+
+	return sk_receive_skb(sk, skb, 1);
+
+discard_put:
+	sock_put(sk);
+
+discard:
+	kfree_skb(skb);
+	return 0;
+}
+
+static int l2tp_ip6_open(struct sock *sk)
+{
+	/* Prevent autobind. We don't have ports. */
+	inet_sk(sk)->inet_num = IPPROTO_L2TP;
+
+	write_lock_bh(&l2tp_ip6_lock);
+	sk_add_node(sk, &l2tp_ip6_table);
+	write_unlock_bh(&l2tp_ip6_lock);
+
+	return 0;
+}
+
+static void l2tp_ip6_close(struct sock *sk, long timeout)
+{
+	write_lock_bh(&l2tp_ip6_lock);
+	hlist_del_init(&sk->sk_bind_node);
+	sk_del_node_init(sk);
+	write_unlock_bh(&l2tp_ip6_lock);
+
+	sk_common_release(sk);
+}
+
+static void l2tp_ip6_destroy_sock(struct sock *sk)
+{
+	lock_sock(sk);
+	ip6_flush_pending_frames(sk);
+	release_sock(sk);
+
+	inet6_destroy_sock(sk);
+}
+
+static int l2tp_ip6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+	struct inet_sock *inet = inet_sk(sk);
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct sockaddr_l2tpip6 *addr = (struct sockaddr_l2tpip6 *) uaddr;
+	__be32 v4addr = 0;
+	int addr_type;
+	int err;
+
+	if (addr_len < sizeof(*addr))
+		return -EINVAL;
+
+	addr_type = ipv6_addr_type(&addr->l2tp_addr);
+
+	/* l2tp_ip6 sockets are IPv6 only */
+	if (addr_type == IPV6_ADDR_MAPPED)
+		return -EADDRNOTAVAIL;
+
+	/* L2TP is point-point, not multicast */
+	if (addr_type & IPV6_ADDR_MULTICAST)
+		return -EADDRNOTAVAIL;
+
+	err = -EADDRINUSE;
+	read_lock_bh(&l2tp_ip6_lock);
+	if (__l2tp_ip6_bind_lookup(&init_net, &addr->l2tp_addr,
+				   sk->sk_bound_dev_if, addr->l2tp_conn_id))
+		goto out_in_use;
+	read_unlock_bh(&l2tp_ip6_lock);
+
+	lock_sock(sk);
+
+	err = -EINVAL;
+	if (sk->sk_state != TCP_CLOSE)
+		goto out_unlock;
+
+	/* Check if the address belongs to the host. */
+	if (addr_type != IPV6_ADDR_ANY) {
+		struct net_device *dev = NULL;
+
+		if (addr_type & IPV6_ADDR_LINKLOCAL) {
+			if (addr_len >= sizeof(struct sockaddr_in6) &&
+			    addr->l2tp_scope_id) {
+				/* Override any existing binding, if another
+				 * one is supplied by user.
+				 */
+				sk->sk_bound_dev_if = addr->l2tp_scope_id;
+			}
+
+			/* Binding to link-local address requires an
+			   interface */
+			if (!sk->sk_bound_dev_if)
+				goto out_unlock;
+
+			err = -ENODEV;
+			rcu_read_lock();
+			dev = dev_get_by_index_rcu(sock_net(sk),
+						   sk->sk_bound_dev_if);
+			rcu_read_unlock();
+			if (!dev)
+				goto out_unlock;
+		}
+
+		/* ipv4 addr of the socket is invalid.  Only the
+		 * unspecified and mapped address have a v4 equivalent.
+		 */
+		v4addr = LOOPBACK4_IPV6;
+		err = -EADDRNOTAVAIL;
+		if (!ipv6_chk_addr(sock_net(sk), &addr->l2tp_addr, dev, 0))
+			goto out_unlock;
+	}
+
+	inet->inet_rcv_saddr = inet->inet_saddr = v4addr;
+	np->rcv_saddr = addr->l2tp_addr;
+	np->saddr = addr->l2tp_addr;
+
+	l2tp_ip6_sk(sk)->conn_id = addr->l2tp_conn_id;
+
+	write_lock_bh(&l2tp_ip6_lock);
+	sk_add_bind_node(sk, &l2tp_ip6_bind_table);
+	sk_del_node_init(sk);
+	write_unlock_bh(&l2tp_ip6_lock);
+
+	err = 0;
+out_unlock:
+	release_sock(sk);
+	return err;
+
+out_in_use:
+	read_unlock_bh(&l2tp_ip6_lock);
+	return err;
+}
+
+static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+{
+	struct sockaddr_l2tpip6 *lsa = (struct sockaddr_l2tpip6 *) uaddr;
+	struct sockaddr_in6	*usin = (struct sockaddr_in6 *) uaddr;
+	struct in6_addr	*daddr;
+	int	addr_type;
+	int rc;
+
+	if (addr_len < sizeof(*lsa))
+		return -EINVAL;
+
+	addr_type = ipv6_addr_type(&usin->sin6_addr);
+	if (addr_type & IPV6_ADDR_MULTICAST)
+		return -EINVAL;
+
+	if (addr_type & IPV6_ADDR_MAPPED) {
+		daddr = &usin->sin6_addr;
+		if (ipv4_is_multicast(daddr->s6_addr32[3]))
+			return -EINVAL;
+	}
+
+	rc = ip6_datagram_connect(sk, uaddr, addr_len);
+
+	lock_sock(sk);
+
+	l2tp_ip6_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;
+
+	write_lock_bh(&l2tp_ip6_lock);
+	hlist_del_init(&sk->sk_bind_node);
+	sk_add_bind_node(sk, &l2tp_ip6_bind_table);
+	write_unlock_bh(&l2tp_ip6_lock);
+
+	release_sock(sk);
+
+	return rc;
+}
+
+static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr,
+			    int *uaddr_len, int peer)
+{
+	struct sockaddr_l2tpip6 *lsa = (struct sockaddr_l2tpip6 *)uaddr;
+	struct sock *sk = sock->sk;
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct l2tp_ip6_sock *lsk = l2tp_ip6_sk(sk);
+
+	lsa->l2tp_family = AF_INET6;
+	lsa->l2tp_flowinfo = 0;
+	lsa->l2tp_scope_id = 0;
+	if (peer) {
+		if (!lsk->peer_conn_id)
+			return -ENOTCONN;
+		lsa->l2tp_conn_id = lsk->peer_conn_id;
+		lsa->l2tp_addr = np->daddr;
+		if (np->sndflow)
+			lsa->l2tp_flowinfo = np->flow_label;
+	} else {
+		if (ipv6_addr_any(&np->rcv_saddr))
+			lsa->l2tp_addr = np->saddr;
+		else
+			lsa->l2tp_addr = np->rcv_saddr;
+
+		lsa->l2tp_conn_id = lsk->conn_id;
+	}
+	if (ipv6_addr_type(&lsa->l2tp_addr) & IPV6_ADDR_LINKLOCAL)
+		lsa->l2tp_scope_id = sk->sk_bound_dev_if;
+	*uaddr_len = sizeof(*lsa);
+	return 0;
+}
+
+static int l2tp_ip6_backlog_recv(struct sock *sk, struct sk_buff *skb)
+{
+	int rc;
+
+	/* Charge it to the socket, dropping if the queue is full. */
+	rc = sock_queue_rcv_skb(sk, skb);
+	if (rc < 0)
+		goto drop;
+
+	return 0;
+
+drop:
+	IP_INC_STATS(&init_net, IPSTATS_MIB_INDISCARDS);
+	kfree_skb(skb);
+	return -1;
+}
+
+static int l2tp_ip6_push_pending_frames(struct sock *sk)
+{
+	struct sk_buff *skb;
+	__be32 *transhdr = NULL;
+	int err = 0;
+
+	skb = skb_peek(&sk->sk_write_queue);
+	if (skb == NULL)
+		goto out;
+
+	transhdr = (__be32 *)skb_transport_header(skb);
+	*transhdr = 0;
+
+	err = ip6_push_pending_frames(sk);
+
+out:
+	return err;
+}
+
+/* Userspace will call sendmsg() on the tunnel socket to send L2TP
+ * control frames.
+ */
+static int l2tp_ip6_sendmsg(struct kiocb *iocb, struct sock *sk,
+			    struct msghdr *msg, size_t len)
+{
+	struct ipv6_txoptions opt_space;
+	struct sockaddr_l2tpip6 *lsa = (struct sockaddr_l2tpip6 *) msg->msg_name;
+	struct in6_addr *daddr, *final_p, final;
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct l2tp_ip6_sock *lsk = l2tp_ip6_sk(sk);
+	struct ipv6_txoptions *opt = NULL;
+	struct ip6_flowlabel *flowlabel = NULL;
+	struct dst_entry *dst = NULL;
+	struct flowi6 fl6;
+	int addr_len = msg->msg_namelen;
+	int hlimit = -1;
+	int tclass = -1;
+	int dontfrag = -1;
+	int transhdrlen = 4; /* zero session-id */
+	int ulen = len + transhdrlen;
+	int err;
+
+	/* Rough check on arithmetic overflow,
+	   better check is made in ip6_append_data().
+	 */
+	if (len > INT_MAX)
+		return -EMSGSIZE;
+
+	/* Mirror BSD error message compatibility */
+	if (msg->msg_flags & MSG_OOB)
+		return -EOPNOTSUPP;
+
+	/*
+	 *	Get and verify the address.
+	 */
+	memset(&fl6, 0, sizeof(fl6));
+
+	fl6.flowi6_mark = sk->sk_mark;
+
+	if (lsa) {
+		if (addr_len < SIN6_LEN_RFC2133)
+			return -EINVAL;
+
+		if (lsa->l2tp_family && lsa->l2tp_family != AF_INET6)
+			return -EAFNOSUPPORT;
+
+		daddr = &lsa->l2tp_addr;
+		if (np->sndflow) {
+			fl6.flowlabel = lsa->l2tp_flowinfo & IPV6_FLOWINFO_MASK;
+			if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) {
+				flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
+				if (flowlabel == NULL)
+					return -EINVAL;
+				daddr = &flowlabel->dst;
+			}
+		}
+
+		/*
+		 * Otherwise it will be difficult to maintain
+		 * sk->sk_dst_cache.
+		 */
+		if (sk->sk_state == TCP_ESTABLISHED &&
+		    ipv6_addr_equal(daddr, &np->daddr))
+			daddr = &np->daddr;
+
+		if (addr_len >= sizeof(struct sockaddr_in6) &&
+		    lsa->l2tp_scope_id &&
+		    ipv6_addr_type(daddr) & IPV6_ADDR_LINKLOCAL)
+			fl6.flowi6_oif = lsa->l2tp_scope_id;
+	} else {
+		if (sk->sk_state != TCP_ESTABLISHED)
+			return -EDESTADDRREQ;
+
+		daddr = &np->daddr;
+		fl6.flowlabel = np->flow_label;
+	}
+
+	if (fl6.flowi6_oif == 0)
+		fl6.flowi6_oif = sk->sk_bound_dev_if;
+
+	if (msg->msg_controllen) {
+		opt = &opt_space;
+		memset(opt, 0, sizeof(struct ipv6_txoptions));
+		opt->tot_len = sizeof(struct ipv6_txoptions);
+
+		err = datagram_send_ctl(sock_net(sk), sk, msg, &fl6, opt,
+					&hlimit, &tclass, &dontfrag);
+		if (err < 0) {
+			fl6_sock_release(flowlabel);
+			return err;
+		}
+		if ((fl6.flowlabel & IPV6_FLOWLABEL_MASK) && !flowlabel) {
+			flowlabel = fl6_sock_lookup(sk, fl6.flowlabel);
+			if (flowlabel == NULL)
+				return -EINVAL;
+		}
+		if (!(opt->opt_nflen|opt->opt_flen))
+			opt = NULL;
+	}
+
+	if (opt == NULL)
+		opt = np->opt;
+	if (flowlabel)
+		opt = fl6_merge_options(&opt_space, flowlabel, opt);
+	opt = ipv6_fixup_options(&opt_space, opt);
+
+	fl6.flowi6_proto = sk->sk_protocol;
+	if (!ipv6_addr_any(daddr))
+		fl6.daddr = *daddr;
+	else
+		fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */
+	if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr))
+		fl6.saddr = np->saddr;
+
+	final_p = fl6_update_dst(&fl6, opt, &final);
+
+	if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
+		fl6.flowi6_oif = np->mcast_oif;
+	else if (!fl6.flowi6_oif)
+		fl6.flowi6_oif = np->ucast_oif;
+
+	security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
+
+	dst = ip6_dst_lookup_flow(sk, &fl6, final_p, true);
+	if (IS_ERR(dst)) {
+		err = PTR_ERR(dst);
+		goto out;
+	}
+
+	if (hlimit < 0) {
+		if (ipv6_addr_is_multicast(&fl6.daddr))
+			hlimit = np->mcast_hops;
+		else
+			hlimit = np->hop_limit;
+		if (hlimit < 0)
+			hlimit = ip6_dst_hoplimit(dst);
+	}
+
+	if (tclass < 0)
+		tclass = np->tclass;
+
+	if (dontfrag < 0)
+		dontfrag = np->dontfrag;
+
+	if (msg->msg_flags & MSG_CONFIRM)
+		goto do_confirm;
+
+back_from_confirm:
+	lock_sock(sk);
+	err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
+			      ulen, transhdrlen, hlimit, tclass, opt,
+			      &fl6, (struct rt6_info *)dst,
+			      msg->msg_flags, dontfrag);
+	if (err)
+		ip6_flush_pending_frames(sk);
+	else if (!(msg->msg_flags & MSG_MORE))
+		err = l2tp_ip6_push_pending_frames(sk);
+	release_sock(sk);
+done:
+	dst_release(dst);
+out:
+	fl6_sock_release(flowlabel);
+
+	/* Update stats */
+	if (err < 0) {
+		lsk->tx_errors++;
+	} else {
+		lsk->tx_packets++;
+		lsk->tx_bytes += len;
+	}
+
+	return err < 0 ? err : len;
+
+do_confirm:
+	dst_confirm(dst);
+	if (!(msg->msg_flags & MSG_PROBE) || len)
+		goto back_from_confirm;
+	err = 0;
+	goto done;
+}
+
+static int l2tp_ip6_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
+			    size_t len, int noblock, int flags, int *addr_len)
+{
+	struct inet_sock *inet = inet_sk(sk);
+	struct l2tp_ip6_sock *lsk = l2tp_ip6_sk(sk);
+	struct sockaddr_l2tpip6 *lsa = (struct sockaddr_l2tpip6 *)msg->msg_name;
+	size_t copied = 0;
+	int err = -EOPNOTSUPP;
+	struct sk_buff *skb;
+
+	if (flags & MSG_OOB)
+		goto out;
+
+	if (addr_len)
+		*addr_len = sizeof(*lsa);
+
+	if (flags & MSG_ERRQUEUE)
+		return ipv6_recv_error(sk, msg, len);
+
+	skb = skb_recv_datagram(sk, flags, noblock, &err);
+	if (!skb)
+		goto out;
+
+	copied = skb->len;
+	if (len < copied) {
+		msg->msg_flags |= MSG_TRUNC;
+		copied = len;
+	}
+
+	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+	if (err)
+		goto done;
+
+	sock_recv_timestamp(msg, sk, skb);
+
+	/* Copy the address. */
+	if (lsa) {
+		lsa->l2tp_family = AF_INET6;
+		lsa->l2tp_unused = 0;
+		lsa->l2tp_addr = ipv6_hdr(skb)->saddr;
+		lsa->l2tp_flowinfo = 0;
+		lsa->l2tp_scope_id = 0;
+		if (ipv6_addr_type(&lsa->l2tp_addr) & IPV6_ADDR_LINKLOCAL)
+			lsa->l2tp_scope_id = IP6CB(skb)->iif;
+	}
+
+	if (inet->cmsg_flags)
+		ip_cmsg_recv(msg, skb);
+
+	if (flags & MSG_TRUNC)
+		copied = skb->len;
+done:
+	skb_free_datagram(sk, skb);
+out:
+	if (err) {
+		lsk->rx_errors++;
+		return err;
+	}
+
+	lsk->rx_packets++;
+	lsk->rx_bytes += copied;
+
+	return copied;
+}
+
+static struct proto l2tp_ip6_prot = {
+	.name		   = "L2TP/IPv6",
+	.owner		   = THIS_MODULE,
+	.init		   = l2tp_ip6_open,
+	.close		   = l2tp_ip6_close,
+	.bind		   = l2tp_ip6_bind,
+	.connect	   = l2tp_ip6_connect,
+	.disconnect	   = udp_disconnect,
+	.ioctl		   = udp_ioctl,
+	.destroy	   = l2tp_ip6_destroy_sock,
+	.setsockopt	   = ipv6_setsockopt,
+	.getsockopt	   = ipv6_getsockopt,
+	.sendmsg	   = l2tp_ip6_sendmsg,
+	.recvmsg	   = l2tp_ip6_recvmsg,
+	.backlog_rcv	   = l2tp_ip6_backlog_recv,
+	.hash		   = inet_hash,
+	.unhash		   = inet_unhash,
+	.obj_size	   = sizeof(struct l2tp_ip6_sock),
+#ifdef CONFIG_COMPAT
+	.compat_setsockopt = compat_ipv6_setsockopt,
+	.compat_getsockopt = compat_ipv6_getsockopt,
+#endif
+};
+
+static const struct proto_ops l2tp_ip6_ops = {
+	.family		   = PF_INET6,
+	.owner		   = THIS_MODULE,
+	.release	   = inet6_release,
+	.bind		   = inet6_bind,
+	.connect	   = inet_dgram_connect,
+	.socketpair	   = sock_no_socketpair,
+	.accept		   = sock_no_accept,
+	.getname	   = l2tp_ip6_getname,
+	.poll		   = datagram_poll,
+	.ioctl		   = inet6_ioctl,
+	.listen		   = sock_no_listen,
+	.shutdown	   = inet_shutdown,
+	.setsockopt	   = sock_common_setsockopt,
+	.getsockopt	   = sock_common_getsockopt,
+	.sendmsg	   = inet_sendmsg,
+	.recvmsg	   = sock_common_recvmsg,
+	.mmap		   = sock_no_mmap,
+	.sendpage	   = sock_no_sendpage,
+#ifdef CONFIG_COMPAT
+	.compat_setsockopt = compat_sock_common_setsockopt,
+	.compat_getsockopt = compat_sock_common_getsockopt,
+#endif
+};
+
+static struct inet_protosw l2tp_ip6_protosw = {
+	.type		= SOCK_DGRAM,
+	.protocol	= IPPROTO_L2TP,
+	.prot		= &l2tp_ip6_prot,
+	.ops		= &l2tp_ip6_ops,
+	.no_check	= 0,
+};
+
+static struct inet6_protocol l2tp_ip6_protocol __read_mostly = {
+	.handler	= l2tp_ip6_recv,
+};
+
+static int __init l2tp_ip6_init(void)
+{
+	int err;
+
+	printk(KERN_INFO "L2TP IP encapsulation support for IPv6 (L2TPv3)\n");
+
+	err = proto_register(&l2tp_ip6_prot, 1);
+	if (err != 0)
+		goto out;
+
+	err = inet6_add_protocol(&l2tp_ip6_protocol, IPPROTO_L2TP);
+	if (err)
+		goto out1;
+
+	inet6_register_protosw(&l2tp_ip6_protosw);
+	return 0;
+
+out1:
+	proto_unregister(&l2tp_ip6_prot);
+out:
+	return err;
+}
+
+static void __exit l2tp_ip6_exit(void)
+{
+	inet6_unregister_protosw(&l2tp_ip6_protosw);
+	inet6_del_protocol(&l2tp_ip6_protocol, IPPROTO_L2TP);
+	proto_unregister(&l2tp_ip6_prot);
+}
+
+module_init(l2tp_ip6_init);
+module_exit(l2tp_ip6_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Chris Elston <celston@katalix.com>");
+MODULE_DESCRIPTION("L2TP IP encapsulation for IPv6");
+MODULE_VERSION("1.0");
+
+/* Use the value of SOCK_DGRAM (2) directory, because __stringify doesn't like
+ * enums
+ */
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET6, 2, IPPROTO_L2TP);
-- 
1.7.0.4

^ permalink raw reply related

* Re: 3.3.0, 3.4-rc1 reproducible tun Oops
From: Stanislav Kinsbursky @ 2012-04-17 12:18 UTC (permalink / raw)
  To: Simon Kirby; +Cc: Eric Dumazet, netdev@vger.kernel.org
In-Reply-To: <20120417020852.GA18875@hostway.ca>

17.04.2012 06:08, Simon Kirby пишет:
> On Thu, Apr 05, 2012 at 04:41:04AM +0200, Eric Dumazet wrote:
>
>> Hmm, is it happening if you remove the nvidia module ?
>>
>> If yes, please try to add slub_debug=FZPU
>
> Finally got annoyed enough at this to bisect it. It doesn't happen every
> time and I got a bit confused, but I finally tracked it down to:
>
> 1ab5ecb90cb6a3df1476e052f76a6e8f6511cb3d is the first bad commit
> commit 1ab5ecb90cb6a3df1476e052f76a6e8f6511cb3d
> Author: Stanislav Kinsbursky<skinsbursky@parallels.com>
> Date:   Mon Mar 12 02:59:41 2012 +0000
>
>      tun: don't hold network namespace by tun sockets
>
>      v3: added previously removed sock_put() to the tun_release() callback, because
>      sk_release_kernel() doesn't drop the socket reference.
>
>      v2: sk_release_kernel() used for socket release. Dummy tun_release() is
>      required for sk_release_kernel() --->  sock_release() --->  sock->ops->release()
>      call.
>
>      TUN was designed to destroy it's socket on network namesapce shutdown. But this
>      will never happen for persistent device, because it's socket holds network
>      namespace.
>      This patch removes of holding network namespace by TUN socket and replaces it
>      by creating socket in init_net and then changing it's net it to desired one. On
>      shutdown socket is moved back to init_net prior to final put.
>
>      Signed-off-by: Stanislav Kinsbursky<skinsbursky@parallels.com>
>      Signed-off-by: David S. Miller<davem@davemloft.net>
>
> ...With this reverted on top of 3.4-rc3, I no longer see crashes when I
> keep making and breaking the SSH tunnel while running "vmstat 1" in an
> SSH session over a socket that is running through that tunnel.
>
> Simon-

Hi, Simon.
Could you please try to apply the patch below on top of your the tree (with 
1ab5ecb90cb6a3df1476e052f76a6e8f6511cb3d applied) and check does it fix the problem:

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index bb8c72c..1fc4622 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1540,13 +1540,10 @@ static int tun_chr_close(struct inode *inode, struct 
file *file)
  			if (dev->reg_state == NETREG_REGISTERED)
  				unregister_netdevice(dev);
  			rtnl_unlock();
-		}
+		} else
+			sock_put(tun->socket.sk);
  	}

-	tun = tfile->tun;
-	if (tun)
-		sock_put(tun->socket.sk);
-
  	put_net(tfile->net);
  	kfree(tfile);

^ permalink raw reply related

* [net-next PATCH v3] bonding: start slaves with link down for ARP monitor
From: Michal Kubecek @ 2012-04-17 12:02 UTC (permalink / raw)
  To: netdev; +Cc: Jay Vosburgh, Andy Gospodarek, Flavio Leitner

Initialize slave device link state as down if ARP monitor is
active and net_carrier_ok() returns zero. Also shift initial
value of its last_arp_tx so that it doesn't immediately cause
fake detection of "up" state.

When ARP monitoring is used, initializing the slave device with
up link state can cause ARP monitor to detect link failure
before the device is really up (with igb driver, this can take
more than two seconds).

Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
 drivers/net/bonding/bond_main.c |   33 +++++++++++++++++++++------------
 1 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index bb92899..44e6a64 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1726,7 +1726,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
 	read_lock(&bond->lock);
 
-	new_slave->last_arp_rx = jiffies;
+	new_slave->last_arp_rx = jiffies -
+		(msecs_to_jiffies(bond->params.arp_interval) + 1);
 
 	if (bond->params.miimon && !bond->params.use_carrier) {
 		link_reporting = bond_check_dev_link(bond, slave_dev, 1);
@@ -1751,22 +1752,30 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 	}
 
 	/* check for initial state */
-	if (!bond->params.miimon ||
-	    (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS)) {
-		if (bond->params.updelay) {
-			pr_debug("Initial state of slave_dev is BOND_LINK_BACK\n");
-			new_slave->link  = BOND_LINK_BACK;
-			new_slave->delay = bond->params.updelay;
+	if (bond->params.miimon) {
+		if (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS) {
+			if (bond->params.updelay) {
+				new_slave->link = BOND_LINK_BACK;
+				new_slave->delay = bond->params.updelay;
+			} else {
+				new_slave->link = BOND_LINK_UP;
+			}
 		} else {
-			pr_debug("Initial state of slave_dev is BOND_LINK_UP\n");
-			new_slave->link  = BOND_LINK_UP;
+			new_slave->link = BOND_LINK_DOWN;
 		}
-		new_slave->jiffies = jiffies;
+	} else if (bond->params.arp_interval) {
+		new_slave->link = (netif_carrier_ok(slave_dev) ?
+			BOND_LINK_UP : BOND_LINK_DOWN);
 	} else {
-		pr_debug("Initial state of slave_dev is BOND_LINK_DOWN\n");
-		new_slave->link  = BOND_LINK_DOWN;
+		new_slave->link = BOND_LINK_UP;
 	}
 
+	if (new_slave->link != BOND_LINK_DOWN)
+		new_slave->jiffies = jiffies;
+	pr_debug("Initial state of slave_dev is BOND_LINK_%s\n",
+		new_slave->link == BOND_LINK_DOWN ? "DOWN" :
+			(new_slave->link == BOND_LINK_UP ? "UP" : "BACK"));
+
 	bond_update_speed_duplex(new_slave);
 
 	if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) {
-- 
1.7.7

^ permalink raw reply related

* pull request: batman-adv 2012-04-17
From: Antonio Quartulli @ 2012-04-17 11:58 UTC (permalink / raw)
  To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	b.a.t.m.a.n-ZwoEplunGu2X36UT3dwllkB+6BGkLq7r

Hello,

here are a set of changes I would like to propose for next-next/3.5.
Most of the patches are simple cleanups and small fixes. The only important
change is patch 3 which changes the Originator Message sequence number starting
value from 0 to a random generated value.

Thank you,
	Antonio

The following changes since commit ecffe75f934b4e3c5301fe5db278068e0efb0d6b:

  hippi: fix printk format in rrunner.c (2012-04-16 23:48:38 -0400)

are available in the git repository at:

  git://git.open-mesh.org/linux-merge.git tags/batman-adv-for-davem

for you to fetch changes up to 520ada6df73ab595f7d51378b9df937371f13460:

  batman-adv: skip the window protection test when the originator has no neighbours (2012-04-17 13:29:19 +0200)

----------------------------------------------------------------
Included changes:
* several cleanups and fixes
* OriGinator Message seqno initial value is now random

----------------------------------------------------------------
Antonio Quartulli (3):
      batman-adv: use ETH_HLEN instead of sizeof(struct ethhdr)
      batman-adv: print OGM seq numbers as unsigned long
      batman-adv: skip the window protection test when the originator has no neighbours

Marek Lindner (8):
      batman-adv: move ogm initialization into the proper function
      batman-adv: refactoring API: find generalized name for bat_ogm_init callback
      batman-adv: randomize initial seqno to avoid collision
      batman-adv: add iface_disable() callback to routing API
      batman-adv: handle routing code initialization properly
      batman-adv: refactoring API: find generalized name for bat_ogm_init_primary callback
      batman-adv: rename BATMAN_OGM_LEN to BATMAN_OGM_HLEN
      batman-adv: mark existing ogm variables as batman iv

 net/batman-adv/bat_iv_ogm.c            |   63 +++++++++++++++++++++-----------
 net/batman-adv/bridge_loop_avoidance.c |   10 ++---
 net/batman-adv/hard-interface.c        |   33 +++++++++--------
 net/batman-adv/icmp_socket.c           |    4 +-
 net/batman-adv/main.c                  |    5 ++-
 net/batman-adv/packet.h                |    6 +--
 net/batman-adv/routing.c               |   10 ++---
 net/batman-adv/send.c                  |   14 +++----
 net/batman-adv/soft-interface.c        |    2 +-
 net/batman-adv/types.h                 |   12 +++---
 net/batman-adv/vis.c                   |    8 ++--
 11 files changed, 95 insertions(+), 72 deletions(-)

^ permalink raw reply

* Re: [PATCH v2] bonding: start slaves with link down for ARP monitor
From: Michal Kubeček @ 2012-04-17 11:58 UTC (permalink / raw)
  To: Jay Vosburgh; +Cc: Flavio Leitner, netdev, Andy Gospodarek
In-Reply-To: <1410525.5tCeY2AOxF@alaris>

On Monday 16 of April 2012 12:27EN, Michal Kubeček wrote:
> On Saturday 14 of April 2012 21:48EN, Jay Vosburgh wrote:
> > Anybody got a 10 or 100 card laying around with fast autoneg to
> > try?  Back in the day I used 3c59x and e100s, and I seem to recall
> > that the 3c59x board I had was pretty speedy at going carrier up.
> 
> It seems these cards are hard to find these days (I tried to find one
> in our office but no luck yet). However, I tried an onboard adapter
> with r8169 driver and patched kernel succeeded to detect carrier in
> time for bonding driver to start the slave in "up" state (and it
> started in "down" state with unplugged cable so that the detection is
> correct).

I tested few more cards:

- two 100 Mb/s Realtek 8139C and 8139D with 8139too driver:
  driver sets carrier on soon enough and slave starts with "up" and
  stays that way (same as r8169)

- 1 Gb/s Intel Pro/1000PT (82572EI) with e1000e driver:
  essentially the same as igb, driver is slow and patch prevents the
  up -> down -> up sequence by starting the slave in "down" state

- 100 Mb/s Intel (?) cards with DECchip Tulip 21142/3, tulip driver:
  card/driver either doesn't set the flag properly or is extremely slow
  with up -> down transition so that the state was "up" all the time
  no matter what the real link state was

I'll resend v3 with fixed style problem in a moment.

                                                        Michal Kubecek

^ permalink raw reply

* [PATCH 11/11] batman-adv: skip the window protection test when the originator has no neighbours
From: Antonio Quartulli @ 2012-04-17 11:58 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n, Antonio Quartulli
In-Reply-To: <1334663907-22725-1-git-send-email-ordex@autistici.org>

When we receive an OGM from from a node for the first time, the last_real_seqno
field of the orig_node structure has not been initialised yet. The value of this
field is used to compute the current ogm-seqno window and therefore the
protection mechanism will probably drop the packet due to an out-of-window error.
To avoid this situation this patch adds a check to skip the window protection
mechanism if no neighbour nodes have already been added. When the first
neighbour node is added, the last_real_seqno field is initialised too.

Reported-by: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Antonio Quartulli <ordex@autistici.org>
---
 net/batman-adv/bat_iv_ogm.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index f36b54c..873ea40 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -861,7 +861,8 @@ static int bat_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
 	seq_diff = batman_ogm_packet->seqno - orig_node->last_real_seqno;
 
 	/* signalize caller that the packet is to be dropped. */
-	if (window_protected(bat_priv, seq_diff,
+	if (!hlist_empty(&orig_node->neigh_list) &&
+	    window_protected(bat_priv, seq_diff,
 			     &orig_node->batman_seqno_reset))
 		goto out;
 
-- 
1.7.9.4

^ permalink raw reply related

* [PATCH 10/11] batman-adv: print OGM seq numbers as unsigned long
From: Antonio Quartulli @ 2012-04-17 11:58 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n, Antonio Quartulli
In-Reply-To: <1334663907-22725-1-git-send-email-ordex@autistici.org>

OGM sequence numbers are declared as uint32_t and so they have to printed
using %u instead of %d in order to avoid wrong representations.

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
---
 net/batman-adv/bat_iv_ogm.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index 5bb35df..f36b54c 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -152,7 +152,7 @@ static void bat_iv_ogm_send_to_if(struct forw_packet *forw_packet,
 							    "Sending own" :
 							    "Forwarding"));
 		bat_dbg(DBG_BATMAN, bat_priv,
-			"%s %spacket (originator %pM, seqno %d, TQ %d, TTL %d, IDF %s, ttvn %d) on interface %s [%pM]\n",
+			"%s %spacket (originator %pM, seqno %u, TQ %d, TTL %d, IDF %s, ttvn %d) on interface %s [%pM]\n",
 			fwd_str, (packet_num > 0 ? "aggregated " : ""),
 			batman_ogm_packet->orig,
 			ntohl(batman_ogm_packet->seqno),
@@ -211,7 +211,7 @@ static void bat_iv_ogm_emit(struct forw_packet *forw_packet)
 
 		/* FIXME: what about aggregated packets ? */
 		bat_dbg(DBG_BATMAN, bat_priv,
-			"%s packet (originator %pM, seqno %d, TTL %d) on interface %s [%pM]\n",
+			"%s packet (originator %pM, seqno %u, TTL %d) on interface %s [%pM]\n",
 			(forw_packet->own ? "Sending own" : "Forwarding"),
 			batman_ogm_packet->orig,
 			ntohl(batman_ogm_packet->seqno),
@@ -892,7 +892,7 @@ static int bat_iv_ogm_update_seqnos(const struct ethhdr *ethhdr,
 
 	if (need_update) {
 		bat_dbg(DBG_BATMAN, bat_priv,
-			"updating last_seqno: old %d, new %d\n",
+			"updating last_seqno: old %u, new %u\n",
 			orig_node->last_real_seqno, batman_ogm_packet->seqno);
 		orig_node->last_real_seqno = batman_ogm_packet->seqno;
 	}
@@ -945,7 +945,7 @@ static void bat_iv_ogm_process(const struct ethhdr *ethhdr,
 					   batman_ogm_packet->orig) ? 1 : 0);
 
 	bat_dbg(DBG_BATMAN, bat_priv,
-		"Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %d, ttvn %u, crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
+		"Received BATMAN packet via NB: %pM, IF: %s [%pM] (from OG: %pM, via prev OG: %pM, seqno %u, ttvn %u, crc %u, changes %u, td %d, TTL %d, V %d, IDF %d)\n",
 		ethhdr->h_source, if_incoming->net_dev->name,
 		if_incoming->net_dev->dev_addr, batman_ogm_packet->orig,
 		batman_ogm_packet->prev_sender, batman_ogm_packet->seqno,
-- 
1.7.9.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