Netdev List
 help / color / mirror / Atom feed
* [PATCH net 0/3] bnx2x: Link/LED fixes
From: Yaniv Rosner @ 2013-02-27 23:06 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Yaniv Rosner

Hi Dave,
The following patch series describe couple of link fixes.
Please consider applying it to net.

Thanks,
Yaniv

^ permalink raw reply

* [PATCH net 2/3] bnx2x: Fix KR2 link
From: Yaniv Rosner @ 2013-02-27 23:06 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Yaniv Rosner, Eilon Greenstein
In-Reply-To: <1362006406-2489-1-git-send-email-yanivr@broadcom.com>

Fix KR2 link down problem after reboot when link speed is reconfigured via ethtool.
Since 1G/10G support link speed were missing by default, 1G/10G link speed were
not advertised.

Signed-off-by: Yaniv Rosner <yanivr@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 .../net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c    |    6 ++++++
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c   |    2 ++
 2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
index 9a674b1..edfa67a 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
@@ -281,6 +281,8 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 			cmd->lp_advertising |= ADVERTISED_2500baseX_Full;
 		if (status & LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE)
 			cmd->lp_advertising |= ADVERTISED_10000baseT_Full;
+		if (status & LINK_STATUS_LINK_PARTNER_20GXFD_CAPABLE)
+			cmd->lp_advertising |= ADVERTISED_20000baseKR2_Full;
 	}
 
 	cmd->maxtxpkt = 0;
@@ -463,6 +465,10 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 						ADVERTISED_10000baseKR_Full))
 				bp->link_params.speed_cap_mask[cfg_idx] |=
 					PORT_HW_CFG_SPEED_CAPABILITY_D0_10G;
+
+			if (cmd->advertising & ADVERTISED_20000baseKR2_Full)
+				bp->link_params.speed_cap_mask[cfg_idx] |=
+					PORT_HW_CFG_SPEED_CAPABILITY_D0_20G;
 		}
 	} else { /* forced speed */
 		/* advertise the requested speed and duplex if supported */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index 4719ab1..bf69c53 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -11851,6 +11851,8 @@ static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
 			phy->media_type = ETH_PHY_KR;
 			phy->flags |= FLAGS_WC_DUAL_MODE;
 			phy->supported &= (SUPPORTED_20000baseKR2_Full |
+					   SUPPORTED_10000baseT_Full |
+					   SUPPORTED_1000baseT_Full |
 					   SUPPORTED_Autoneg |
 					   SUPPORTED_FIBRE |
 					   SUPPORTED_Pause |
-- 
1.7.7.1

^ permalink raw reply related

* [PATCH net 3/3] bnx2x: Fix KR2 work-around condition
From: Yaniv Rosner @ 2013-02-27 23:06 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Yaniv Rosner, Eilon Greenstein
In-Reply-To: <1362006406-2489-1-git-send-email-yanivr@broadcom.com>

Fix condition typo for running KR2 work-around though it doesn't have 
real effect since the typo bits matched by chance.

Signed-off-by: Yaniv Rosner <yanivr@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index bf69c53..31c5787 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -13499,7 +13499,7 @@ void bnx2x_period_func(struct link_params *params, struct link_vars *vars)
 		struct bnx2x_phy *phy = &params->phy[INT_PHY];
 		bnx2x_set_aer_mmd(params, phy);
 		if ((phy->supported & SUPPORTED_20000baseKR2_Full) &&
-		    (phy->speed_cap_mask & SPEED_20000))
+		    (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_20G))
 			bnx2x_check_kr2_wa(params, vars, phy);
 		bnx2x_check_over_curr(params, vars);
 		if (vars->rx_tx_asic_rst)
-- 
1.7.7.1

^ permalink raw reply related

* Re: [PATCH v2] net/sctp: Validate parameter size for SCTP_GET_ASSOC_STATS
From: David Miller @ 2013-02-27 21:08 UTC (permalink / raw)
  To: vyasevich; +Cc: linux, netdev, linux-sctp, sri, nhorman
In-Reply-To: <512E73FA.1090407@gmail.com>

From: Vlad Yasevich <vyasevich@gmail.com>
Date: Wed, 27 Feb 2013 16:00:42 -0500

> On 02/27/2013 03:57 PM, Guenter Roeck wrote:
>> Building sctp may fail with:
>>
>> In function ‘copy_from_user’,
>>      inlined from ‘sctp_getsockopt_assoc_stats’ at
>>      net/sctp/socket.c:5656:20:
>> arch/x86/include/asm/uaccess_32.h:211:26: error: call to
>>      ‘copy_from_user_overflow’ declared with attribute error:
>>      copy_from_user()
>>      buffer size is not provably correct
>>
>> if built with W=1 due to a missing parameter size validation
>> before the call to copy_from_user.
>>
>> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
>> ---
>> v2: Fix by moving the existing parameter size validation up
>>      in the function instead of adding an additional one.
> 
> This works too...
> 
> Acked-by: Vlad Yasevich <vyasevich@gmail.com>

I'll apply this and queue it up for -stable, thanks everyone.

^ permalink raw reply

* Re: [PATCH net 0/3] bnx2x: Link/LED fixes
From: David Miller @ 2013-02-27 21:10 UTC (permalink / raw)
  To: yanivr; +Cc: netdev
In-Reply-To: <1362006406-2489-1-git-send-email-yanivr@broadcom.com>

From: "Yaniv Rosner" <yanivr@broadcom.com>
Date: Thu, 28 Feb 2013 01:06:43 +0200

> Hi Dave,
> The following patch series describe couple of link fixes.
> Please consider applying it to net.

Where is patch #1?

^ permalink raw reply

* [PATCH net 1/3] bnx2x: Fix port identification for the 84834
From: Yaniv Rosner @ 2013-02-27 23:06 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Yaniv Rosner, Eilon Greenstein
In-Reply-To: <1362006406-2489-1-git-send-email-yanivr@broadcom.com>

Fix the "ethtool -p" for boards with BCM84834, by using LED4 of the PHY 
to toggle the link LED while keeping interrupt disabled to avoid NIG attentions,
and at the end restore NIG to previous state.

Signed-off-by: Yaniv Rosner <yanivr@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
---
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c |   60 ++++++++++++++++++++++
 drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h |    3 +-
 2 files changed, 62 insertions(+), 1 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
index 1663e0b..4719ab1 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -10422,6 +10422,28 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
 					 MDIO_PMA_DEVAD,
 					 MDIO_PMA_REG_8481_LED1_MASK,
 					 0x0);
+			if (phy->type ==
+			    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) {
+				/* Disable MI_INT interrupt before setting LED4
+				 * source to constant off.
+				 */
+				if (REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
+					   params->port*4) &
+				    NIG_MASK_MI_INT) {
+					params->link_flags |=
+					LINK_FLAGS_INT_DISABLED;
+
+					bnx2x_bits_dis(
+						bp,
+						NIG_REG_MASK_INTERRUPT_PORT0 +
+						params->port*4,
+						NIG_MASK_MI_INT);
+				}
+				bnx2x_cl45_write(bp, phy,
+						 MDIO_PMA_DEVAD,
+						 MDIO_PMA_REG_8481_SIGNAL_MASK,
+						 0x0);
+			}
 		}
 		break;
 	case LED_MODE_ON:
@@ -10468,6 +10490,28 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
 					 MDIO_PMA_DEVAD,
 					 MDIO_PMA_REG_8481_LED1_MASK,
 					 0x20);
+			if (phy->type ==
+			    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) {
+				/* Disable MI_INT interrupt before setting LED4
+				 * source to constant on.
+				 */
+				if (REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 +
+					   params->port*4) &
+				    NIG_MASK_MI_INT) {
+					params->link_flags |=
+					LINK_FLAGS_INT_DISABLED;
+
+					bnx2x_bits_dis(
+						bp,
+						NIG_REG_MASK_INTERRUPT_PORT0 +
+						params->port*4,
+						NIG_MASK_MI_INT);
+				}
+				bnx2x_cl45_write(bp, phy,
+						 MDIO_PMA_DEVAD,
+						 MDIO_PMA_REG_8481_SIGNAL_MASK,
+						 0x20);
+			}
 		}
 		break;
 
@@ -10532,6 +10576,22 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
 					 MDIO_PMA_DEVAD,
 					 MDIO_PMA_REG_8481_LINK_SIGNAL,
 					 val);
+			if (phy->type ==
+			    PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) {
+				/* Restore LED4 source to external link,
+				 * and re-enable interrupts.
+				 */
+				bnx2x_cl45_write(bp, phy,
+						 MDIO_PMA_DEVAD,
+						 MDIO_PMA_REG_8481_SIGNAL_MASK,
+						 0x40);
+				if (params->link_flags &
+				    LINK_FLAGS_INT_DISABLED) {
+					bnx2x_link_int_enable(params);
+					params->link_flags &=
+						~LINK_FLAGS_INT_DISABLED;
+				}
+			}
 		}
 		break;
 	}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
index d25c7d7..be5c195 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
@@ -307,7 +307,8 @@ struct link_params {
 	struct bnx2x *bp;
 	u16 req_fc_auto_adv; /* Should be set to TX / BOTH when
 				req_flow_ctrl is set to AUTO */
-	u16 rsrv1;
+	u16 link_flags;
+#define LINK_FLAGS_INT_DISABLED		(1<<0)
 	u32 lfa_base;
 };
 
-- 
1.7.7.1

^ permalink raw reply related

* Re: [PATCH net 0/3] bnx2x: Link/LED fixes
From: David Miller @ 2013-02-27 21:14 UTC (permalink / raw)
  To: yanivr; +Cc: netdev
In-Reply-To: <20130227.161044.1861708594976235273.davem@davemloft.net>

From: David Miller <davem@davemloft.net>
Date: Wed, 27 Feb 2013 16:10:44 -0500 (EST)

> From: "Yaniv Rosner" <yanivr@broadcom.com>
> Date: Thu, 28 Feb 2013 01:06:43 +0200
> 
>> Hi Dave,
>> The following patch series describe couple of link fixes.
>> Please consider applying it to net.
> 
> Where is patch #1?

Nevermind it just showed up :)

^ permalink raw reply

* Re: [PATCH] tcp: avoid wakeups for pure ACK
From: David Miller @ 2013-02-27 21:15 UTC (permalink / raw)
  To: eric.dumazet; +Cc: netdev, ncardwell, therbert, ycheng, ak
In-Reply-To: <1361989059.11403.50.camel@edumazet-glaptop>

From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Wed, 27 Feb 2013 10:17:39 -0800

> So this patch will also help this (not very usual) situation, as we will
> only wakeup the tcp_sendmsg() thread when ACK is processed from softirq
> handler, and let the thread blocked in tcp_recvmsg() sleeping.

Ok, thanks for the analysis.

^ permalink raw reply

* Re: [PATCH] net: af_packet: Validate parameter size for PACKET_HDRLEN control message
From: Daniel Borkmann @ 2013-02-27 21:18 UTC (permalink / raw)
  To: Guenter Roeck; +Cc: David Miller, netdev
In-Reply-To: <20130227203327.GA6113@roeck-us.net>

On 02/27/2013 09:33 PM, Guenter Roeck wrote:
> On Wed, Feb 27, 2013 at 03:26:30PM -0500, David Miller wrote:
>> From: Daniel Borkmann <dborkman@redhat.com>
>> Date: Wed, 27 Feb 2013 21:22:17 +0100
>>
>>> On 02/27/2013 08:46 PM, Guenter Roeck wrote:
>>>> Building af_packet may fail with
>>>>
>>>> In function ‘copy_from_user’,
>>>>       inlined from ‘packet_getsockopt’ at
>>>>       net/packet/af_packet.c:3215:21:
>>>> arch/x86/include/asm/uaccess_32.h:211:26: error: call to
>>>>       ‘copy_from_user_overflow’ declared with attribute error:
>>>>       copy_from_user()
>>>>       buffer size is not provably correct
>>>>
>>>> if built with W=1 due to a missing parameter size validation.
>>>>
>>>> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
>>>> ---
>>>>    net/packet/af_packet.c |    2 ++
>>>>    1 file changed, 2 insertions(+)
>>>>
>>>> diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
>>>> index c7bfeff..1976b23 100644
>>>> --- a/net/packet/af_packet.c
>>>> +++ b/net/packet/af_packet.c
>>>> @@ -3210,6 +3210,8 @@ static int packet_getsockopt(struct socket
>>>> *sock, int level, int optname,
>>>>    		val = po->tp_version;
>>>>    		break;
>>>>    	case PACKET_HDRLEN:
>>>> +		if (len < sizeof(int))
>>>> +			return -EINVAL;
>>>
>>> I think this could break some user space applications here, those who
>>> e.g. only pass
>>> an uint16_t to packet_getsockopt with PACKET_HDRLEN.
>>
>> Well, their shit is broken on big endian then.
>
> There must be something else going on anyway ... yes, my patch fixes the
> warning/error, but copy_from_user should only bail out if the copy size
> can be larger than the provided buffer (unless I misunderstand the code
> in copy_from_user). And the second check should take care of that.

Fair enough, from what I read the implementation on x86_64 uses gcc's
__builtin_object_size(<X>, 0) [1]. Since the <to> (<X>) argument is known
at compile time (val:int), __builtin_object_size() will return sizeof(int)-1,
the number of bytes from val start to the end of the object val pointer
points to. Since our length that we pass can be [0, sizeof(int)] the
compiler cannot prove it, if the copy_from_user() buffer size is correct.
Thus, "buffer size is not provably correct". Applications not passing int
to this getsockopt(2) are screwed up then anyway.

   [1] http://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html

^ permalink raw reply

* Re: [PATCH v6 04/46] percpu_rwlock: Implement the core design of Per-CPU Reader-Writer Locks
From: Srivatsa S. Bhat @ 2013-02-27 21:19 UTC (permalink / raw)
  To: Lai Jiangshan
  Cc: Michel Lespinasse, linux-doc, peterz, fweisbec, linux-kernel,
	namhyung, mingo, linux-arch, linux, xiaoguangrong, wangyun,
	paulmck, nikunj, linux-pm, rusty, rostedt, rjw, vincent.guittot,
	tglx, linux-arm-kernel, netdev, oleg, sbw, tj, akpm, linuxppc-dev
In-Reply-To: <CACvQF53ph2ixdM-otzetjM5cR+2kcZj6sckOp3TnzzA_x-EZ8w@mail.gmail.com>

On 02/27/2013 06:03 AM, Lai Jiangshan wrote:
> On Wed, Feb 27, 2013 at 3:30 AM, Srivatsa S. Bhat
> <srivatsa.bhat@linux.vnet.ibm.com> wrote:
>> On 02/26/2013 09:55 PM, Lai Jiangshan wrote:
>>> On Tue, Feb 26, 2013 at 10:22 PM, Srivatsa S. Bhat
>>> <srivatsa.bhat@linux.vnet.ibm.com> wrote:
>>>>
>>>> Hi Lai,
>>>>
>>>> I'm really not convinced that piggy-backing on lglocks would help
>>>> us in any way. But still, let me try to address some of the points
>>>> you raised...
>>>>
>>>> On 02/26/2013 06:29 PM, Lai Jiangshan wrote:
>>>>> On Tue, Feb 26, 2013 at 5:02 PM, Srivatsa S. Bhat
>>>>> <srivatsa.bhat@linux.vnet.ibm.com> wrote:
>>>>>> On 02/26/2013 05:47 AM, Lai Jiangshan wrote:
>>>>>>> On Tue, Feb 26, 2013 at 3:26 AM, Srivatsa S. Bhat
>>>>>>> <srivatsa.bhat@linux.vnet.ibm.com> wrote:
>>>>>>>> Hi Lai,
>>>>>>>>
>>>>>>>> On 02/25/2013 09:23 PM, Lai Jiangshan wrote:
>>>>>>>>> Hi, Srivatsa,
>>>>>>>>>
>>>>>>>>> The target of the whole patchset is nice for me.
>>>>>>>>
>>>>>>>> Cool! Thanks :-)
>>>>>>>>
>>>>>> [...]
>>>>>>
>>>>>> Unfortunately, I see quite a few issues with the code above. IIUC, the
>>>>>> writer and the reader both increment the same counters. So how will the
>>>>>> unlock() code in the reader path know when to unlock which of the locks?
>>>>>
>>>>> The same as your code, the reader(which nested in write C.S.) just dec
>>>>> the counters.
>>>>
>>>> And that works fine in my case because the writer and the reader update
>>>> _two_ _different_ counters.
>>>
>>> I can't find any magic in your code, they are the same counter.
>>>
>>>         /*
>>>          * It is desirable to allow the writer to acquire the percpu-rwlock
>>>          * for read (if necessary), without deadlocking or getting complaints
>>>          * from lockdep. To achieve that, just increment the reader_refcnt of
>>>          * this CPU - that way, any attempt by the writer to acquire the
>>>          * percpu-rwlock for read, will get treated as a case of nested percpu
>>>          * reader, which is safe, from a locking perspective.
>>>          */
>>>         this_cpu_inc(pcpu_rwlock->rw_state->reader_refcnt);
>>>
>>
>> Whoa! Hold on, were you really referring to _this_ increment when you said
>> that, in your patch you would increment the refcnt at the writer? Then I guess
>> there is a major disconnect in our conversations. (I had assumed that you were
>> referring to the update of writer_signal, and were just trying to have a single
>> refcnt instead of reader_refcnt and writer_signal).
> 
> https://github.com/laijs/linux/commit/53e5053d5b724bea7c538b11743d0f420d98f38d
> 
> Sorry the name "fallback_reader_refcnt" misled you.
> 
[...]

>>> All I was considered is "nested reader is seldom", so I always
>>> fallback to rwlock when nested.
>>> If you like, I can add 6 lines of code, the overhead is
>>> 1 spin_try_lock()(fast path)  + N  __this_cpu_inc()
>>>
>>
>> I'm assuming that calculation is no longer valid, considering that
>> we just discussed how the per-cpu refcnt that you were using is quite
>> unnecessary and can be removed.
>>
>> IIUC, the overhead with your code, as per above discussion would be:
>> 1 spin_try_lock() [non-nested] + N read_lock(global_rwlock).
> 
> https://github.com/laijs/linux/commit/46334544bb7961550b7065e015da76f6dab21f16
> 
> Again, I'm so sorry the name "fallback_reader_refcnt" misled you.
> 

At this juncture I really have to admit that I don't understand your
intentions at all. What are you really trying to prove? Without giving
a single good reason why my code is inferior, why are you even bringing
up the discussion about a complete rewrite of the synchronization code?
http://article.gmane.org/gmane.linux.kernel.cross-arch/17103
http://article.gmane.org/gmane.linux.power-management.general/31345

I'm beginning to add 2 + 2 together based on the kinds of questions you
have been asking...

You posted a patch in this thread and started a discussion around it without
even establishing a strong reason to do so. Now you point me to your git
tree where your patches have even more traces of ideas being borrowed from
my patchset (apart from my own ideas/code, there are traces of others' ideas
being borrowed too - for example, it was Oleg who originally proposed the
idea of splitting up the counter into 2 parts and I'm seeing that it is
slowly crawling into your code with no sign of appropriate credits).
http://article.gmane.org/gmane.linux.network/260288

And in reply to my mail pointing out the performance implications of the
global read_lock at the reader side in your code, you said you'll come up
with a comparison between that and my patchset.
http://article.gmane.org/gmane.linux.network/260288
The issue has been well-documented in my patch description of patch 4.
http://article.gmane.org/gmane.linux.kernel/1443258

Are you really trying to pit bits and pieces of my own ideas/versions
against one another and claiming them as your own?

You projected the work involved in handling the locking issues pertaining
to CPU_DYING notifiers etc as a TODO, despite the fact that I had explicitly
noted in my cover letter that I had audited and taken care of all of them.
http://article.gmane.org/gmane.linux.documentation/9727
http://article.gmane.org/gmane.linux.documentation/9520

You failed to acknowledge (on purpose?) that I had done a tree-wide
conversion despite the fact that you were replying to the very thread which
had the 46 patches which did exactly that (and I had also mentioned it
explicitly in my cover letter).
http://article.gmane.org/gmane.linux.documentation/9727
http://article.gmane.org/gmane.linux.documentation/9520

You then started probing more and more about the technique I used to do
the tree-wide conversion.
http://article.gmane.org/gmane.linux.kernel.cross-arch/17111

You also retorted saying you did go through my patch descriptions, so
its not like you have missed reading them.
http://article.gmane.org/gmane.linux.power-management.general/31345

Each of these when considered individually, might appear like innocuous and
honest attempts at evaluating my code. But when put together, I'm beginning
to sense a whole different angle to it altogether, as if you are trying
to spin your own patch series, complete with the locking framework _and_
the tree-wide conversion, heavily borrowed from mine. At the beginning of
this discussion, I predicted that the lglock version that you are proposing
would end up being either less efficient than my version or look very similar
to my version. http://article.gmane.org/gmane.linux.kernel/1447139

I thought it was just the former till now, but its not hard to see how it
is getting closer to becoming the latter too. So yeah, I'm not amused.

Maybe (and hopefully) you are just trying out different ideas on your own,
and I'm just being paranoid. I really hope that is the case. If you are just
trying to review my code, then please stop sending patches with borrowed ideas
with your sole Signed-off-by, and purposefully ignoring the work already done
in my patchset, because it is really starting to look suspicious, at least
to me.

Don't get me wrong - I'll whole-heartedly acknowledge and appreciate if
_your_ code is better than mine. I just don't like the idea of somebody
plagiarizing my ideas/code (or even others' ideas for that matter).
However, I sincerely apologize in advance if I misunderstood/misjudged your
intentions; I just wanted to voice my concerns out loud at this point,
considering the bad feeling I got by looking at your responses collectively.

Regards,
Srivatsa S. Bhat

^ permalink raw reply

* Re: [RFC PATCH 0/5] net: low latency Ethernet device polling
From: Ben Greear @ 2013-02-27 21:42 UTC (permalink / raw)
  To: Eliezer Tamir
  Cc: Rick Jones, Eliezer Tamir, linux-kernel, netdev, Dave Miller,
	Jesse Brandeburg, e1000-devel, Willem de Bruijn, Andi Kleen, HPA,
	Eliezer Tamir
In-Reply-To: <512E6F23.3090003@linux.intel.com>

On 02/27/2013 12:40 PM, Eliezer Tamir wrote:
> On 27/02/2013 21:58, Rick Jones wrote:
>> On 02/27/2013 09:55 AM, Eliezer Tamir wrote:
>>>
>>> Performance numbers:
>>> Kernel   Config     C3/6  rx-usecs  TCP  UDP
>>> 3.8rc6   typical    off   adaptive  37k  40k
>>> 3.8rc6   typical    off   0*        50k  56k
>>> 3.8rc6   optimized  off   0*        61k  67k
>>> 3.8rc6   optimized  on    adaptive  26k  29k
>>> patched  typical    off   adaptive  70k  78k
>>> patched  optimized  off   adaptive  79k  88k
>>> patched  optimized  off   100       84k  92k
>>> patched  optimized  on    adaptive  83k  91k
>>> *rx-usecs=0 is usually not useful in a production environment.
>>
>> I would think that latency-sensitive folks would be using rx-usecs=0 in
>> production - at least if the NIC in use didn't have low enough latency
>> with its default interrupt coalescing/avoidance heuristics.
>
> It will only work well if you have no bulk traffic on the same port as the low latency traffic at all.

Have you done any tests for bulk throughput with busy-poll?  Yes, it will eat a core,
but that might be worth it in some cases if there was significant throughput increase...

Thanks,
Ben

-- 
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com

^ permalink raw reply

* [PATCH iproute2] ip/iptunnel: Fix incorrect syntax in man page
From: David Ward @ 2013-02-27 22:58 UTC (permalink / raw)
  To: netdev; +Cc: Andreas Henriksson, David Ward

Reported-by: Andreas Henriksson <andreas@fatal.se>
Signed-off-by: David Ward <david.ward@ll.mit.edu>
---
 man/man8/ip-tunnel.8 |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/man/man8/ip-tunnel.8 b/man/man8/ip-tunnel.8
index b408517..3e558b0 100644
--- a/man/man8/ip-tunnel.8
+++ b/man/man8/ip-tunnel.8
@@ -60,9 +60,9 @@ ip-tunnel - tunnel configuration
 .IR TOS " := { " STRING " | " 00 ".." ff " |"
 .BR inherit " |"
 .BI "inherit/" STRING
-.R " |"
+.RB "|"
 .BI "inherit/" 00 ".." ff
-.R " }"
+.RB "}"
 
 .ti -8
 .IR ELIM " := {"
-- 
1.7.1

^ permalink raw reply related

* [PATCH iproute2] iplink_vlan: Add flag for Multiple VLAN Registration Protocol (MVRP)
From: David Ward @ 2013-02-27 23:00 UTC (permalink / raw)
  To: netdev; +Cc: David Ward

Signed-off-by: David Ward <david.ward@ll.mit.edu>
Acked-by: Patrick McHardy <kaber@trash.net>
---
 include/linux/if_vlan.h |    1 +
 ip/iplink_vlan.c        |   12 +++++++++++-
 2 files changed, 12 insertions(+), 1 deletions(-)

diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 3be1ca6..24ae007 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -34,6 +34,7 @@ enum vlan_flags {
 	VLAN_FLAG_REORDER_HDR	= 0x1,
 	VLAN_FLAG_GVRP		= 0x2,
 	VLAN_FLAG_LOOSE_BINDING	= 0x4,
+	VLAN_FLAG_MVRP		= 0x8,
 };
 
 enum vlan_name_types {
diff --git a/ip/iplink_vlan.c b/ip/iplink_vlan.c
index 26ceb8d..ed8984a 100644
--- a/ip/iplink_vlan.c
+++ b/ip/iplink_vlan.c
@@ -26,7 +26,7 @@ static void explain(void)
 		"\n"
 		"VLANID := 0-4095\n"
 		"FLAG-LIST := [ FLAG-LIST ] FLAG\n"
-		"FLAG := [ reorder_hdr { on | off } ] [ gvrp { on | off } ]\n"
+		"FLAG := [ reorder_hdr { on | off } ] [ gvrp { on | off } ] [ mvrp { on | off } ]\n"
 		"        [ loose_binding { on | off } ]\n"
 		"QOS-MAP := [ QOS-MAP ] QOS-MAPPING\n"
 		"QOS-MAPPING := FROM:TO\n"
@@ -103,6 +103,15 @@ static int vlan_parse_opt(struct link_util *lu, int argc, char **argv,
 				flags.flags &= ~VLAN_FLAG_GVRP;
 			else
 				return on_off("gvrp", *argv);
+		} else if (matches(*argv, "mvrp") == 0) {
+			NEXT_ARG();
+			flags.mask |= VLAN_FLAG_MVRP;
+			if (strcmp(*argv, "on") == 0)
+				flags.flags |= VLAN_FLAG_MVRP;
+			else if (strcmp(*argv, "off") == 0)
+				flags.flags &= ~VLAN_FLAG_MVRP;
+			else
+				return on_off("mvrp", *argv);
 		} else if (matches(*argv, "loose_binding") == 0) {
 			NEXT_ARG();
 			flags.mask |= VLAN_FLAG_LOOSE_BINDING;
@@ -166,6 +175,7 @@ static void vlan_print_flags(FILE *fp, __u32 flags)
 		}
 	_PF(REORDER_HDR);
 	_PF(GVRP);
+	_PF(MVRP);
 	_PF(LOOSE_BINDING);
 #undef _PF
 	if (flags)
-- 
1.7.1

^ permalink raw reply related

* [PATCH net 1/1] r8169: honor jumbo settings when chipset is requested to start.
From: Francois Romieu @ 2013-02-27 23:01 UTC (permalink / raw)
  To: netdev; +Cc: Tomi Orava, David Miller, Hayes Wang

Some hardware start settings implicitely assume an usual 1500 bytes mtu
that can't be guaranteed because changes of mtu may be requested both
before and after the hardware is started.

Reported-by: Tomi Orava <tomimo@ncircle.nullnet.fi>
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Cc: Hayes Wang <hayeswang@realtek.com>
---

 Tomi, can you give this one a try ? It should be the "don't break non
 jumbo setup and fix similar problem on different chipsets" patch that
 my previous hack wasn't.

 drivers/net/ethernet/realtek/r8169.c | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 8900398..28fb50a 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -4765,8 +4765,10 @@ static void rtl_hw_start_8168bb(struct rtl8169_private *tp)
 
 	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
 
-	rtl_tx_performance_tweak(pdev,
-		(0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
+	if (tp->dev->mtu <= ETH_DATA_LEN) {
+		rtl_tx_performance_tweak(pdev, (0x5 << MAX_READ_REQUEST_SHIFT) |
+					 PCI_EXP_DEVCTL_NOSNOOP_EN);
+	}
 }
 
 static void rtl_hw_start_8168bef(struct rtl8169_private *tp)
@@ -4789,7 +4791,8 @@ static void __rtl_hw_start_8168cp(struct rtl8169_private *tp)
 
 	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
 
-	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+	if (tp->dev->mtu <= ETH_DATA_LEN)
+		rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
 
 	rtl_disable_clock_request(pdev);
 
@@ -4822,7 +4825,8 @@ static void rtl_hw_start_8168cp_2(struct rtl8169_private *tp)
 
 	RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en);
 
-	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+	if (tp->dev->mtu <= ETH_DATA_LEN)
+		rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
 
 	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
 }
@@ -4841,7 +4845,8 @@ static void rtl_hw_start_8168cp_3(struct rtl8169_private *tp)
 
 	RTL_W8(MaxTxPacketSize, TxPacketMax);
 
-	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+	if (tp->dev->mtu <= ETH_DATA_LEN)
+		rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
 
 	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
 }
@@ -4901,7 +4906,8 @@ static void rtl_hw_start_8168d(struct rtl8169_private *tp)
 
 	RTL_W8(MaxTxPacketSize, TxPacketMax);
 
-	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+	if (tp->dev->mtu <= ETH_DATA_LEN)
+		rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
 
 	RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
 }
@@ -4913,7 +4919,8 @@ static void rtl_hw_start_8168dp(struct rtl8169_private *tp)
 
 	rtl_csi_access_enable_1(tp);
 
-	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+	if (tp->dev->mtu <= ETH_DATA_LEN)
+		rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
 
 	RTL_W8(MaxTxPacketSize, TxPacketMax);
 
@@ -4972,7 +4979,8 @@ static void rtl_hw_start_8168e_1(struct rtl8169_private *tp)
 
 	rtl_ephy_init(tp, e_info_8168e_1, ARRAY_SIZE(e_info_8168e_1));
 
-	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+	if (tp->dev->mtu <= ETH_DATA_LEN)
+		rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
 
 	RTL_W8(MaxTxPacketSize, TxPacketMax);
 
@@ -4998,7 +5006,8 @@ static void rtl_hw_start_8168e_2(struct rtl8169_private *tp)
 
 	rtl_ephy_init(tp, e_info_8168e_2, ARRAY_SIZE(e_info_8168e_2));
 
-	rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+	if (tp->dev->mtu <= ETH_DATA_LEN)
+		rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
 
 	rtl_eri_write(tp, 0xc0, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
 	rtl_eri_write(tp, 0xb8, ERIAR_MASK_0011, 0x0000, ERIAR_EXGMAC);
-- 
1.8.1.2

^ permalink raw reply related

* Re: [PATCH] drivers/isdn: checkng length to be sure not memory overflow
From: Chen Gang @ 2013-02-28  1:45 UTC (permalink / raw)
  To: Jiri Slaby; +Cc: Jiri Kosina, isdn, Greg KH, alan, netdev
In-Reply-To: <512DE380.8080804@suse.cz>

于 2013年02月27日 18:44, Jiri Slaby 写道:
> On 02/27/2013 11:25 AM, Chen Gang wrote:
>> > 于 2013年02月27日 17:48, Jiri Slaby 写道:
>>> >> I have no idea if
>>> >> this is correct from the ISDN POV as we drop the end of the buffer
>> > 
>> >   pardon ?  what about "ISDN POV".
> "point of view" aka POV.
> 
> Hmm, "also known as" alias "aka" :).


  sorry, I still not quite understand (I am really not familiar with ISDN)

  so I have to bother you with 2 questions, please help reply, thanks.

    A) is our current patch OK ?
       a. yes, ok, need do nothing for it, just is waiting for Acked-by or applying.
       b. no, need improving (e.g. additional consideration, comments, or others)
       c. no, it is useless patch.

    B) does "ISDN POV" point to another issue ?
       if yes:
         I will read source code or search document on net, and should not bother you again.
         if possible, I can try to send relative patches, next.
       else (no):
         could you please say more details again ?
         I should improve current patch (also need let you as Signed-of-By)

  thanks.

  :-)

-- 
Chen Gang

Asianux Corporation

^ permalink raw reply

* [PATCH] drivers/isdn: break out of the loop after call isdn_tty_send_msg
From: Chen Gang @ 2013-02-28  2:57 UTC (permalink / raw)
  To: Jiri Slaby; +Cc: Jiri Kosina, isdn, Greg KH, Alan Cox, netdev
In-Reply-To: <512DD94C.2020008@suse.cz>


  need break out of the loop after call isdn_tty_send_msg.
    isdn_tty_send_msg is intended to eat the rest of the string.
    so need not scan again the string which appended "+M...".

Signed-off-by: Chen Gang <gang.chen@asianux.com>
---
 drivers/isdn/i4l/isdn_tty.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index d8a7d83..8ac7b33 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -3587,7 +3587,7 @@ isdn_tty_parse_at(modem_info *info)
 			case 'M':	/* MESSAGE */
 				p++;
 				isdn_tty_send_msg(info, m, p);
-				break;
+				goto tail;
 			default:
 				PARSE_ERROR;
 			}
@@ -3601,6 +3601,8 @@ isdn_tty_parse_at(modem_info *info)
 			PARSE_ERROR;
 		}
 	}
+
+tail:
 #ifdef CONFIG_ISDN_AUDIO
 	if (!info->vonline)
 #endif
-- 
1.7.7.6

^ permalink raw reply related

* Re: [RFC PATCH 2/3] ixgbe: Use default fdb handlers when not in VF mode.
From: John Fastabend @ 2013-02-28  4:26 UTC (permalink / raw)
  To: Vlad Yasevich; +Cc: netdev, davem, Rose, Gregory V
In-Reply-To: <1361987164-15280-3-git-send-email-vyasevic@redhat.com>

On 2/27/2013 9:46 AM, Vlad Yasevich wrote:
> Allow the use of ndo_dflt_fdb_<add|del|dump> when the
> adapter does not have VF configured.  This allows for
> IFF_UNICAST_FLT support and allows VF handling to potentially
> do something different.
>
> CC: John Fastabend <john.r.fastabend@intel.com>
> Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
> ---
>   drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |   26 ++++++++++--------------
>   1 files changed, 11 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> index 68478d6..0ae2525 100644
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> @@ -7007,7 +7007,7 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],

With the first patch we can just remove this routine altogether and
let the dflt handler do its work.

CC'd Greg in case I miss something.

>   	int err;
>
>   	if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
> -		return -EOPNOTSUPP;
> +		return ndo_dflt_fdb_add(ndm, tb, dev, addr, flags);
>
>   	/* Hardware does not support aging addresses so if a
>   	 * ndm_state is given only allow permanent addresses
> @@ -7045,20 +7045,21 @@ static int ixgbe_ndo_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],

same here just remove it and use the dflt handler.

>   	struct ixgbe_adapter *adapter = netdev_priv(dev);
>   	int err = -EOPNOTSUPP;
>
> +	if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
> +		return ndo_dflt_fdb_del(ndm, tb, dev, addr);
> +
>   	if (ndm->ndm_state & NUD_PERMANENT) {
>   		pr_info("%s: FDB only supports static addresses\n",
>   			ixgbe_driver_name);
>   		return -EINVAL;
>   	}
>
> -	if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
> -		if (is_unicast_ether_addr(addr))
> -			err = dev_uc_del(dev, addr);
> -		else if (is_multicast_ether_addr(addr))
> -			err = dev_mc_del(dev, addr);
> -		else
> -			err = -EINVAL;
> -	}
> +	if (is_unicast_ether_addr(addr))
> +		err = dev_uc_del(dev, addr);
> +	else if (is_multicast_ether_addr(addr))
> +		err = dev_mc_del(dev, addr);
> +	else
> +		err = -EINVAL;
>
>   	return err;
>   }
> @@ -7068,12 +7069,7 @@ static int ixgbe_ndo_fdb_dump(struct sk_buff *skb,
>   			      struct net_device *dev,
>   			      int idx)
>   {

This is the same as not defining the op at all right? Just
remove it.

> -	struct ixgbe_adapter *adapter = netdev_priv(dev);
> -
> -	if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
> -		idx = ndo_dflt_fdb_dump(skb, cb, dev, idx);
> -
> -	return idx;
> +	return ndo_dflt_fdb_dump(skb, cb, dev, idx);
>   }
>
>   static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
>

Then we get a patch with all '-' which is sort of nice.

^ permalink raw reply

* Re: [RFC PATCH 3/3] mlx4: Use default fdb handlers when not multifunction.
From: John Fastabend @ 2013-02-28  4:27 UTC (permalink / raw)
  To: Vlad Yasevich, Amir Vadai; +Cc: netdev, davem
In-Reply-To: <1361987164-15280-4-git-send-email-vyasevic@redhat.com>

On 2/27/2013 9:46 AM, Vlad Yasevich wrote:
> Allow the use of ndo_dflt_fdb_<add|del|dump> when the
> adapter is not configured with virtual functins (!mlx4_is_mfunc())
> This allows proper IFF_UNICAST_FLT support and allows for
> additional handling by the driver if needed.
>
> CC: Amir Vadai <amirv@mellanox.com>
> Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
> ---
>   drivers/net/ethernet/mellanox/mlx4/en_netdev.c |   12 +++---------
>   1 files changed, 3 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
> index 5385474..5732025 100644
> --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
> +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
> @@ -1934,7 +1934,7 @@ static int mlx4_en_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],

Amir are the default ops good enough here?

>   	int err;
>
>   	if (!mlx4_is_mfunc(mdev))
> -		return -EOPNOTSUPP;
> +		return ndo_dflt_fdb_add(ndm, tb, dev, addr, flags);
>
>   	/* Hardware does not support aging addresses, allow only
>   	 * permanent addresses if ndm_state is given
> @@ -1968,7 +1968,7 @@ static int mlx4_en_fdb_del(struct ndmsg *ndm,
>   	int err;
>
>   	if (!mlx4_is_mfunc(mdev))
> -		return -EOPNOTSUPP;
> +		return ndo_dflt_fdb_del(ndm, tb, dev, addr);
>
>   	if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
>   		en_info(priv, "Del FDB only supports static addresses\n");
> @@ -1989,13 +1989,7 @@ static int mlx4_en_fdb_dump(struct sk_buff *skb,
>   			    struct netlink_callback *cb,
>   			    struct net_device *dev, int idx)
>   {

same comment here. Don't define this op and we get the same behavior?



.John

^ permalink raw reply

* [PATCH 1/1 net-next] fec: net: put tx to napi poll function to fix dead lock
From: Frank Li @ 2013-02-28  3:44 UTC (permalink / raw)
  To: lznuaa, shawn.guo, B38611, davem, linux-arm-kernel, netdev
  Cc: s.hauer, Frank Li

up stack ndo_start_xmit already hold lock.
fec_enet_start_xmit needn't spin lock.
stat_xmit just update fep->cur_tx
fec_enet_tx just update fep->dirty_tx

Reserve a empty bdb to check full or empty
cur_tx == dirty_tx    means full
cur_tx == dirty_tx +1 means empty

So needn't is_full variable.

Fix spin lock deadlock
=================================
[ INFO: inconsistent lock state ]
3.8.0-rc5+ #107 Not tainted
---------------------------------
inconsistent {HARDIRQ-ON-W} -> {IN-HARDIRQ-W} usage.
ptp4l/615 [HC1[1]:SC0[0]:HE0:SE1] takes:
 (&(&list->lock)->rlock#3){?.-...}, at: [<8042c3c4>] skb_queue_tail+0x20/0x50
 {HARDIRQ-ON-W} state was registered at:
 [<80067250>] mark_lock+0x154/0x4e8
 [<800676f4>] mark_irqflags+0x110/0x1a4
 [<80069208>] __lock_acquire+0x494/0x9c0
 [<80069ce8>] lock_acquire+0x90/0xa4
 [<80527ad0>] _raw_spin_lock_bh+0x44/0x54
 [<804877e0>] first_packet_length+0x38/0x1f0
 [<804879e4>] udp_poll+0x4c/0x5c
 [<804231f8>] sock_poll+0x24/0x28
 [<800d27f0>] do_poll.isra.10+0x120/0x254
 [<800d36e4>] do_sys_poll+0x15c/0x1e8
 [<800d3828>] sys_poll+0x60/0xc8
 [<8000e780>] ret_fast_syscall+0x0/0x3c

 *** DEADLOCK ***

 1 lock held by ptp4l/615:
  #0:  (&(&fep->hw_lock)->rlock){-.-...}, at: [<80355f9c>] fec_enet_tx+0x24/0x268
  stack backtrace:
  Backtrace:
  [<800121e0>] (dump_backtrace+0x0/0x10c) from [<80516210>] (dump_stack+0x18/0x1c)
  r6:8063b1fc r5:bf38b2f8 r4:bf38b000 r3:bf38b000
  [<805161f8>] (dump_stack+0x0/0x1c) from [<805189d0>] (print_usage_bug.part.34+0x164/0x1a4)
  [<8051886c>] (print_usage_bug.part.34+0x0/0x1a4) from [<80518a88>] (print_usage_bug+0x78/0x88)
  r8:80065664 r7:bf38b2f8 r6:00000002 r5:00000000 r4:bf38b000
  [<80518a10>] (print_usage_bug+0x0/0x88) from [<80518b58>] (mark_lock_irq+0xc0/0x270)
  r7:bf38b000 r6:00000002 r5:bf38b2f8 r4:00000000
  [<80518a98>] (mark_lock_irq+0x0/0x270) from [<80067270>] (mark_lock+0x174/0x4e8)
  [<800670fc>] (mark_lock+0x0/0x4e8) from [<80067744>] (mark_irqflags+0x160/0x1a4)
  [<800675e4>] (mark_irqflags+0x0/0x1a4) from [<80069208>] (__lock_acquire+0x494/0x9c0)
  r5:00000002 r4:bf38b2f8
  [<80068d74>] (__lock_acquire+0x0/0x9c0) from [<80069ce8>] (lock_acquire+0x90/0xa4)
  [<80069c58>] (lock_acquire+0x0/0xa4) from [<805278d8>] (_raw_spin_lock_irqsave+0x4c/0x60)
  [<8052788c>] (_raw_spin_lock_irqsave+0x0/0x60) from [<8042c3c4>] (skb_queue_tail+0x20/0x50)
  r6:bfbb2180 r5:bf1d0190 r4:bf1d0184
  [<8042c3a4>] (skb_queue_tail+0x0/0x50) from [<8042c4cc>] (sock_queue_err_skb+0xd8/0x188)
  r6:00000056 r5:bfbb2180 r4:bf1d0000 r3:00000000
  [<8042c3f4>] (sock_queue_err_skb+0x0/0x188) from [<8042d15c>] (skb_tstamp_tx+0x70/0xa0)
  r6:bf0dddb0 r5:bf1d0000 r4:bfbb2180 r3:00000004
  [<8042d0ec>] (skb_tstamp_tx+0x0/0xa0) from [<803561d0>] (fec_enet_tx+0x258/0x268)
  r6:c089d260 r5:00001c00 r4:bfbd0000
  [<80355f78>] (fec_enet_tx+0x0/0x268) from [<803562cc>] (fec_enet_interrupt+0xec/0xf8)
  [<803561e0>] (fec_enet_interrupt+0x0/0xf8) from [<8007d5b0>] (handle_irq_event_percpu+0x54/0x1a0)
  [<8007d55c>] (handle_irq_event_percpu+0x0/0x1a0) from [<8007d740>] (handle_irq_event+0x44/0x64)
  [<8007d6fc>] (handle_irq_event+0x0/0x64) from [<80080690>] (handle_fasteoi_irq+0xc4/0x15c)
  r6:bf0dc000 r5:bf811290 r4:bf811240 r3:00000000
  [<800805cc>] (handle_fasteoi_irq+0x0/0x15c) from [<8007ceec>] (generic_handle_irq+0x28/0x38)
  r5:807130c8 r4:00000096
  [<8007cec4>] (generic_handle_irq+0x0/0x38) from [<8000f16c>] (handle_IRQ+0x54/0xb4)
  r4:8071d280 r3:00000180
  [<8000f118>] (handle_IRQ+0x0/0xb4) from [<80008544>] (gic_handle_irq+0x30/0x64)
  r8:8000e924 r7:f4000100 r6:bf0ddef8 r5:8071c974 r4:f400010c
  r3:00000000
  [<80008514>] (gic_handle_irq+0x0/0x64) from [<8000e2e4>] (__irq_svc+0x44/0x5c)
  Exception stack(0xbf0ddef8 to 0xbf0ddf40)

Signed-off-by: Frank Li <Frank.Li@freescale.com>
---
 drivers/net/ethernet/freescale/fec.c |  100 ++++++++++++++++++----------------
 drivers/net/ethernet/freescale/fec.h |    3 -
 2 files changed, 52 insertions(+), 51 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index 0fe68c4..d592965 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -246,14 +246,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	struct bufdesc *bdp;
 	void *bufaddr;
 	unsigned short	status;
-	unsigned long flags;
+	unsigned int index;
 
 	if (!fep->link) {
 		/* Link is down or autonegotiation is in progress. */
 		return NETDEV_TX_BUSY;
 	}
 
-	spin_lock_irqsave(&fep->hw_lock, flags);
 	/* Fill in a Tx ring entry */
 	bdp = fep->cur_tx;
 
@@ -264,7 +263,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		 * This should not happen, since ndev->tbusy should be set.
 		 */
 		printk("%s: tx queue full!.\n", ndev->name);
-		spin_unlock_irqrestore(&fep->hw_lock, flags);
 		return NETDEV_TX_BUSY;
 	}
 
@@ -280,13 +278,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	 * 4-byte boundaries. Use bounce buffers to copy data
 	 * and get it aligned. Ugh.
 	 */
+	if (fep->bufdesc_ex)
+		index = (struct bufdesc_ex *)bdp -
+			(struct bufdesc_ex *)fep->tx_bd_base;
+	else
+		index = bdp - fep->tx_bd_base;
+
 	if (((unsigned long) bufaddr) & FEC_ALIGNMENT) {
-		unsigned int index;
-		if (fep->bufdesc_ex)
-			index = (struct bufdesc_ex *)bdp -
-				(struct bufdesc_ex *)fep->tx_bd_base;
-		else
-			index = bdp - fep->tx_bd_base;
 		memcpy(fep->tx_bounce[index], skb->data, skb->len);
 		bufaddr = fep->tx_bounce[index];
 	}
@@ -300,10 +298,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 		swap_buffer(bufaddr, skb->len);
 
 	/* Save skb pointer */
-	fep->tx_skbuff[fep->skb_cur] = skb;
-
-	ndev->stats.tx_bytes += skb->len;
-	fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK;
+	fep->tx_skbuff[index] = skb;
 
 	/* Push the data cache so the CPM does not get stale memory
 	 * data.
@@ -331,26 +326,22 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 			ebdp->cbd_esc = BD_ENET_TX_INT;
 		}
 	}
-	/* Trigger transmission start */
-	writel(0, fep->hwp + FEC_X_DES_ACTIVE);
-
 	/* If this was the last BD in the ring, start at the beginning again. */
 	if (status & BD_ENET_TX_WRAP)
 		bdp = fep->tx_bd_base;
 	else
 		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
 
-	if (bdp == fep->dirty_tx) {
-		fep->tx_full = 1;
+	fep->cur_tx = bdp;
+
+	if (fep->cur_tx == fep->dirty_tx)
 		netif_stop_queue(ndev);
-	}
 
-	fep->cur_tx = bdp;
+	/* Trigger transmission start */
+	writel(0, fep->hwp + FEC_X_DES_ACTIVE);
 
 	skb_tx_timestamp(skb);
 
-	spin_unlock_irqrestore(&fep->hw_lock, flags);
-
 	return NETDEV_TX_OK;
 }
 
@@ -406,11 +397,8 @@ fec_restart(struct net_device *ndev, int duplex)
 		writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc)
 			* RX_RING_SIZE,	fep->hwp + FEC_X_DES_START);
 
-	fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;
 	fep->cur_rx = fep->rx_bd_base;
 
-	/* Reset SKB transmit buffers. */
-	fep->skb_cur = fep->skb_dirty = 0;
 	for (i = 0; i <= TX_RING_MOD_MASK; i++) {
 		if (fep->tx_skbuff[i]) {
 			dev_kfree_skb_any(fep->tx_skbuff[i]);
@@ -566,27 +554,47 @@ fec_timeout(struct net_device *ndev)
 	netif_wake_queue(ndev);
 }
 
-static void
+static int
 fec_enet_tx(struct net_device *ndev)
 {
 	struct	fec_enet_private *fep;
 	struct bufdesc *bdp;
 	unsigned short status;
 	struct	sk_buff	*skb;
+	int	pkts = 0;
+	int	index = 0;
+
+	if (IS_ERR(ndev))
+		return 0;
 
 	fep = netdev_priv(ndev);
-	spin_lock(&fep->hw_lock);
 	bdp = fep->dirty_tx;
 
+	/* get next bdp of dirty_tx */
+	if (bdp->cbd_sc & BD_ENET_TX_WRAP)
+		bdp = fep->tx_bd_base;
+	else
+		bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
+
 	while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
-		if (bdp == fep->cur_tx && fep->tx_full == 0)
+
+		/* current queue is empty */
+		if (bdp == fep->cur_tx)
 			break;
+		pkts++;
+
+		if (fep->bufdesc_ex)
+			index = (struct bufdesc_ex *)bdp -
+				(struct bufdesc_ex *)fep->tx_bd_base;
+		else
+			index = bdp - fep->tx_bd_base;
 
 		dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
 				FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE);
 		bdp->cbd_bufaddr = 0;
 
-		skb = fep->tx_skbuff[fep->skb_dirty];
+		skb = fep->tx_skbuff[index];
+
 		/* Check for errors. */
 		if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
 				   BD_ENET_TX_RL | BD_ENET_TX_UN |
@@ -631,8 +639,9 @@ fec_enet_tx(struct net_device *ndev)
 
 		/* Free the sk buffer associated with this last transmit */
 		dev_kfree_skb_any(skb);
-		fep->tx_skbuff[fep->skb_dirty] = NULL;
-		fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK;
+		fep->tx_skbuff[index] = NULL;
+
+		fep->dirty_tx = bdp;
 
 		/* Update pointer to next buffer descriptor to be transmitted */
 		if (status & BD_ENET_TX_WRAP)
@@ -642,14 +651,12 @@ fec_enet_tx(struct net_device *ndev)
 
 		/* Since we have freed up a buffer, the ring is no longer full
 		 */
-		if (fep->tx_full) {
-			fep->tx_full = 0;
+		if (fep->dirty_tx != fep->cur_tx) {
 			if (netif_queue_stopped(ndev))
 				netif_wake_queue(ndev);
 		}
 	}
-	fep->dirty_tx = bdp;
-	spin_unlock(&fep->hw_lock);
+	return pkts;
 }
 
 
@@ -816,7 +823,7 @@ fec_enet_interrupt(int irq, void *dev_id)
 		int_events = readl(fep->hwp + FEC_IEVENT);
 		writel(int_events, fep->hwp + FEC_IEVENT);
 
-		if (int_events & FEC_ENET_RXF) {
+		if (int_events & (FEC_ENET_RXF | FEC_ENET_TXF)) {
 			ret = IRQ_HANDLED;
 
 			/* Disable the RX interrupt */
@@ -827,15 +834,6 @@ fec_enet_interrupt(int irq, void *dev_id)
 			}
 		}
 
-		/* Transmit OK, or non-fatal error. Update the buffer
-		 * descriptors. FEC handles all errors, we just discover
-		 * them as part of the transmit process.
-		 */
-		if (int_events & FEC_ENET_TXF) {
-			ret = IRQ_HANDLED;
-			fec_enet_tx(ndev);
-		}
-
 		if (int_events & FEC_ENET_MII) {
 			ret = IRQ_HANDLED;
 			complete(&fep->mdio_done);
@@ -848,14 +846,18 @@ fec_enet_interrupt(int irq, void *dev_id)
 static int fec_enet_rx_napi(struct napi_struct *napi, int budget)
 {
 	struct net_device *ndev = napi->dev;
-	int pkts = fec_enet_rx(ndev, budget);
+	int rx_pkts = fec_enet_rx(ndev, budget);
 	struct fec_enet_private *fep = netdev_priv(ndev);
+	int tx_pkts = fec_enet_tx(ndev);
+
+	if (tx_pkts)
+		return budget;
 
-	if (pkts < budget) {
+	if (rx_pkts < budget) {
 		napi_complete(napi);
 		writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
 	}
-	return pkts;
+	return rx_pkts;
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1646,6 +1648,7 @@ static int fec_enet_init(struct net_device *ndev)
 
 	/* ...and the same for transmit */
 	bdp = fep->tx_bd_base;
+	fep->cur_tx = bdp;
 	for (i = 0; i < TX_RING_SIZE; i++) {
 
 		/* Initialize the BD for every fragment in the page. */
@@ -1657,6 +1660,7 @@ static int fec_enet_init(struct net_device *ndev)
 	/* Set the last buffer to wrap */
 	bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
 	bdp->cbd_sc |= BD_SC_WRAP;
+	fep->dirty_tx = bdp;
 
 	fec_restart(ndev, 0);
 
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 01579b8..c0f63be 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -214,8 +214,6 @@ struct fec_enet_private {
 	unsigned char *tx_bounce[TX_RING_SIZE];
 	struct	sk_buff *tx_skbuff[TX_RING_SIZE];
 	struct	sk_buff *rx_skbuff[RX_RING_SIZE];
-	ushort	skb_cur;
-	ushort	skb_dirty;
 
 	/* CPM dual port RAM relative addresses */
 	dma_addr_t	bd_dma;
@@ -227,7 +225,6 @@ struct fec_enet_private {
 	/* The ring entries to be free()ed */
 	struct bufdesc	*dirty_tx;
 
-	uint	tx_full;
 	/* hold while accessing the HW like ringbuffer for tx/rx but not MAC */
 	spinlock_t hw_lock;
 
-- 
1.7.1

^ permalink raw reply related

* Re: [PATCH 6/8] netfront: multi-page ring support
From: ANNIE LI @ 2013-02-28  5:19 UTC (permalink / raw)
  To: Wei Liu
  Cc: xen-devel@lists.xen.org, netdev@vger.kernel.org, Ian Campbell,
	konrad.wilk@oracle.com
In-Reply-To: <1361980154.2109.67.camel@zion.uk.xensource.com>



On 2013-2-27 23:49, Wei Liu wrote:
> On Wed, 2013-02-27 at 07:39 +0000, ANNIE LI wrote:
>> On 2013-2-26 20:35, Wei Liu wrote:
>>> On Tue, 2013-02-26 at 06:52 +0000, ANNIE LI wrote:
>>>> On 2013-2-16 0:00, Wei Liu wrote:
>>>>> Signed-off-by: Wei Liu<wei.liu2@citrix.com>
>>>>> ---
>>>>>     drivers/net/xen-netfront.c |  246 +++++++++++++++++++++++++++++++-------------
>>>>>     1 file changed, 174 insertions(+), 72 deletions(-)
>>>>>
>>>>> diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
>>>>> index 8bd75a1..de73a71 100644
>>>>> --- a/drivers/net/xen-netfront.c
>>>>> +++ b/drivers/net/xen-netfront.c
>>>>> @@ -67,9 +67,19 @@ struct netfront_cb {
>>>>>
>>>>>     #define GRANT_INVALID_REF   0
>>>>>
>>>>> -#define NET_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE)
>>>>> -#define NET_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE)
>>>>> -#define TX_MAX_TARGET min_t(int, NET_TX_RING_SIZE, 256)
>>>>> +#define XENNET_MAX_RING_PAGE_ORDER XENBUS_MAX_RING_PAGE_ORDER
>>>>> +#define XENNET_MAX_RING_PAGES      (1U<<    XENNET_MAX_RING_PAGE_ORDER)
>>>>> +
>>>>> +
>>>>> +#define NET_TX_RING_SIZE(_nr_pages)                  \
>>>>> +     __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE * (_nr_pages))
>>>>> +#define NET_RX_RING_SIZE(_nr_pages)                  \
>>>>> +     __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE * (_nr_pages))
>>>>> +
>>>>> +#define XENNET_MAX_TX_RING_SIZE NET_TX_RING_SIZE(XENNET_MAX_RING_PAGES)
>>>>> +#define XENNET_MAX_RX_RING_SIZE NET_RX_RING_SIZE(XENNET_MAX_RING_PAGES)
>>>>> +
>>>>> +#define TX_MAX_TARGET min_t(int, NET_TX_RING_SIZE(1), 256)
>>>> Not using multi-page ring here?
>>>> In xennet_create_dev, gnttab_alloc_grant_references allocates
>>>> TX_MAX_TARGET number of grant reference for tx. In
>>>> xennet_release_tx_bufs, NET_TX_RING_SIZE(np->tx_ring_pages) numbers of
>>>> grants are processed. And NET_RX_RING_SIZE(np->tx_ring_pages) is totally
>>>> different from TX_MAX_TARGET if np->rx_ring_pages is not 1. Although
>>>> skb_entry_is_link helps to not release invalid grants, lots of null loop
>>>> seems unnecessary. I think TX_MAX_TARGET should be changed into some
>>>> variableconnected with np->tx_ring_pages. Or you intended to use one
>>>> page ring here?
>>>>
>>> Looking back my history, this limitation was introduced because if we
>>> have a multi-page backend and single page frontend, the backend skb
>>> processing could overlap.
>> I did not see the overlap you mentioned here in netback. Although
>> netback supports multi-page, netback->vif still uses single page if the
>> frontend only supports single page. Netfront and netback negotiate this
>> through xenstore in your 5/8 patch. The requests and response should not
>> have any overlap between netback and netfront. Am I missing something?
>>
> I tried to dig up mail archive just now and realized that the bug report
> was in private mail exchange with Konrad.
>
> I don't really remember the details now since it is more than one year
> old, but you can find trace in Konrad's tree, CS 5b4c3dd5b255. All I can
> remember is that this bug was triggered by mixed old/new
> frontend/backend.

I checked the code in Konrad's tree and am thinking this overlap issue 
you mentioned existing in original netback(without multi-ring) and newer 
netfront. Original netback does not support multi-ring, and your newer 
netfront before this bug fix used "#define TX_MAX_TARGET 
XENNET_MAX_TX_RING_SIZE" directly. So that would cause overlap when 
netfront allocating rx skbs.
"#define TX_MAX_TARGET min_t(int, NET_TX_RING_SIZE(1), 256)" limits the 
netfront to single ring, it fixed the overlap issue, but not enough.

>
> I think this cap can be removed if we make all buffers in netfront
> dynamically allocated.

Yes, making TX_MAX_TARGET dynamically would fix this issue.

Thanks
Annie
>
>
> Wei.
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [RFC Patch net-next] vxlan: add ipv6 support
From: Cong Wang @ 2013-02-28  6:01 UTC (permalink / raw)
  To: netdev; +Cc: David S. Miller, Stephen Hemminger, Cong Wang

WARNING: This is just an RFC patch, it only compiles!!

This patch adds IPv6 support to vxlan device, as the new version
RFC already mentioned it:

	http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-03

I am not sure if the following trick will work:

	+       if (nla_len(nla) == sizeof(__be32)) {
	+               ip->ip4 = nla_get_be32(nla);
	+               ip->proto = htons(ETH_P_IP);
	+       }
	+#if IS_ENABLED(CONFIG_IPV6)
	+       else if (nla_len(nla) == sizeof(struct in6_addr)) {
	+               nla_memcpy(&ip->ip6, nla, sizeof(struct in6_addr));
	+               ip->proto = htons(ETH_P_IPV6);
	+       }
	+#endif

otherwise we have to introduce some new netlink attributes for
IPv6 addresses? Any comments?
 
Cc: David S. Miller <davem@davemloft.net>
Cc: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: Cong Wang <amwang@redhat.com>

---
 drivers/net/vxlan.c |  463 ++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 344 insertions(+), 119 deletions(-)

diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index f736823..6d6fc68 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -9,7 +9,6 @@
  *
  * TODO
  *  - use IANA UDP port number (when defined)
- *  - IPv6 (not in RFC)
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -42,6 +41,10 @@
 #include <net/inet_ecn.h>
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
+#if IS_ENABLED(CONFIG_IPV6)
+#include <net/addrconf.h>
+#include <net/ip6_route.h>
+#endif
 
 #define VXLAN_VERSION	"0.1"
 
@@ -78,16 +81,29 @@ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
 static unsigned int vxlan_net_id;
 struct vxlan_net {
 	struct socket	  *sock;	/* UDP encap socket */
+#if IS_ENABLED(CONFIG_IPV6)
+	struct socket	  *sock6;
+#endif
 	struct hlist_head vni_list[VNI_HASH_SIZE];
 };
 
+struct vxlan_ip {
+	union {
+		__be32  ip4;
+#if IS_ENABLED(CONFIG_IPV6)
+		struct in6_addr ip6;
+#endif
+	};
+	__be16          proto;
+};
+
 /* Forwarding table entry */
 struct vxlan_fdb {
 	struct hlist_node hlist;	/* linked list of entries */
 	struct rcu_head	  rcu;
 	unsigned long	  updated;	/* jiffies */
 	unsigned long	  used;
-	__be32		  remote_ip;
+	struct vxlan_ip	  remote_ip;
 	u16		  state;	/* see ndm_state */
 	u8		  eth_addr[ETH_ALEN];
 };
@@ -107,8 +123,8 @@ struct vxlan_dev {
 	struct net_device *dev;
 	struct vxlan_stats __percpu *stats;
 	__u32		  vni;		/* virtual network id */
-	__be32	          gaddr;	/* multicast group */
-	__be32		  saddr;	/* source address */
+	struct vxlan_ip	  gaddr;	/* multicast group */
+	struct vxlan_ip	  saddr;	/* source address */
 	unsigned int      link;		/* link to multicast over */
 	__u16		  port_min;	/* source port range */
 	__u16		  port_max;
@@ -131,6 +147,62 @@ struct vxlan_dev {
 #define VXLAN_F_L2MISS	0x08
 #define VXLAN_F_L3MISS	0x10
 
+static inline int vxlan_ip_equal(const struct vxlan_ip *a, const struct vxlan_ip *b)
+{
+	if (a->proto != b->proto)
+		return 0;
+	switch (a->proto) {
+	case htons(ETH_P_IP):
+		return a->ip4 == b->ip4;
+#if IS_ENABLED(CONFIG_IPV6)
+	case htons(ETH_P_IPV6):
+		return ipv6_addr_equal(&a->ip6, &b->ip6);
+#endif
+	}
+	return 0;
+}
+
+static inline bool vxlan_ip_any(const struct vxlan_ip *ipa)
+{
+#if IS_ENABLED(CONFIG_IPV6)
+	if (ipa->proto == htons(ETH_P_IP))
+		return ipa->ip4 == htonl(INADDR_ANY);
+	else
+		return ipv6_addr_any(&ipa->ip6);
+#else
+	return ipa->ip4 == htonl(INADDR_ANY);
+#endif
+}
+
+static int vxlan_nla_get_addr(struct vxlan_ip *ip, struct nlattr *nla)
+{
+	if (nla_len(nla) == sizeof(__be32)) {
+		ip->ip4 = nla_get_be32(nla);
+		ip->proto = htons(ETH_P_IP);
+	}
+#if IS_ENABLED(CONFIG_IPV6)
+	else if (nla_len(nla) == sizeof(struct in6_addr)) {
+		nla_memcpy(&ip->ip6, nla, sizeof(struct in6_addr));
+		ip->proto = htons(ETH_P_IPV6);
+	}
+#endif
+	else
+		return -EAFNOSUPPORT;
+	return 0;
+}
+
+static int vxlan_nla_put_addr(struct sk_buff *skb, int attr, const struct vxlan_ip *ip)
+{
+	if (ip->proto == htons(ETH_P_IP))
+		return nla_put_be32(skb, attr, ip->ip4);
+#if IS_ENABLED(CONFIG_IPV6)
+	else if (ip->proto == htons(ETH_P_IPV6))
+		return nla_put(skb, attr, sizeof(struct in6_addr), &ip->ip6);
+#endif
+	else
+		return -EAFNOSUPPORT;
+}
+
 /* salt for hash table */
 static u32 vxlan_salt __read_mostly;
 
@@ -177,7 +249,7 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan,
 
 	if (type == RTM_GETNEIGH) {
 		ndm->ndm_family	= AF_INET;
-		send_ip = fdb->remote_ip != 0;
+		send_ip = fdb->remote_ip.proto != 0;
 		send_eth = !is_zero_ether_addr(fdb->eth_addr);
 	} else
 		ndm->ndm_family	= AF_BRIDGE;
@@ -189,7 +261,7 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan,
 	if (send_eth && nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->eth_addr))
 		goto nla_put_failure;
 
-	if (send_ip && nla_put_be32(skb, NDA_DST, fdb->remote_ip))
+	if (send_ip && vxlan_nla_put_addr(skb, NDA_DST, &fdb->remote_ip))
 		goto nla_put_failure;
 
 	ci.ndm_used	 = jiffies_to_clock_t(now - fdb->used);
@@ -211,7 +283,7 @@ static inline size_t vxlan_nlmsg_size(void)
 {
 	return NLMSG_ALIGN(sizeof(struct ndmsg))
 		+ nla_total_size(ETH_ALEN) /* NDA_LLADDR */
-		+ nla_total_size(sizeof(__be32)) /* NDA_DST */
+		+ nla_total_size(sizeof(struct in6_addr)) /* NDA_DST */
 		+ nla_total_size(sizeof(struct nda_cacheinfo));
 }
 
@@ -241,14 +313,14 @@ errout:
 		rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
 }
 
-static void vxlan_ip_miss(struct net_device *dev, __be32 ipa)
+static void vxlan_ip_miss(struct net_device *dev, struct vxlan_ip *ipa)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	struct vxlan_fdb f;
 
 	memset(&f, 0, sizeof f);
 	f.state = NUD_STALE;
-	f.remote_ip = ipa; /* goes to NDA_DST */
+	f.remote_ip = *ipa; /* goes to NDA_DST */
 
 	vxlan_fdb_notify(vxlan, &f, RTM_GETNEIGH);
 }
@@ -304,7 +376,7 @@ static struct vxlan_fdb *vxlan_find_mac(struct vxlan_dev *vxlan,
 
 /* Add new entry to forwarding table -- assumes lock held */
 static int vxlan_fdb_create(struct vxlan_dev *vxlan,
-			    const u8 *mac, __be32 ip,
+			    const u8 *mac, struct vxlan_ip *ip,
 			    __u16 state, __u16 flags)
 {
 	struct vxlan_fdb *f;
@@ -335,7 +407,7 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan,
 			return -ENOMEM;
 
 		notify = 1;
-		f->remote_ip = ip;
+		f->remote_ip = *ip;
 		f->state = state;
 		f->updated = f->used = jiffies;
 		memcpy(f->eth_addr, mac, ETH_ALEN);
@@ -369,7 +441,7 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 			 const unsigned char *addr, u16 flags)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
-	__be32 ip;
+	struct vxlan_ip ip;
 	int err;
 
 	if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_REACHABLE))) {
@@ -381,13 +453,12 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
 	if (tb[NDA_DST] == NULL)
 		return -EINVAL;
 
-	if (nla_len(tb[NDA_DST]) != sizeof(__be32))
-		return -EAFNOSUPPORT;
-
-	ip = nla_get_be32(tb[NDA_DST]);
+	err = vxlan_nla_get_addr(&ip, tb[NDA_DST]);
+	if (err)
+		return err;
 
 	spin_lock_bh(&vxlan->hash_lock);
-	err = vxlan_fdb_create(vxlan, addr, ip, ndm->ndm_state, flags);
+	err = vxlan_fdb_create(vxlan, addr, &ip, ndm->ndm_state, flags);
 	spin_unlock_bh(&vxlan->hash_lock);
 
 	return err;
@@ -448,7 +519,7 @@ skip:
  * and Tunnel endpoint.
  */
 static void vxlan_snoop(struct net_device *dev,
-			__be32 src_ip, const u8 *src_mac)
+			struct vxlan_ip *src_ip, const u8 *src_mac)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	struct vxlan_fdb *f;
@@ -457,7 +528,7 @@ static void vxlan_snoop(struct net_device *dev,
 	f = vxlan_find_mac(vxlan, src_mac);
 	if (likely(f)) {
 		f->used = jiffies;
-		if (likely(f->remote_ip == src_ip))
+		if (likely(vxlan_ip_equal(&f->remote_ip, src_ip)))
 			return;
 
 		if (net_ratelimit())
@@ -465,7 +536,7 @@ static void vxlan_snoop(struct net_device *dev,
 				    "%pM migrated from %pI4 to %pI4\n",
 				    src_mac, &f->remote_ip, &src_ip);
 
-		f->remote_ip = src_ip;
+		f->remote_ip = *src_ip;
 		f->updated = jiffies;
 	} else {
 		/* learned new entry */
@@ -494,7 +565,7 @@ static bool vxlan_group_used(struct vxlan_net *vn,
 			if (!netif_running(vxlan->dev))
 				continue;
 
-			if (vxlan->gaddr == this->gaddr)
+			if (vxlan_ip_equal(&vxlan->gaddr, &this->gaddr))
 				return true;
 		}
 
@@ -506,9 +577,9 @@ static int vxlan_join_group(struct net_device *dev)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
-	struct sock *sk = vn->sock->sk;
+	struct sock *sk;
 	struct ip_mreqn mreq = {
-		.imr_multiaddr.s_addr	= vxlan->gaddr,
+		.imr_multiaddr.s_addr	= vxlan->gaddr.ip4,
 		.imr_ifindex		= vxlan->link,
 	};
 	int err;
@@ -519,8 +590,17 @@ static int vxlan_join_group(struct net_device *dev)
 
 	/* Need to drop RTNL to call multicast join */
 	rtnl_unlock();
-	lock_sock(sk);
-	err = ip_mc_join_group(sk, &mreq);
+	if (vxlan->gaddr.proto == htons(ETH_P_IP)) {
+		sk = vn->sock->sk;
+		lock_sock(sk);
+		err = ip_mc_join_group(sk, &mreq);
+	} else {
+#if IS_ENABLED(CONFIG_IPV6)
+		sk = vn->sock6->sk;
+		lock_sock(sk);
+		err = ipv6_sock_mc_join(sk, vxlan->link, &vxlan->gaddr.ip6);
+#endif
+	}
 	release_sock(sk);
 	rtnl_lock();
 
@@ -534,9 +614,9 @@ static int vxlan_leave_group(struct net_device *dev)
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
 	int err = 0;
-	struct sock *sk = vn->sock->sk;
+	struct sock *sk;
 	struct ip_mreqn mreq = {
-		.imr_multiaddr.s_addr	= vxlan->gaddr,
+		.imr_multiaddr.s_addr	= vxlan->gaddr.ip4,
 		.imr_ifindex		= vxlan->link,
 	};
 
@@ -546,8 +626,17 @@ static int vxlan_leave_group(struct net_device *dev)
 
 	/* Need to drop RTNL to call multicast leave */
 	rtnl_unlock();
-	lock_sock(sk);
-	err = ip_mc_leave_group(sk, &mreq);
+	if (vxlan->gaddr.proto == htons(ETH_P_IP)) {
+		sk = vn->sock->sk;
+		lock_sock(sk);
+		err = ip_mc_leave_group(sk, &mreq);
+	} else {
+#if IS_ENABLED(CONFIG_IPV6)
+		sk = vn->sock6->sk;
+		lock_sock(sk);
+		err = ipv6_sock_mc_drop(sk, vxlan->link, &vxlan->gaddr.ip6);
+#endif
+	}
 	release_sock(sk);
 	rtnl_lock();
 
@@ -557,10 +646,12 @@ static int vxlan_leave_group(struct net_device *dev)
 /* Callback from net/ipv4/udp.c to receive packets */
 static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
-	struct iphdr *oip;
+	struct iphdr *oip = NULL;
+	struct ipv6hdr *oip6 = NULL;
 	struct vxlanhdr *vxh;
 	struct vxlan_dev *vxlan;
 	struct vxlan_stats *stats;
+	struct vxlan_ip src_ip;
 	__u32 vni;
 	int err;
 
@@ -599,7 +690,13 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 	skb_reset_mac_header(skb);
 
 	/* Re-examine inner Ethernet packet */
-	oip = ip_hdr(skb);
+	if (skb->protocol == htons(ETH_P_IP))
+		oip = ip_hdr(skb);
+#if IS_ENABLED(CONFIG_IPV6)
+	else
+		oip6 = ipv6_hdr(skb);
+#endif
+
 	skb->protocol = eth_type_trans(skb, vxlan->dev);
 
 	/* Ignore packet loops (and multicast echo) */
@@ -607,8 +704,19 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 			       vxlan->dev->dev_addr) == 0)
 		goto drop;
 
-	if (vxlan->flags & VXLAN_F_LEARN)
-		vxlan_snoop(skb->dev, oip->saddr, eth_hdr(skb)->h_source);
+	if (vxlan->flags & VXLAN_F_LEARN) {
+		if (oip) {
+			src_ip.ip4 = oip->saddr;
+			src_ip.proto = htons(ETH_P_IP);
+		}
+#if IS_ENABLED(CONFIG_IPV6)
+		if (oip6) {
+			src_ip.ip6 = oip6->saddr;
+			src_ip.proto = ETH_P_IPV6;
+		}
+#endif
+		vxlan_snoop(skb->dev, &src_ip, eth_hdr(skb)->h_source);
+	}
 
 	__skb_tunnel_rx(skb, vxlan->dev);
 	skb_reset_network_header(skb);
@@ -663,6 +771,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
 	u8 *arpptr, *sha;
 	__be32 sip, tip;
 	struct neighbour *n;
+	struct vxlan_ip ipa;
 
 	if (dev->flags & IFF_NOARP)
 		goto out;
@@ -705,7 +814,7 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
 		}
 
 		f = vxlan_find_mac(vxlan, n->ha);
-		if (f && f->remote_ip == 0) {
+		if (f && f->remote_ip.proto == 0) {
 			/* bridge-local neighbor */
 			neigh_release(n);
 			goto out;
@@ -723,8 +832,11 @@ static int arp_reduce(struct net_device *dev, struct sk_buff *skb)
 
 		if (netif_rx_ni(reply) == NET_RX_DROP)
 			dev->stats.rx_dropped++;
-	} else if (vxlan->flags & VXLAN_F_L3MISS)
-		vxlan_ip_miss(dev, tip);
+	} else if (vxlan->flags & VXLAN_F_L3MISS) {
+		ipa.ip4 = tip;
+		ipa.proto = htons(ETH_P_IP);
+		vxlan_ip_miss(dev, &ipa);
+	}
 out:
 	consume_skb(skb);
 	return NETDEV_TX_OK;
@@ -746,6 +858,14 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
 			return false;
 		pip = ip_hdr(skb);
 		n = neigh_lookup(&arp_tbl, &pip->daddr, dev);
+		if (!n && vxlan->flags & VXLAN_F_L3MISS) {
+			struct vxlan_ip ipa;
+			ipa.ip4 = pip->daddr;
+			ipa.proto = htons(ETH_P_IP);
+			vxlan_ip_miss(dev, &ipa);
+			return false;
+		}
+
 		break;
 	default:
 		return false;
@@ -762,17 +882,17 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
 		}
 		neigh_release(n);
 		return diff;
-	} else if (vxlan->flags & VXLAN_F_L3MISS)
-		vxlan_ip_miss(dev, pip->daddr);
+	}
+
 	return false;
 }
 
 /* Extract dsfield from inner protocol */
-static inline u8 vxlan_get_dsfield(const struct iphdr *iph,
+static inline u8 vxlan_get_dsfield(const void *iph,
 				   const struct sk_buff *skb)
 {
 	if (skb->protocol == htons(ETH_P_IP))
-		return iph->tos;
+		return ((struct iphdr *)iph)->tos;
 	else if (skb->protocol == htons(ETH_P_IPV6))
 		return ipv6_get_dsfield((const struct ipv6hdr *)iph);
 	else
@@ -795,10 +915,11 @@ static void vxlan_sock_free(struct sk_buff *skb)
 }
 
 /* On transmit, associate with the tunnel socket */
-static void vxlan_set_owner(struct net_device *dev, struct sk_buff *skb)
+static inline void vxlan_set_owner(struct net_device *dev,
+				   struct sk_buff *skb, bool ipv6)
 {
 	struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
-	struct sock *sk = vn->sock->sk;
+	struct sock *sk = ipv6 ? vn->sock6->sk : vn->sock->sk;
 
 	skb_orphan(skb);
 	sock_hold(sk);
@@ -833,15 +954,16 @@ static u16 vxlan_src_port(const struct vxlan_dev *vxlan, struct sk_buff *skb)
 static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
-	struct rtable *rt;
-	const struct iphdr *old_iph;
+	const struct iphdr *old_iph = NULL;
+	const struct ipv6hdr *old_iph6 = NULL;
 	struct ethhdr *eth;
 	struct iphdr *iph;
+	struct ipv6hdr *ip6h;
 	struct vxlanhdr *vxh;
 	struct udphdr *uh;
-	struct flowi4 fl4;
 	unsigned int pkt_len = skb->len;
-	__be32 dst;
+	const struct vxlan_ip *dst;
+	struct dst_entry *ndst;
 	__u16 src_port;
 	__be16 df = 0;
 	__u8 tos, ttl;
@@ -860,14 +982,14 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
 	f = vxlan_find_mac(vxlan, eth->h_dest);
 	if (f == NULL) {
 		did_rsc = false;
-		dst = vxlan->gaddr;
-		if (!dst && (vxlan->flags & VXLAN_F_L2MISS) &&
+		dst = &vxlan->gaddr;
+		if (vxlan_ip_any(dst) && (vxlan->flags & VXLAN_F_L2MISS) &&
 		    !is_multicast_ether_addr(eth->h_dest))
 			vxlan_fdb_miss(vxlan, eth->h_dest);
 	} else
-		dst = f->remote_ip;
+		dst = &f->remote_ip;
 
-	if (!dst) {
+	if (vxlan_ip_any(dst)) {
 		if (did_rsc) {
 			__skb_pull(skb, skb_network_offset(skb));
 			skb->ip_summed = CHECKSUM_NONE;
@@ -900,43 +1022,83 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
 	if (skb_cow_head(skb, VXLAN_HEADROOM))
 		goto drop;
 
-	old_iph = ip_hdr(skb);
+	if (dst->proto == htons(ETH_P_IP)) {
+		struct flowi4 fl4;
+		struct rtable *rt;
 
-	ttl = vxlan->ttl;
-	if (!ttl && IN_MULTICAST(ntohl(dst)))
-		ttl = 1;
+		old_iph = ip_hdr(skb);
+		ttl = vxlan->ttl;
+		if (!ttl && IN_MULTICAST(ntohl(dst->ip4)))
+			ttl = 1;
 
-	tos = vxlan->tos;
-	if (tos == 1)
-		tos = vxlan_get_dsfield(old_iph, skb);
+		tos = vxlan->tos;
+		if (tos == 1)
+			tos = vxlan_get_dsfield(old_iph, skb);
 
-	src_port = vxlan_src_port(vxlan, skb);
+		src_port = vxlan_src_port(vxlan, skb);
 
-	memset(&fl4, 0, sizeof(fl4));
-	fl4.flowi4_oif = vxlan->link;
-	fl4.flowi4_tos = RT_TOS(tos);
-	fl4.daddr = dst;
-	fl4.saddr = vxlan->saddr;
+		memset(&fl4, 0, sizeof(fl4));
+		fl4.flowi4_oif = vxlan->link;
+		fl4.flowi4_tos = RT_TOS(tos);
+		fl4.daddr = dst->ip4;
+		fl4.saddr = vxlan->saddr.ip4;
 
-	rt = ip_route_output_key(dev_net(dev), &fl4);
-	if (IS_ERR(rt)) {
-		netdev_dbg(dev, "no route to %pI4\n", &dst);
-		dev->stats.tx_carrier_errors++;
-		goto tx_error;
-	}
+		rt = ip_route_output_key(dev_net(dev), &fl4);
+		if (IS_ERR(rt)) {
+			netdev_dbg(dev, "no route to %pI4\n", &dst->ip4);
+			dev->stats.tx_carrier_errors++;
+			goto tx_error;
+		}
+
+		if (rt->dst.dev == dev) {
+			netdev_dbg(dev, "circular route to %pI4\n", &dst->ip4);
+			ip_rt_put(rt);
+			dev->stats.collisions++;
+			goto tx_error;
+		}
+		ndst = &rt->dst;
+		memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+	} else {
+#if IS_ENABLED(CONFIG_IPV6)
+		struct flowi6 fl6;
+
+		old_iph6 = ipv6_hdr(skb);
+		ttl = vxlan->ttl;
+		if (!ttl && ipv6_addr_is_multicast(&dst->ip6))
+			ttl = 1;
+
+		tos = vxlan->tos;
+		if (tos == 1)
+			tos = vxlan_get_dsfield(old_iph6, skb);
+
+		src_port = vxlan_src_port(vxlan, skb);
+
+		memset(&fl6, 0, sizeof(fl6));
+		fl6.flowi6_oif = vxlan->link;
+		fl6.flowi6_tos = RT_TOS(tos);
+		fl6.daddr = dst->ip6;
+		fl6.saddr = vxlan->saddr.ip6;
+
+		ndst = ip6_route_output(dev_net(dev), NULL, &fl6);
+		if (ndst->error) {
+			netdev_dbg(dev, "no route to %pI6\n", &dst->ip6);
+			dev->stats.tx_carrier_errors++;
+			goto tx_error;
+		}
 
-	if (rt->dst.dev == dev) {
-		netdev_dbg(dev, "circular route to %pI4\n", &dst);
-		ip_rt_put(rt);
-		dev->stats.collisions++;
-		goto tx_error;
+		if (ndst->dev == dev) {
+			netdev_dbg(dev, "circular route to %pI6\n", &dst->ip6);
+			dst_release(ndst);
+			dev->stats.collisions++;
+			goto tx_error;
+		}
+#endif
 	}
 
-	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
 	IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
 			      IPSKB_REROUTED);
 	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->dst);
+	skb_dst_set(skb, ndst);
 
 	vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
 	vxh->vx_flags = htonl(VXLAN_FLAGS);
@@ -952,20 +1114,36 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev)
 	uh->len = htons(skb->len);
 	uh->check = 0;
 
-	__skb_push(skb, sizeof(*iph));
-	skb_reset_network_header(skb);
-	iph		= ip_hdr(skb);
-	iph->version	= 4;
-	iph->ihl	= sizeof(struct iphdr) >> 2;
-	iph->frag_off	= df;
-	iph->protocol	= IPPROTO_UDP;
-	iph->tos	= vxlan_ecn_encap(tos, old_iph, skb);
-	iph->daddr	= dst;
-	iph->saddr	= fl4.saddr;
-	iph->ttl	= ttl ? : ip4_dst_hoplimit(&rt->dst);
-	tunnel_ip_select_ident(skb, old_iph, &rt->dst);
-
-	vxlan_set_owner(dev, skb);
+	if (dst->proto == htons(ETH_P_IP)) {
+		__skb_push(skb, sizeof(*iph));
+		skb_reset_network_header(skb);
+		iph		= ip_hdr(skb);
+		iph->version	= 4;
+		iph->ihl	= sizeof(struct iphdr) >> 2;
+		iph->frag_off	= df;
+		iph->protocol	= IPPROTO_UDP;
+		iph->tos	= vxlan_ecn_encap(tos, old_iph, skb);
+		iph->daddr	= dst->ip4;
+		iph->saddr	= vxlan->saddr.ip4;
+		iph->ttl	= ttl ? : ip4_dst_hoplimit(ndst);
+		tunnel_ip_select_ident(skb, old_iph, ndst);
+
+		vxlan_set_owner(dev, skb, false);
+	} else {
+#if IS_ENABLED(CONFIG_IPV6)
+		__skb_push(skb, sizeof(*ip6h));
+		skb_reset_network_header(skb);
+		ip6h		  = ipv6_hdr(skb);
+		ip6h->version	  = 6;
+		ip6h->payload_len = htons(skb->len - sizeof(*ip6h));
+		ip6h->nexthdr     = IPPROTO_UDP;
+		ip6h->hop_limit   = ttl ? : ip6_dst_hoplimit(ndst);
+		ip6h->daddr	  = dst->ip6;
+		ip6h->saddr	  = vxlan->saddr.ip6;
+
+		vxlan_set_owner(dev, skb, true);
+#endif
+	}
 
 	/* See iptunnel_xmit() */
 	if (skb->ip_summed != CHECKSUM_PARTIAL)
@@ -1051,7 +1229,7 @@ static int vxlan_open(struct net_device *dev)
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	int err;
 
-	if (vxlan->gaddr) {
+	if (!vxlan_ip_any(&vxlan->gaddr)) {
 		err = vxlan_join_group(dev);
 		if (err)
 			return err;
@@ -1085,7 +1263,7 @@ static int vxlan_stop(struct net_device *dev)
 {
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 
-	if (vxlan->gaddr)
+	if (!vxlan_ip_any(&vxlan->gaddr))
 		vxlan_leave_group(dev);
 
 	del_timer_sync(&vxlan->age_timer);
@@ -1253,10 +1431,19 @@ static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
 	}
 
 	if (data[IFLA_VXLAN_GROUP]) {
-		__be32 gaddr = nla_get_be32(data[IFLA_VXLAN_GROUP]);
-		if (!IN_MULTICAST(ntohl(gaddr))) {
-			pr_debug("group address is not IPv4 multicast\n");
-			return -EADDRNOTAVAIL;
+		if (nla_len(data[IFLA_VXLAN_GROUP]) == sizeof(__be32)) {
+			__be32 gaddr = nla_get_be32(data[IFLA_VXLAN_GROUP]);
+			if (!IN_MULTICAST(ntohl(gaddr))) {
+				pr_debug("group address is not IPv4 multicast\n");
+				return -EADDRNOTAVAIL;
+			}
+		} else if (nla_len(data[IFLA_VXLAN_GROUP]) == sizeof(struct in6_addr)) {
+			struct in6_addr gaddr;
+			nla_memcpy(&gaddr, data[IFLA_VXLAN_GROUP], sizeof(struct in6_addr));
+			if (!ipv6_addr_is_multicast(&gaddr)) {
+				pr_debug("group address is not IPv6 multicast\n");
+				return -EADDRNOTAVAIL;
+			}
 		}
 	}
 
@@ -1304,10 +1491,10 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
 	vxlan->vni = vni;
 
 	if (data[IFLA_VXLAN_GROUP])
-		vxlan->gaddr = nla_get_be32(data[IFLA_VXLAN_GROUP]);
+		vxlan_nla_get_addr(&vxlan->gaddr, data[IFLA_VXLAN_GROUP]);
 
 	if (data[IFLA_VXLAN_LOCAL])
-		vxlan->saddr = nla_get_be32(data[IFLA_VXLAN_LOCAL]);
+		vxlan_nla_get_addr(&vxlan->saddr, data[IFLA_VXLAN_LOCAL]);
 
 	if (data[IFLA_VXLAN_LINK] &&
 	    (vxlan->link = nla_get_u32(data[IFLA_VXLAN_LINK]))) {
@@ -1385,9 +1572,9 @@ static size_t vxlan_get_size(const struct net_device *dev)
 {
 
 	return nla_total_size(sizeof(__u32)) +	/* IFLA_VXLAN_ID */
-		nla_total_size(sizeof(__be32)) +/* IFLA_VXLAN_GROUP */
+		nla_total_size(sizeof(struct in6_addr)) + /* IFLA_VXLAN_GROUP */
 		nla_total_size(sizeof(__u32)) +	/* IFLA_VXLAN_LINK */
-		nla_total_size(sizeof(__be32))+	/* IFLA_VXLAN_LOCAL */
+		nla_total_size(sizeof(struct in6_addr)) + /* IFLA_VXLAN_LOCAL */
 		nla_total_size(sizeof(__u8)) +	/* IFLA_VXLAN_TTL */
 		nla_total_size(sizeof(__u8)) +	/* IFLA_VXLAN_TOS */
 		nla_total_size(sizeof(__u8)) +	/* IFLA_VXLAN_LEARNING */
@@ -1412,13 +1599,13 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
 	if (nla_put_u32(skb, IFLA_VXLAN_ID, vxlan->vni))
 		goto nla_put_failure;
 
-	if (vxlan->gaddr && nla_put_be32(skb, IFLA_VXLAN_GROUP, vxlan->gaddr))
+	if (!vxlan_ip_any(&vxlan->gaddr) && vxlan_nla_put_addr(skb, IFLA_VXLAN_GROUP, &vxlan->gaddr))
 		goto nla_put_failure;
 
 	if (vxlan->link && nla_put_u32(skb, IFLA_VXLAN_LINK, vxlan->link))
 		goto nla_put_failure;
 
-	if (vxlan->saddr && nla_put_be32(skb, IFLA_VXLAN_LOCAL, vxlan->saddr))
+	if (!vxlan_ip_any(&vxlan->saddr) && vxlan_nla_put_addr(skb, IFLA_VXLAN_LOCAL, &vxlan->saddr))
 		goto nla_put_failure;
 
 	if (nla_put_u8(skb, IFLA_VXLAN_TTL, vxlan->ttl) ||
@@ -1458,39 +1645,35 @@ static struct rtnl_link_ops vxlan_link_ops __read_mostly = {
 	.fill_info	= vxlan_fill_info,
 };
 
-static __net_init int vxlan_init_net(struct net *net)
+static __net_init int vxlan_init_sock(struct net *net, struct socket **sock,
+				      struct sockaddr *addr)
 {
-	struct vxlan_net *vn = net_generic(net, vxlan_net_id);
 	struct sock *sk;
-	struct sockaddr_in vxlan_addr = {
-		.sin_family = AF_INET,
-		.sin_addr.s_addr = htonl(INADDR_ANY),
-	};
-	int rc;
-	unsigned h;
+	int val = 1, rc;
 
 	/* Create UDP socket for encapsulation receive. */
-	rc = sock_create_kern(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &vn->sock);
+	rc = sock_create_kern(addr->sa_family, SOCK_DGRAM, IPPROTO_UDP, sock);
 	if (rc < 0) {
 		pr_debug("UDP socket create failed\n");
 		return rc;
 	}
 	/* Put in proper namespace */
-	sk = vn->sock->sk;
+	sk = (*sock)->sk;
 	sk_change_net(sk, net);
 
-	vxlan_addr.sin_port = htons(vxlan_port);
-
-	rc = kernel_bind(vn->sock, (struct sockaddr *) &vxlan_addr,
-			 sizeof(vxlan_addr));
+	rc = kernel_bind(*sock, addr, addr->sa_family == AF_INET ?
+			 sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
 	if (rc < 0) {
-		pr_debug("bind for UDP socket %pI4:%u (%d)\n",
-			 &vxlan_addr.sin_addr, ntohs(vxlan_addr.sin_port), rc);
 		sk_release_kernel(sk);
-		vn->sock = NULL;
+		*sock = NULL;
 		return rc;
 	}
 
+#if IS_ENABLED(CONFIG_IPV6)
+	if (addr->sa_family == AF_INET6)
+		kernel_setsockopt(*sock, SOL_IPV6, IPV6_V6ONLY,
+				  (char *)&val, sizeof(val));
+#endif
 	/* Disable multicast loopback */
 	inet_sk(sk)->mc_loop = 0;
 
@@ -1498,6 +1681,42 @@ static __net_init int vxlan_init_net(struct net *net)
 	udp_sk(sk)->encap_type = 1;
 	udp_sk(sk)->encap_rcv = vxlan_udp_encap_recv;
 	udp_encap_enable();
+	return 0;
+}
+
+static __net_init int vxlan_init_net(struct net *net)
+{
+	struct vxlan_net *vn = net_generic(net, vxlan_net_id);
+	int rc;
+	unsigned h;
+	struct sockaddr_in vxlan_addr = {
+		.sin_family = AF_INET,
+		.sin_addr.s_addr = htonl(INADDR_ANY),
+		.sin_port = htons(vxlan_port),
+	};
+#if IS_ENABLED(CONFIG_IPV6)
+	struct sockaddr_in6 vxlan_addr6 = {
+		.sin6_family = AF_INET6,
+		.sin6_port = htons(vxlan_port),
+	};
+#endif
+
+	rc = vxlan_init_sock(net, &vn->sock, (struct sockaddr *)&vxlan_addr);
+	if (rc < 0) {
+		pr_debug("bind for UDP socket %pI4:%u (%d)\n",
+			 &vxlan_addr.sin_addr, ntohs(vxlan_addr.sin_port), rc);
+		return rc;
+	}
+#if IS_ENABLED(CONFIG_IPV6)
+	rc = vxlan_init_sock(net, &vn->sock6, (struct sockaddr *)&vxlan_addr6);
+	if (rc < 0) {
+		sk_release_kernel(vn->sock->sk);
+		vn->sock = NULL;
+		pr_debug("bind for UDP socket %pI6:%u (%d)\n",
+			 &vxlan_addr6.sin6_addr, ntohs(vxlan_addr6.sin6_port), rc);
+		return rc;
+	}
+#endif
 
 	for (h = 0; h < VNI_HASH_SIZE; ++h)
 		INIT_HLIST_HEAD(&vn->vni_list[h]);
@@ -1513,6 +1732,12 @@ static __net_exit void vxlan_exit_net(struct net *net)
 		sk_release_kernel(vn->sock->sk);
 		vn->sock = NULL;
 	}
+#if IS_ENABLED(CONFIG_IPV6)
+	if (vn->sock6) {
+		sk_release_kernel(vn->sock6->sk);
+		vn->sock6 = NULL;
+	}
+#endif
 }
 
 static struct pernet_operations vxlan_net_ops = {

^ permalink raw reply related

* Re: Fwd: [linux] [PATCH] ATH6KL: "Fix the byte alignment rule to avoid loss of bytes in a TCP segment" (#27)
From: Kalle Valo @ 2013-02-28  7:50 UTC (permalink / raw)
  To: Myoungje Kim
  Cc: Linus Torvalds, David Miller, Network Development, linux-wireless,
	John W. Linville, ath6kl-devel
In-Reply-To: <CABzs15BFOUWH=fMnerKW9-84PZKy5+2eN8XDhiCHTEHHjYf31w@mail.gmail.com>

Hi Myoungje,

(adding ath6kl-devel)

Myoungje Kim <mjei78@gmail.com> writes:

> How I appreciate your e-mail about my trivial patch.
> I am very happy due to receiving your reply(even though 'CC' ^^;)
>
> You don't need to count the ways you hate GitHub pull requests, 
> now I knew that enough ^^.
> It was the only easy way I've thought to commit to the main tree.
> You already know that I am very beginner.
>
>
> I'm ashamed to say that I spent about 3 weeks to find and debug this issue.
> My patch looks so simple,
> but I don't want anyone to trouble spending or wasting their time like me
> due to this issue makes me suspect all of linux kernel TCP/IP stack and curl,
> wget, ftp client, user HTTP client, library, everything of my system.
> So it made me to make pull request through github I`ve ever known as the way to
> commit.
>
> One more, now I knew that how to commit and how much I want to commit ^^.
> Thanks and have a good day~

No worries, it always takes some time to learn the process. And I hope
you send more ath6kl patches in the future :)

I'm on vacation right, but I will take a look at your patch next week.

BTW, I have documented the process of sending patches to ath6kl here:

http://wireless.kernel.org/en/users/Drivers/ath6kl#Hacking_on_ath6kl

Hopefully that helps. Please let me know if I need to improve it.

-- 
Kalle Valo

^ permalink raw reply

* [PATCH] net/8021q: beautify code, name_type is unsigned int, always >= 0
From: Chen Gang @ 2013-02-28  7:51 UTC (permalink / raw)
  To: kaber, David Miller; +Cc: netdev


  args.u.name_type is unsigned int, which is always >= 0

Signed-off-by: Chen Gang <gang.chen@asianux.com>
---
 net/8021q/vlan.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index a187144..0f5261a 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -571,8 +571,7 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg)
 		err = -EPERM;
 		if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
 			break;
-		if ((args.u.name_type >= 0) &&
-		    (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) {
+		if (args.u.name_type < VLAN_NAME_TYPE_HIGHEST) {
 			struct vlan_net *vn;
 
 			vn = net_generic(net, vlan_net_id);
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH 3/5] wl1251: call pm_runtime_put_sync in pm_runtime_get_sync failed case
From: Li Fei @ 2013-02-28  7:51 UTC (permalink / raw)
  To: coelho, linville, wfp5p, gregkh, notasas
  Cc: rjw, linux-wireless, netdev, linux-kernel, chuansheng.liu, fei.li
In-Reply-To: <1362037455.6212.8.camel@fli24-HP-Compaq-8100-Elite-CMT-PC>


Even in failed case of pm_runtime_get_sync, the usage_count
is incremented. In order to keep the usage_count with correct
value and runtime power management to behave correctly, call
pm_runtime_put(_sync) in such case.

Signed-off-by Liu Chuansheng <chuansheng.liu@intel.com>
Signed-off-by: Li Fei <fei.li@intel.com>
---
 drivers/net/wireless/ti/wl1251/sdio.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c
index e57ee48..e2b3d9c 100644
--- a/drivers/net/wireless/ti/wl1251/sdio.c
+++ b/drivers/net/wireless/ti/wl1251/sdio.c
@@ -186,8 +186,10 @@ static int wl1251_sdio_set_power(struct wl1251 *wl, bool enable)
 			wl->set_power(true);
 
 		ret = pm_runtime_get_sync(&func->dev);
-		if (ret < 0)
+		if (ret < 0) {
+			pm_runtime_put_sync(&func->dev);
 			goto out;
+		}
 
 		sdio_claim_host(func);
 		sdio_enable_func(func);
-- 
1.7.4.1

^ permalink raw reply related

* [PATCH ethtool] Restore 20000baseKR2 cap display
From: Yaniv Rosner @ 2013-02-28 10:10 UTC (permalink / raw)
  To: Ben Hutchings; +Cc: netdev, Yaniv Rosner

Restore the 20000baseKR2 which was removed by mistake back in June 2012.

Signed-off-by: Yaniv Rosner <yanivr@broadcom.com>
---
 ethtool.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/ethtool.c b/ethtool.c
index 55bc082..acac32a 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -513,6 +513,7 @@ dump_link_caps(const char *prefix, const char *an_prefix, u32 mask,
 		{ 0, ADVERTISED_10000baseT_Full,    "10000baseT/Full" },
 		{ 0, ADVERTISED_10000baseKX4_Full,  "10000baseKX4/Full" },
 		{ 0, ADVERTISED_20000baseMLD2_Full, "20000baseMLD2/Full" },
+		{ 0, ADVERTISED_20000baseKR2_Full,  "20000baseKR2/Full" },
 		{ 0, ADVERTISED_40000baseKR4_Full,  "40000baseKR4/Full" },
 		{ 0, ADVERTISED_40000baseCR4_Full,  "40000baseCR4/Full" },
 		{ 0, ADVERTISED_40000baseSR4_Full,  "40000baseSR4/Full" },
-- 
1.7.7.1

^ 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