* [patch net 0/3] mlxsw: Couple of fixes
From: Jiri Pirko @ 2016-05-06 9:17 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, eladr, yotamg, ogerlitz
From: Jiri Pirko <jiri@mellanox.com>
Ido Schimmel (2):
mlxsw: spectrum: Fix rollback order in LAG join failure
mlxsw: spectrum: Add missing rollback in flood configuration
Jiri Pirko (1):
mlxsw: spectrum: Fix ordering in mlxsw_sp_fini
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 5 +++--
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 8 ++++++++
2 files changed, 11 insertions(+), 2 deletions(-)
--
2.5.5
^ permalink raw reply
* [patch net 1/3] mlxsw: spectrum: Fix rollback order in LAG join failure
From: Jiri Pirko @ 2016-05-06 9:17 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, eladr, yotamg, ogerlitz
In-Reply-To: <1462526244-11898-1-git-send-email-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
Make the leave procedure in the error path symmetric to the join
procedure and first remove the port from the collector before
potentially destroying the LAG.
Fixes: 0d65fc13042f ("mlxsw: spectrum: Implement LAG port join/leave")
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 4afbc3e..668b2f4 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -2541,11 +2541,11 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port,
lag->ref_count++;
return 0;
+err_col_port_enable:
+ mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id);
err_col_port_add:
if (!lag->ref_count)
mlxsw_sp_lag_destroy(mlxsw_sp, lag_id);
-err_col_port_enable:
- mlxsw_sp_lag_col_port_remove(mlxsw_sp_port, lag_id);
return err;
}
--
2.5.5
^ permalink raw reply related
* [patch net 2/3] mlxsw: spectrum: Add missing rollback in flood configuration
From: Jiri Pirko @ 2016-05-06 9:17 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, eladr, yotamg, ogerlitz
In-Reply-To: <1462526244-11898-1-git-send-email-jiri@resnulli.us>
From: Ido Schimmel <idosch@mellanox.com>
When we fail to set the flooding configuration for the broadcast and
unregistered multicast traffic, we should revert the flooding
configuration of the unknown unicast traffic.
Fixes: 0293038e0c36 ("mlxsw: spectrum: Add support for flood control")
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index e1c74ef..9cd6f47 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -214,7 +214,15 @@ static int __mlxsw_sp_port_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BM, idx_begin,
table_type, range, local_port, set);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
+ if (err)
+ goto err_flood_bm_set;
+ else
+ goto buffer_out;
+err_flood_bm_set:
+ mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_UC, idx_begin,
+ table_type, range, local_port, !set);
+ mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl);
buffer_out:
kfree(sftr_pl);
return err;
--
2.5.5
^ permalink raw reply related
* [patch net 3/3] mlxsw: spectrum: Fix ordering in mlxsw_sp_fini
From: Jiri Pirko @ 2016-05-06 9:17 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, eladr, yotamg, ogerlitz
In-Reply-To: <1462526244-11898-1-git-send-email-jiri@resnulli.us>
From: Jiri Pirko <jiri@mellanox.com>
Fixes: 0f433fa0ec ("mlxsw: spectrum_buffers: Implement shared buffer configuration")
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index 668b2f4..749cc27 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -2159,6 +2159,7 @@ static void mlxsw_sp_fini(void *priv)
struct mlxsw_sp *mlxsw_sp = priv;
mlxsw_sp_switchdev_fini(mlxsw_sp);
+ mlxsw_sp_buffers_fini(mlxsw_sp);
mlxsw_sp_traps_fini(mlxsw_sp);
mlxsw_sp_event_unregister(mlxsw_sp, MLXSW_TRAP_ID_PUDE);
mlxsw_sp_ports_remove(mlxsw_sp);
--
2.5.5
^ permalink raw reply related
* Re: [PATCH v9 net-next 4/7] openvswitch: add layer 3 flow/port support
From: Jiri Benc @ 2016-05-06 9:25 UTC (permalink / raw)
To: Simon Horman
Cc: pravin shelar, Linux Kernel Network Developers, ovs dev,
Lorand Jakab, Thomas Morin
In-Reply-To: <20160506055705.GA9276@penelope.isobedori.kobe.vergenet.net>
On Fri, 6 May 2016 14:57:07 +0900, Simon Horman wrote:
> On Thu, May 05, 2016 at 10:37:08AM -0700, pravin shelar wrote:
> > On transmit side you are using mac_len to detect l3 packet, why not do
> > same while extracting the key?
I agree. The skb should be self-contained, i.e. it should be obvious
whether it has the MAC header set or not just from the skb itself at
any point in the packet processing. Otherwise, I'd expect things like
recirculation to break after push/pop of eth header.
> Unfortunately mac_len can't be relied on here, emprically it has the same
> value (28 in my tests) for both the TEB and layer3 case above.
That's strange, it looks like there's something setting the mac header
unconditionally in ovs code. We should find that place and change it.
The ARPHRD_NONE interfaces don't even set mac_header and mac_len, this
will need to be set by ovs upon getting frame from such interface.
> Perhaps that could be changed by futher enhancements in the tunneling code
> but I think things are symetric as they stand:
>
> * On recieve skb->protocol can be read to distinguish TEB and layer3 packets
> * On transmit skb->protocol should be set to distinguish TEB and layer3 packets
Yes, but you need to act upon this directly after receiving the
frame/just before sending the frame and set up an internal flag that
will be used throughout the code. That way, the packet can be handed
over to different parts of the code, recirculated, etc. without
worries. skb->mac_len is probably a good candidate for such flag.
Jiri
^ permalink raw reply
* Re: [PATCHv2 bluetooth-next 02/10] 6lowpan: add 802.15.4 short addr slaac
From: Alexander Aring @ 2016-05-06 9:26 UTC (permalink / raw)
To: Stefan Schmidt, linux-wpan
Cc: kernel, marcel, jukka.rissanen, hannes, mcr, werner,
linux-bluetooth, netdev, David S . Miller, Alexey Kuznetsov,
James Morris, Hideaki YOSHIFUJI, Patrick McHardy
In-Reply-To: <5728EB0A.5080108@osg.samsung.com>
Hi,
On 05/03/2016 08:16 PM, Stefan Schmidt wrote:
> Hello.
>
> On 20/04/16 10:19, Alexander Aring wrote:
>> This patch adds the autoconfiguration if a valid 802.15.4 short address
>> is available for 802.15.4 6LoWPAN interfaces.
>>
>> Cc: David S. Miller<davem@davemloft.net>
>> Cc: Alexey Kuznetsov<kuznet@ms2.inr.ac.ru>
>> Cc: James Morris<jmorris@namei.org>
>> Cc: Hideaki YOSHIFUJI<yoshfuji@linux-ipv6.org>
>> Cc: Patrick McHardy<kaber@trash.net>
>> Signed-off-by: Alexander Aring<aar@pengutronix.de>
>> ---
>> include/net/addrconf.h | 3 +++
>> net/6lowpan/core.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
>> net/ipv6/addrconf.c | 5 +++--
>> 3 files changed, 52 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/net/addrconf.h b/include/net/addrconf.h
>> index 730d856..b1774eb 100644
>> --- a/include/net/addrconf.h
>> +++ b/include/net/addrconf.h
>> @@ -94,6 +94,9 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2,
>> void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr);
>> void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr);
>> +void addrconf_add_linklocal(struct inet6_dev *idev,
>> + const struct in6_addr *addr, u32 flags);
>> +
>> static inline int addrconf_ifid_eui48(u8 *eui, struct net_device *dev)
>> {
>> if (dev->addr_len != ETH_ALEN)
>> diff --git a/net/6lowpan/core.c b/net/6lowpan/core.c
>> index 7a240b3..fbae31e 100644
>> --- a/net/6lowpan/core.c
>> +++ b/net/6lowpan/core.c
>> @@ -14,6 +14,7 @@
>> #include <linux/module.h>
>> #include <net/6lowpan.h>
>> +#include <net/addrconf.h>
>> #include "6lowpan_i.h"
>> @@ -72,16 +73,61 @@ void lowpan_unregister_netdev(struct net_device *dev)
>> }
>> EXPORT_SYMBOL(lowpan_unregister_netdev);
>> +static int addrconf_ifid_802154_6lowpan(u8 *eui, struct net_device *dev)
>> +{
>> + struct wpan_dev *wpan_dev = lowpan_802154_dev(dev)->wdev->ieee802154_ptr;
>> +
>> + /* Set short_addr autoconfiguration if short_addr is present only */
>> + if (!ieee802154_is_valid_src_short_addr(wpan_dev->short_addr))
>> + return -1;
>
> -EINVAL instead of -1?
>
The ipv6 implementation do that for the "dev->addr" slaac the same here.
I think the reason is because here, if this fails for any reason then
this is simple not an error, we just don't add a link-local for short
addr slaac here and don't abort completely the CHANGE/UP of interface.
IPv6 also use "-1" return value only if parsing fails, I would to see
that also for iphc stuff where we mixed a lot of "-EIO" and "-EINVAL",
anyway nobody will really care about that return value.
It just means: 0 parsing successful and -1 parsing failed.
- Alex
^ permalink raw reply
* Re: [PATCH v9 net-next 4/7] openvswitch: add layer 3 flow/port support
From: Jiri Benc @ 2016-05-06 9:35 UTC (permalink / raw)
To: Simon Horman; +Cc: netdev, dev, Lorand Jakab, Thomas Morin
In-Reply-To: <1462347393-22354-5-git-send-email-simon.horman@netronome.com>
On Wed, 4 May 2016 16:36:30 +0900, Simon Horman wrote:
> +static int push_eth(struct sk_buff *skb, struct sw_flow_key *key,
> + const struct ovs_action_push_eth *ethh)
> +{
> + int err;
> +
> + /* De-accelerate any hardware accelerated VLAN tag added to a previous
> + * Ethernet header */
> + err = skb_vlan_deaccel(skb);
> + if (unlikely(err))
> + return err;
> +
> + /* Add the new Ethernet header */
> + if (skb_cow_head(skb, ETH_HLEN) < 0)
> + return -ENOMEM;
> +
> + skb_push(skb, ETH_HLEN);
> + skb_reset_mac_header(skb);
> + skb_reset_mac_len(skb);
> +
> + ether_addr_copy(eth_hdr(skb)->h_source, ethh->addresses.eth_src);
> + ether_addr_copy(eth_hdr(skb)->h_dest, ethh->addresses.eth_dst);
> + eth_hdr(skb)->h_proto = ethh->eth_type;
This doesn't seem right. We know the packet type, it's skb->protocol.
We should fill in that.
In addition, we should check whether mac_len > 0 and in such case,
change skb->protocol to ETH_P_TEB first (and store that value in the
pushed eth header).
Similarly on pop_eth, we need to check skb->protocol and if it is
ETH_P_TEB, call eth_type_trans on the modified frame to set the new
skb->protocol correctly. It's probably not that simple, as we'd need a
version of eth_type_trans that doesn't need a net device.
Jiri
^ permalink raw reply
* Re: [PATCHv2 bluetooth-next 07/10] ipv6: introduce neighbour discovery ops
From: Alexander Aring @ 2016-05-06 9:36 UTC (permalink / raw)
To: Stefan Schmidt, Hannes Frederic Sowa,
linux-wpan-u79uwXL29TY76Z2rM5mHXA
Cc: kernel-bIcnvbaLZ9MEGnE8C9+IrQ, marcel-kz+m5ild9QBg9hUCZPvPmw,
jukka.rissanen-VuQAYsv1563Yd54FQh9/CA, mcr-SWp7JaYWvAQV+D8aMU/kSg,
werner-SEdMjqphH88wryQfseakQg,
linux-bluetooth-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, David S . Miller, Alexey Kuznetsov,
James Morris, Hideaki YOSHIFUJI, Patrick McHardy
In-Reply-To: <5728EB3F.2060808-JPH+aEBZ4P+UEJcrhfAQsw@public.gmane.org>
Hi,
On 05/03/2016 08:17 PM, Stefan Schmidt wrote:
> Hello.
>
> On 02/05/16 21:36, Hannes Frederic Sowa wrote:
>> On 20.04.2016 10:19, Alexander Aring wrote:
>>> This patch introduces neighbour discovery ops callback structure. The
>>> structure contains at first receive and transmit handling for NS/NA and
>>> userspace option field functionality.
>>>
>>> These callback offers 6lowpan different handling, such as 802.15.4 short
>>> address handling or RFC6775 (Neighbor Discovery Optimization for IPv6 over
>>> 6LoWPANs).
>>>
>>> Cc: David S. Miller<davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
>>> Cc: Alexey Kuznetsov<kuznet-v/Mj1YrvjDBInbfyfbPRSQ@public.gmane.org>
>>> Cc: James Morris<jmorris-gx6/JNMH7DfYtjvyW6yDsg@public.gmane.org>
>>> Cc: Hideaki YOSHIFUJI<yoshfuji-VfPWfsRibaP+Ru+s062T9g@public.gmane.org>
>>> Cc: Patrick McHardy<kaber-dcUjhNyLwpNeoWH0uzbU5w@public.gmane.org>
>>> Signed-off-by: Alexander Aring<aar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
>>> ---
>>> include/linux/netdevice.h | 3 ++
>>> include/net/ndisc.h | 96 +++++++++++++++++++++++++++++++++++++++++++----
>>> net/ipv6/addrconf.c | 1 +
>>> net/ipv6/ndisc.c | 71 ++++++++++++++++++++++++-----------
>>> net/ipv6/route.c | 2 +-
>>> 5 files changed, 144 insertions(+), 29 deletions(-)
>>>
>>> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>>> index 0052c42..bc60033 100644
>>> --- a/include/linux/netdevice.h
>>> +++ b/include/linux/netdevice.h
>>> @@ -1677,6 +1677,9 @@ struct net_device {
>>> #ifdef CONFIG_NET_L3_MASTER_DEV
>>> const struct l3mdev_ops *l3mdev_ops;
>>> #endif
>>> +#if IS_ENABLED(CONFIG_IPV6)
>>> + const struct ndisc_ops *ndisc_ops;
>>> +#endif
>>> const struct header_ops *header_ops;
>>> diff --git a/include/net/ndisc.h b/include/net/ndisc.h
>>> index aac868e..14ed016 100644
>>> --- a/include/net/ndisc.h
>>> +++ b/include/net/ndisc.h
>>> @@ -110,7 +110,8 @@ struct ndisc_options {
>>> #define NDISC_OPT_SPACE(len) (((len)+2+7)&~7)
>>> -struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
>>> +struct ndisc_options *ndisc_parse_options(const struct net_device *dev,
>>> + u8 *opt, int opt_len,
>>> struct ndisc_options *ndopts);
>>> /*
>>> @@ -173,6 +174,93 @@ static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, cons
>>> return n;
>>> }
>>> +static inline int __ip6_ndisc_is_useropt(struct nd_opt_hdr *opt)
>>> +{
>>> + return opt->nd_opt_type == ND_OPT_RDNSS ||
>>> + opt->nd_opt_type == ND_OPT_DNSSL;
>>> +}
>>> +
>>> +#if IS_ENABLED(CONFIG_IPV6)
>>> +struct ndisc_ops {
>>> + int (*is_useropt)(struct nd_opt_hdr *opt);
>>> + void (*send_na)(struct net_device *dev,
>>> + const struct in6_addr *daddr,
>>> + const struct in6_addr *solicited_addr,
>>> + bool router, bool solicited,
>>> + bool override, bool inc_opt);
>>> + void (*recv_na)(struct sk_buff *skb);
>>> + void (*send_ns)(struct net_device *dev,
>>> + const struct in6_addr *solicit,
>>> + const struct in6_addr *daddr,
>>> + const struct in6_addr *saddr);
>>> + void (*recv_ns)(struct sk_buff *skb);
>>> +};
>>> +
>>> +static inline int ndisc_is_useropt(const struct net_device *dev,
>>> + struct nd_opt_hdr *opt)
>>> +{
>>> + if (likely(dev->ndisc_ops->is_useropt))
>>> + return dev->ndisc_ops->is_useropt(opt);
>>> + else
>>> + return 0;
>>> +}
>>> +
>>> +static inline void ndisc_send_na(struct net_device *dev,
>>> + const struct in6_addr *daddr,
>>> + const struct in6_addr *solicited_addr,
>>> + bool router, bool solicited, bool override,
>>> + bool inc_opt)
>>> +{
>>> + if (likely(dev->ndisc_ops->send_na))
>>> + dev->ndisc_ops->send_na(dev, daddr, solicited_addr, router,
>>> + solicited, override, inc_opt);
>>> +}
>>> +
>>> +static inline void ndisc_recv_na(struct sk_buff *skb)
>>> +{
>>> + if (likely(skb->dev->ndisc_ops->recv_na))
>>> + skb->dev->ndisc_ops->recv_na(skb);
>>> +}
>>> +
>>> +static inline void ndisc_send_ns(struct net_device *dev,
>>> + const struct in6_addr *solicit,
>>> + const struct in6_addr *daddr,
>>> + const struct in6_addr *saddr)
>>> +{
>>> + if (likely(dev->ndisc_ops->send_ns))
>>> + dev->ndisc_ops->send_ns(dev, solicit, daddr, saddr);
>>> +}
>>> +
>>> +static inline void ndisc_recv_ns(struct sk_buff *skb)
>>> +{
>>> + if (likely(skb->dev->ndisc_ops->recv_ns))
>>> + skb->dev->ndisc_ops->recv_ns(skb);
>>> +}
>>> +#else
>>> +static inline int ndisc_is_useropt(const struct net_device *dev,
>>> + struct nd_opt_hdr *opt)
>>> +{
>>> + return 0;
>>> +}
>>> +
>>> +static inline void ndisc_send_na(struct net_device *dev,
>>> + const struct in6_addr *daddr,
>>> + const struct in6_addr *solicited_addr,
>>> + bool router, bool solicited, bool override,
>>> + bool inc_opt) { }
>>> +
>>> +static inline void ndisc_recv_na(struct sk_buff *skb) { }
>>> +
>>> +static inline void ndisc_send_ns(struct net_device *dev,
>>> + const struct in6_addr *solicit,
>>> + const struct in6_addr *daddr,
>>> + const struct in6_addr *saddr) { }
>>> +
>>> +static inline void ndisc_recv_ns(struct sk_buff *skb) { }
>>> +#endif
>> Do those empty functions actually make sense? I wonder a bit because
>> 6lowpan strictly depends on ipv6 and they should never be called without
>> IPv6, no?
>
> Agreed. 6LoWAPN is only an adaptation layer so we know that IPv6 must be enabled here. I would also argue for removing this ifdef and the empty functions.
>
I removed the empty function, removing ifdef is not possible. There are
still somewhere net/ipv6.h includes at do_mounts/networking filesystems.
I need to leave the ifdef there otherwise compiling will fail that
"ndisc->ops" are not available.
I tested it with several randconfigs.
- Alex
^ permalink raw reply
* OpenWRT wrong adjustment of fq_codel defaults (Was: fq_codel_drop vs a udp flood)
From: Jesper Dangaard Brouer @ 2016-05-06 9:42 UTC (permalink / raw)
To: Eric Dumazet, Felix Fietkau, Dave Taht
Cc: make-wifi-fast, zajec5, ath10k, netdev@vger.kernel.org,
codel@lists.bufferbloat.net, Jonathan Morton, Roman Yeryomin
In-Reply-To: <1462476207.13075.20.camel@edumazet-glaptop3.roam.corp.google.com>
Hi Felix,
This is an important fix for OpenWRT, please read!
OpenWRT changed the default fq_codel sch->limit from 10240 to 1024,
without also adjusting q->flows_cnt. Eric explains below that you must
also adjust the buckets (q->flows_cnt) for this not to break. (Just
adjust it to 128)
Problematic OpenWRT commit in question:
http://git.openwrt.org/?p=openwrt.git;a=patch;h=12cd6578084e
12cd6578084e ("kernel: revert fq_codel quantum override to prevent it from causing too much cpu load with higher speed (#21326)")
I also highly recommend you cherry-pick this very recent commit:
net-next: 9d18562a2278 ("fq_codel: add batch ability to fq_codel_drop()")
https://git.kernel.org/davem/net-next/c/9d18562a227
This should fix very high CPU usage in-case fq_codel goes into drop mode.
The problem is that drop mode was considered rare, and implementation
wise it was chosen to be more expensive (to save cycles on normal mode).
Unfortunately is it easy to trigger with an UDP flood. Drop mode is
especially expensive for smaller devices, as it scans a 4K big array,
thus 64 cache misses for small devices!
The fix is to allow drop-mode to bulk-drop more packets when entering
drop-mode (default 64 bulk drop). That way we don't suddenly
experience a significantly higher processing cost per packet, but
instead can amortize this.
To Eric, should we recommend OpenWRT to adjust default (max) 64 bulk
drop, given we also recommend bucket size to be 128 ? (thus the amount
of memory to scan is less, but their CPU is also much smaller).
--Jesper
On Thu, 05 May 2016 12:23:27 -0700 Eric Dumazet <eric.dumazet@gmail.com> wrote:
> On Thu, 2016-05-05 at 19:25 +0300, Roman Yeryomin wrote:
> > On 5 May 2016 at 19:12, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> > > On Thu, 2016-05-05 at 17:53 +0300, Roman Yeryomin wrote:
> > >
> > >>
> > >> qdisc fq_codel 0: dev eth0 root refcnt 2 limit 1024p flows 1024
> > >> quantum 1514 target 5.0ms interval 100.0ms ecn
> > >> Sent 12306 bytes 128 pkt (dropped 0, overlimits 0 requeues 0)
> > >> backlog 0b 0p requeues 0
> > >> maxpacket 0 drop_overlimit 0 new_flow_count 0 ecn_mark 0
> > >> new_flows_len 0 old_flows_len 0
> > >
> > >
> > > Limit of 1024 packets and 1024 flows is not wise I think.
> > >
> > > (If all buckets are in use, each bucket has a virtual queue of 1 packet,
> > > which is almost the same than having no queue at all)
> > >
> > > I suggest to have at least 8 packets per bucket, to let Codel have a
> > > chance to trigger.
> > >
> > > So you could either reduce number of buckets to 128 (if memory is
> > > tight), or increase limit to 8192.
> >
> > Will try, but what I've posted is default, I didn't change/configure that.
>
> fq_codel has a default of 10240 packets and 1024 buckets.
>
> http://lxr.free-electrons.com/source/net/sched/sch_fq_codel.c#L413
>
> If someone changed that in the linux variant you use, he probably should
> explain the rationale.
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Principal Kernel Engineer at Red Hat
Author of http://www.iptv-analyzer.org
LinkedIn: http://www.linkedin.com/in/brouer
_______________________________________________
Codel mailing list
Codel@lists.bufferbloat.net
https://lists.bufferbloat.net/listinfo/codel
^ permalink raw reply
* Re: [PATCHv2 bluetooth-next 07/10] ipv6: introduce neighbour discovery ops
From: Alexander Aring @ 2016-05-06 9:47 UTC (permalink / raw)
To: Stefan Schmidt, linux-wpan-u79uwXL29TY76Z2rM5mHXA
Cc: kernel-bIcnvbaLZ9MEGnE8C9+IrQ, marcel-kz+m5ild9QBg9hUCZPvPmw,
jukka.rissanen-VuQAYsv1563Yd54FQh9/CA,
hannes-tFNcAqjVMyqKXQKiL6tip0B+6BGkLq7r,
mcr-SWp7JaYWvAQV+D8aMU/kSg, werner-SEdMjqphH88wryQfseakQg,
linux-bluetooth-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, David S . Miller, Alexey Kuznetsov,
James Morris, Hideaki YOSHIFUJI, Patrick McHardy
In-Reply-To: <5729E9AB.5000301-JPH+aEBZ4P+UEJcrhfAQsw@public.gmane.org>
Hi,
On 05/04/2016 02:23 PM, Stefan Schmidt wrote:
> Hello.
>
> On 20/04/16 10:19, Alexander Aring wrote:
>> This patch introduces neighbour discovery ops callback structure. The
>> structure contains at first receive and transmit handling for NS/NA and
>> userspace option field functionality.
>>
>> These callback offers 6lowpan different handling, such as 802.15.4 short
>> address handling or RFC6775 (Neighbor Discovery Optimization for IPv6 over
>> 6LoWPANs).
>>
>> Cc: David S. Miller<davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
>> Cc: Alexey Kuznetsov<kuznet-v/Mj1YrvjDBInbfyfbPRSQ@public.gmane.org>
>> Cc: James Morris<jmorris-gx6/JNMH7DfYtjvyW6yDsg@public.gmane.org>
>> Cc: Hideaki YOSHIFUJI<yoshfuji-VfPWfsRibaP+Ru+s062T9g@public.gmane.org>
>> Cc: Patrick McHardy<kaber-dcUjhNyLwpNeoWH0uzbU5w@public.gmane.org>
>> Signed-off-by: Alexander Aring<aar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
>> ---
>> include/linux/netdevice.h | 3 ++
>> include/net/ndisc.h | 96 +++++++++++++++++++++++++++++++++++++++++++----
>> net/ipv6/addrconf.c | 1 +
>> net/ipv6/ndisc.c | 71 ++++++++++++++++++++++++-----------
>> net/ipv6/route.c | 2 +-
>> 5 files changed, 144 insertions(+), 29 deletions(-)
>>
>> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>> index 0052c42..bc60033 100644
>> --- a/include/linux/netdevice.h
>> +++ b/include/linux/netdevice.h
>> @@ -1677,6 +1677,9 @@ struct net_device {
>> #ifdef CONFIG_NET_L3_MASTER_DEV
>> const struct l3mdev_ops *l3mdev_ops;
>> #endif
>> +#if IS_ENABLED(CONFIG_IPV6)
>> + const struct ndisc_ops *ndisc_ops;
>> +#endif
>> const struct header_ops *header_ops;
>> diff --git a/include/net/ndisc.h b/include/net/ndisc.h
>> index aac868e..14ed016 100644
>> --- a/include/net/ndisc.h
>> +++ b/include/net/ndisc.h
>> @@ -110,7 +110,8 @@ struct ndisc_options {
>> #define NDISC_OPT_SPACE(len) (((len)+2+7)&~7)
>> -struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
>> +struct ndisc_options *ndisc_parse_options(const struct net_device *dev,
>> + u8 *opt, int opt_len,
>> struct ndisc_options *ndopts);
>> /*
>> @@ -173,6 +174,93 @@ static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, cons
>> return n;
>> }
>> +static inline int __ip6_ndisc_is_useropt(struct nd_opt_hdr *opt)
>
> Name it __ipv6... instead of __ip6...?
I had ipv6 before, but then I saw ip6... prefixes functionality in
ndisc.c and changed it to ip6...., but both seems to be used.
See "ip6_nd_hdr".
>> +{
>> + return opt->nd_opt_type == ND_OPT_RDNSS ||
>> + opt->nd_opt_type == ND_OPT_DNSSL;
>> +}
>> +
>> +#if IS_ENABLED(CONFIG_IPV6)
>> +struct ndisc_ops {
>> + int (*is_useropt)(struct nd_opt_hdr *opt);
>> + void (*send_na)(struct net_device *dev,
>> + const struct in6_addr *daddr,
>> + const struct in6_addr *solicited_addr,
>> + bool router, bool solicited,
>> + bool override, bool inc_opt);
>> + void (*recv_na)(struct sk_buff *skb);
>> + void (*send_ns)(struct net_device *dev,
>> + const struct in6_addr *solicit,
>> + const struct in6_addr *daddr,
>> + const struct in6_addr *saddr);
>> + void (*recv_ns)(struct sk_buff *skb);
>> +};
>> +
>> +static inline int ndisc_is_useropt(const struct net_device *dev,
>> + struct nd_opt_hdr *opt)
>> +{
>> + if (likely(dev->ndisc_ops->is_useropt))
>> + return dev->ndisc_ops->is_useropt(opt);
>> + else
>> + return 0;
>> +}
>> +
>> +static inline void ndisc_send_na(struct net_device *dev,
>> + const struct in6_addr *daddr,
>> + const struct in6_addr *solicited_addr,
>> + bool router, bool solicited, bool override,
>> + bool inc_opt)
>> +{
>> + if (likely(dev->ndisc_ops->send_na))
>> + dev->ndisc_ops->send_na(dev, daddr, solicited_addr, router,
>> + solicited, override, inc_opt);
>> +}
>> +
>> +static inline void ndisc_recv_na(struct sk_buff *skb)
>> +{
>> + if (likely(skb->dev->ndisc_ops->recv_na))
>> + skb->dev->ndisc_ops->recv_na(skb);
>> +}
>> +
>> +static inline void ndisc_send_ns(struct net_device *dev,
>> + const struct in6_addr *solicit,
>> + const struct in6_addr *daddr,
>> + const struct in6_addr *saddr)
>> +{
>> + if (likely(dev->ndisc_ops->send_ns))
>> + dev->ndisc_ops->send_ns(dev, solicit, daddr, saddr);
>> +}
>> +
>> +static inline void ndisc_recv_ns(struct sk_buff *skb)
>> +{
>> + if (likely(skb->dev->ndisc_ops->recv_ns))
>> + skb->dev->ndisc_ops->recv_ns(skb);
>> +}
>> +#else
>> +static inline int ndisc_is_useropt(const struct net_device *dev,
>> + struct nd_opt_hdr *opt)
>> +{
>> + return 0;
>> +}
>> +
>> +static inline void ndisc_send_na(struct net_device *dev,
>> + const struct in6_addr *daddr,
>> + const struct in6_addr *solicited_addr,
>> + bool router, bool solicited, bool override,
>> + bool inc_opt) { }
>> +
>> +static inline void ndisc_recv_na(struct sk_buff *skb) { }
>> +
>> +static inline void ndisc_send_ns(struct net_device *dev,
>> + const struct in6_addr *solicit,
>> + const struct in6_addr *daddr,
>> + const struct in6_addr *saddr) { }
>> +
>> +static inline void ndisc_recv_ns(struct sk_buff *skb) { }
>> +#endif
>> +
>> +void ip6_register_ndisc_ops(struct net_device *dev);
>> +
>> int ndisc_init(void);
>> int ndisc_late_init(void);
>> @@ -181,14 +269,8 @@ void ndisc_cleanup(void);
>> int ndisc_rcv(struct sk_buff *skb);
>> -void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
>> - const struct in6_addr *daddr, const struct in6_addr *saddr);
>> -
>> void ndisc_send_rs(struct net_device *dev,
>> const struct in6_addr *saddr, const struct in6_addr *daddr);
>> -void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr,
>> - const struct in6_addr *solicited_addr,
>> - bool router, bool solicited, bool override, bool inc_opt);
>> void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target);
>> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
>> index 54e18c2..a2ef04b 100644
>> --- a/net/ipv6/addrconf.c
>> +++ b/net/ipv6/addrconf.c
>> @@ -3266,6 +3266,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
>> idev = ipv6_add_dev(dev);
>> if (IS_ERR(idev))
>> return notifier_from_errno(PTR_ERR(idev));
>> + ip6_register_ndisc_ops(dev);
>> }
>> break;
>> diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
>> index 176c7c4..297080a 100644
>> --- a/net/ipv6/ndisc.c
>> +++ b/net/ipv6/ndisc.c
>> @@ -185,24 +185,25 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
>> return cur <= end && cur->nd_opt_type == type ? cur : NULL;
>> }
>> -static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
>> +static inline int ip6_ndisc_is_useropt(struct nd_opt_hdr *opt)
>> {
>> - return opt->nd_opt_type == ND_OPT_RDNSS ||
>> - opt->nd_opt_type == ND_OPT_DNSSL;
>> + return __ip6_ndisc_is_useropt(opt);
>
> Why putting this check into a different function? It looks like a not needed redirection.
because these IPv6 userspace options are valid in 6LoWPAN-ND and IPv6-ND.
In 6LoWPAN we do:
static inline int lowpan_ndisc_is_useropt(struct nd_opt_hdr *opt)
{
return __ip6_ndisc_is_useropt(opt) || opt->nd_opt_type == ND_OPT_6CO;
}
I don't believe that _any_ IPv6 implementation in userspace can do something
with 6CO option fields. For this reason ARPHRD_6LOWPAN should make them
valid for userspace only. (btw: the radvd maintainer wants to add some
patches for 6CO processing support).
- Alex
^ permalink raw reply
* Re: ixgbe: cannot enable LRO
From: Otto Sabart @ 2016-05-06 10:18 UTC (permalink / raw)
To: Alexander Duyck; +Cc: Netdev, Jirka Hladky, Adam Okuliar
In-Reply-To: <CAKgT0UceTxomp+Zf5ks_B0bFomdx2jyhWLwSXh4716voJ5YFAg@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1958 bytes --]
> On Wed, Apr 27, 2016 at 2:36 AM, Otto Sabart <osabart@redhat.com> wrote:
> >
> > Hello everyone,
> > does anybody have a problem with LRO on ixge (on latest 4.6-rc5)?
> > I cannot find a way to enable it.
> >
> > On stable RHEL7.2 kernel everything works fine.
> >
> > I opened a bug report [0].
> >
> > [0] https://bugzilla.kernel.org/show_bug.cgi?id=117291
> >
> >
> > Thanks!
> >
> > Ota
>
Hello Alex,
> So I am able to turn on LRO without any issues.
Yes, I badly desciribed the problem. The LRO was not possible to turn on
immediately _after the boot_ (I was enabling it in /etc/rc.local).
When I reloaded the ixgbe driver, the LRO was possible to turn on
without problem.
I found out that the problem was caused by network manager. When I
disabled NM, the LRO started to work.
>
> Do you know if you have done anything that might disable LRO such as
> modified the rx-usecs to a value less than 10 or enabled routing or
> bridging on the device? Also I think a stacked device might be able
> to block you from enabling LRO unless all the devices stacked on the
> interface can support it.
I did not modify rx-usecs (at least not intentionally). Its value is
always (with disabled or enabled LRO) equal to 1 (with disabled NM).
$ ethtool -c ixgbe | grep rx-usecs
rx-usecs: 1
rx-usecs-irq: 0
rx-usecs-low: 0
rx-usecs-high: 0
There is no linux bridge or routing enabled on this device. There is
only a VLAN configured. Does it matter?
$ ip l show ixgbe
9: ixgbe: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT qlen 1000
link/ether 00:1b:21:90:c3:86 brd ff:ff:ff:ff:ff:ff
$ ip l show ixgbe.40
19: ixgbe.40@ixgbe: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT qlen 1000
link/ether 00:1b:21:90:c3:86 brd ff:ff:ff:ff:ff:ff
I updated the bugzilla [0] and I think we can close this as a NOTABUG.
Thanks!
Ota
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 520 bytes --]
^ permalink raw reply
* Re: [PATCHv2 bluetooth-next 07/10] ipv6: introduce neighbour discovery ops
From: Alexander Aring @ 2016-05-06 10:19 UTC (permalink / raw)
To: Stefan Schmidt, linux-wpan
Cc: kernel, marcel, jukka.rissanen, hannes, mcr, werner,
linux-bluetooth, netdev, David S . Miller, Alexey Kuznetsov,
James Morris, Hideaki YOSHIFUJI, Patrick McHardy
In-Reply-To: <741404ec-e23e-30a9-c954-83b26ea71d7e@pengutronix.de>
Hi,
On 05/06/2016 11:47 AM, Alexander Aring wrote:
>
> Hi,
>
> On 05/04/2016 02:23 PM, Stefan Schmidt wrote:
>> Hello.
>>
>> On 20/04/16 10:19, Alexander Aring wrote:
>>> This patch introduces neighbour discovery ops callback structure. The
>>> structure contains at first receive and transmit handling for NS/NA and
>>> userspace option field functionality.
>>>
>>> These callback offers 6lowpan different handling, such as 802.15.4 short
>>> address handling or RFC6775 (Neighbor Discovery Optimization for IPv6 over
>>> 6LoWPANs).
>>>
>>> Cc: David S. Miller<davem@davemloft.net>
>>> Cc: Alexey Kuznetsov<kuznet@ms2.inr.ac.ru>
>>> Cc: James Morris<jmorris@namei.org>
>>> Cc: Hideaki YOSHIFUJI<yoshfuji@linux-ipv6.org>
>>> Cc: Patrick McHardy<kaber@trash.net>
>>> Signed-off-by: Alexander Aring<aar@pengutronix.de>
>>> ---
>>> include/linux/netdevice.h | 3 ++
>>> include/net/ndisc.h | 96 +++++++++++++++++++++++++++++++++++++++++++----
>>> net/ipv6/addrconf.c | 1 +
>>> net/ipv6/ndisc.c | 71 ++++++++++++++++++++++++-----------
>>> net/ipv6/route.c | 2 +-
>>> 5 files changed, 144 insertions(+), 29 deletions(-)
>>>
>>> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>>> index 0052c42..bc60033 100644
>>> --- a/include/linux/netdevice.h
>>> +++ b/include/linux/netdevice.h
>>> @@ -1677,6 +1677,9 @@ struct net_device {
>>> #ifdef CONFIG_NET_L3_MASTER_DEV
>>> const struct l3mdev_ops *l3mdev_ops;
>>> #endif
>>> +#if IS_ENABLED(CONFIG_IPV6)
>>> + const struct ndisc_ops *ndisc_ops;
>>> +#endif
>>> const struct header_ops *header_ops;
>>> diff --git a/include/net/ndisc.h b/include/net/ndisc.h
>>> index aac868e..14ed016 100644
>>> --- a/include/net/ndisc.h
>>> +++ b/include/net/ndisc.h
>>> @@ -110,7 +110,8 @@ struct ndisc_options {
>>> #define NDISC_OPT_SPACE(len) (((len)+2+7)&~7)
>>> -struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
>>> +struct ndisc_options *ndisc_parse_options(const struct net_device *dev,
>>> + u8 *opt, int opt_len,
>>> struct ndisc_options *ndopts);
>>> /*
>>> @@ -173,6 +174,93 @@ static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, cons
>>> return n;
>>> }
>>> +static inline int __ip6_ndisc_is_useropt(struct nd_opt_hdr *opt)
>>
>> Name it __ipv6... instead of __ip6...?
>
> I had ipv6 before, but then I saw ip6... prefixes functionality in
> ndisc.c and changed it to ip6...., but both seems to be used.
>
> See "ip6_nd_hdr".
>
>>> +{
>>> + return opt->nd_opt_type == ND_OPT_RDNSS ||
>>> + opt->nd_opt_type == ND_OPT_DNSSL;
>>> +}
>>> +
>>> +#if IS_ENABLED(CONFIG_IPV6)
>>> +struct ndisc_ops {
>>> + int (*is_useropt)(struct nd_opt_hdr *opt);
>>> + void (*send_na)(struct net_device *dev,
>>> + const struct in6_addr *daddr,
>>> + const struct in6_addr *solicited_addr,
>>> + bool router, bool solicited,
>>> + bool override, bool inc_opt);
>>> + void (*recv_na)(struct sk_buff *skb);
>>> + void (*send_ns)(struct net_device *dev,
>>> + const struct in6_addr *solicit,
>>> + const struct in6_addr *daddr,
>>> + const struct in6_addr *saddr);
>>> + void (*recv_ns)(struct sk_buff *skb);
>>> +};
>>> +
>>> +static inline int ndisc_is_useropt(const struct net_device *dev,
>>> + struct nd_opt_hdr *opt)
>>> +{
>>> + if (likely(dev->ndisc_ops->is_useropt))
>>> + return dev->ndisc_ops->is_useropt(opt);
>>> + else
>>> + return 0;
>>> +}
>>> +
>>> +static inline void ndisc_send_na(struct net_device *dev,
>>> + const struct in6_addr *daddr,
>>> + const struct in6_addr *solicited_addr,
>>> + bool router, bool solicited, bool override,
>>> + bool inc_opt)
>>> +{
>>> + if (likely(dev->ndisc_ops->send_na))
>>> + dev->ndisc_ops->send_na(dev, daddr, solicited_addr, router,
>>> + solicited, override, inc_opt);
>>> +}
>>> +
>>> +static inline void ndisc_recv_na(struct sk_buff *skb)
>>> +{
>>> + if (likely(skb->dev->ndisc_ops->recv_na))
>>> + skb->dev->ndisc_ops->recv_na(skb);
>>> +}
>>> +
>>> +static inline void ndisc_send_ns(struct net_device *dev,
>>> + const struct in6_addr *solicit,
>>> + const struct in6_addr *daddr,
>>> + const struct in6_addr *saddr)
>>> +{
>>> + if (likely(dev->ndisc_ops->send_ns))
>>> + dev->ndisc_ops->send_ns(dev, solicit, daddr, saddr);
>>> +}
>>> +
>>> +static inline void ndisc_recv_ns(struct sk_buff *skb)
>>> +{
>>> + if (likely(skb->dev->ndisc_ops->recv_ns))
>>> + skb->dev->ndisc_ops->recv_ns(skb);
>>> +}
>>> +#else
>>> +static inline int ndisc_is_useropt(const struct net_device *dev,
>>> + struct nd_opt_hdr *opt)
>>> +{
>>> + return 0;
>>> +}
>>> +
>>> +static inline void ndisc_send_na(struct net_device *dev,
>>> + const struct in6_addr *daddr,
>>> + const struct in6_addr *solicited_addr,
>>> + bool router, bool solicited, bool override,
>>> + bool inc_opt) { }
>>> +
>>> +static inline void ndisc_recv_na(struct sk_buff *skb) { }
>>> +
>>> +static inline void ndisc_send_ns(struct net_device *dev,
>>> + const struct in6_addr *solicit,
>>> + const struct in6_addr *daddr,
>>> + const struct in6_addr *saddr) { }
>>> +
>>> +static inline void ndisc_recv_ns(struct sk_buff *skb) { }
>>> +#endif
>>> +
>>> +void ip6_register_ndisc_ops(struct net_device *dev);
>>> +
>>> int ndisc_init(void);
>>> int ndisc_late_init(void);
>>> @@ -181,14 +269,8 @@ void ndisc_cleanup(void);
>>> int ndisc_rcv(struct sk_buff *skb);
>>> -void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
>>> - const struct in6_addr *daddr, const struct in6_addr *saddr);
>>> -
>>> void ndisc_send_rs(struct net_device *dev,
>>> const struct in6_addr *saddr, const struct in6_addr *daddr);
>>> -void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr,
>>> - const struct in6_addr *solicited_addr,
>>> - bool router, bool solicited, bool override, bool inc_opt);
>>> void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target);
>>> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
>>> index 54e18c2..a2ef04b 100644
>>> --- a/net/ipv6/addrconf.c
>>> +++ b/net/ipv6/addrconf.c
>>> @@ -3266,6 +3266,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
>>> idev = ipv6_add_dev(dev);
>>> if (IS_ERR(idev))
>>> return notifier_from_errno(PTR_ERR(idev));
>>> + ip6_register_ndisc_ops(dev);
>>> }
>>> break;
>>> diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
>>> index 176c7c4..297080a 100644
>>> --- a/net/ipv6/ndisc.c
>>> +++ b/net/ipv6/ndisc.c
>>> @@ -185,24 +185,25 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
>>> return cur <= end && cur->nd_opt_type == type ? cur : NULL;
>>> }
>>> -static inline int ndisc_is_useropt(struct nd_opt_hdr *opt)
>>> +static inline int ip6_ndisc_is_useropt(struct nd_opt_hdr *opt)
>>> {
>>> - return opt->nd_opt_type == ND_OPT_RDNSS ||
>>> - opt->nd_opt_type == ND_OPT_DNSSL;
>>> + return __ip6_ndisc_is_useropt(opt);
>>
>> Why putting this check into a different function? It looks like a not needed redirection.
>
> because these IPv6 userspace options are valid in 6LoWPAN-ND and IPv6-ND.
>
> In 6LoWPAN we do:
>
> static inline int lowpan_ndisc_is_useropt(struct nd_opt_hdr *opt)
> {
> return __ip6_ndisc_is_useropt(opt) || opt->nd_opt_type == ND_OPT_6CO;
> }
>
> I don't believe that _any_ IPv6 implementation in userspace can do something
> with 6CO option fields. For this reason ARPHRD_6LOWPAN should make them
> valid for userspace only. (btw: the radvd maintainer wants to add some
> patches for 6CO processing support).
>
Okay, I remove the different function and add an EXPORT_SYMBOL. Then the
6LoWPAN-ND is_useropt callback can also use this function instead using
the __ip6_ndisc_is_useropt inline function.
- Alex
^ permalink raw reply
* Re: [PATCH net] netfilter: nf_conntrack: Use net_mutex for helper unregistration.
From: Pablo Neira Ayuso @ 2016-05-06 11:03 UTC (permalink / raw)
To: Joe Stringer; +Cc: netdev, netfilter-devel, fw
In-Reply-To: <1462488637-46877-1-git-send-email-joe@ovn.org>
Hi Joe,
On Thu, May 05, 2016 at 03:50:37PM -0700, Joe Stringer wrote:
> diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
> index 3b40ec575cd5..6860b19be406 100644
> --- a/net/netfilter/nf_conntrack_helper.c
> +++ b/net/netfilter/nf_conntrack_helper.c
> @@ -449,10 +449,10 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
> */
> synchronize_rcu();
>
> - rtnl_lock();
> + mutex_lock(&net_mutex);
> for_each_net(net)
> __nf_conntrack_helper_unregister(me, net);
> - rtnl_unlock();
> + mutex_unlock(&net_mutex);
This simple solution works because we have no .exit callbacks in any
of our helpers. Otherwise, the helper code may be already gone by when
the worker has a chance to run to release the netns.
If so, probably I can append this as comment to this function so we
don't forget. If we ever have .exit callbacks (I don't expect so), we
would need to wait for worker completion.
^ permalink raw reply
* [PATCH v2] net: arc/emac: Move arc_emac_tx_clean() into arc_emac_tx() and disable tx interrut
From: Caesar Wang @ 2016-05-06 12:19 UTC (permalink / raw)
To: davem
Cc: heiko, linux-rockchip, Shuyu Wei, Alexander Kochetkov, netdev,
Caesar Wang, linux-kernel
From: Shuyu Wei <sy.w@outlook.com>
Doing tx_clean() inside poll() may scramble the tx ring buffer if
tx() is running. This will cause tx to stop working, which can be
reproduced by simultaneously downloading two large files at high speed.
Moving tx_clean() into tx() will prevent this. And tx interrupt is no
longer needed now.
Picked the Shuyu's patch up, the patch is sent on
https://patchwork.kernel.org/patch/8356821/, since that make sense for
rockchip platform.
Note: Many people feedback the cransh problems with rk3036/rk3188 emac when
download the heavy loading and this patch is indeed can fix the crash.
The crash log as the followings:
...
[ 2191.996127 ] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.4.0-rc6 #114
[ 2192.002475 ] Hardware name: Rockchip (Device Tree)
[ 2192.007174 ] Backtrace:
[ 2192.009658 ] [<c00134d4>] (dump_backtrace) from [<c0013680>]
(show_stack+0x18/0x1c)
[ 2192.017220 ] r7:c051c4f8 r6:ef463180 r5:c05b7000 r4:00000000
[ 2192.022948 ] [<c0013668>] (show_stack) from [<c0219d90>]
(dump_stack+0x90/0xa0)
[ 2192.030176 ] [<c0219d00>] (dump_stack) from [<c00b2cd4>]
(bad_page+0xdc/0x12c)
[ 2192.037302 ] r5:c059a100 r4:c05f430c
[ 2192.040913 ] [<c00b2bf8>] (bad_page) from [<c00b606c>]
(get_page_from_freelist+0x388/0x95c)
[ 2192.049166 ] r9:00000008 r8:ef463180 r7:c051c4d0 r6:00000000
r5:00000000 r4:c051c4e4
[ 2192.056982 ] [<c00b5ce4>] (get_page_from_freelist) from
[<c00b6880>] (__alloc_pages_nodemask+0xd8/0x8e8)
[ 2192.066362 ] r10:c001b068 r9:00000000 r8:ee0b02b0 r7:60000113
r6:00000003 r5:02095220
[ 2192.074254 ] r4:c05ca1c0
[ 2192.076809 ] [<c00b67a8>] (__alloc_pages_nodemask) from
[<c00b7140>] (__alloc_page_frag+0xb0/0x160)
[ 2192.085757 ] r10:c001b068 r9:00000000 r8:ee0b02b0 r7:60000113
r6:02080020 r5:00000740
[ 2192.093650 ] r4:eedbc884
[ 2192.096207 ] [<c00b7090>] (__alloc_page_frag) from [<c03273b4>]
(__netdev_alloc_skb+0xa0/0x104)
[ 2192.104806 ] r7:60000113 r6:eedbc884 r5:ee0b0000 r4:00000740
[ 2192.110525 ] [<c0327314>] (__netdev_alloc_skb) from [<c02aac00>]
(arc_emac_poll+0x318/0x57c)
[ 2192.118865 ] r9:00000000 r8:ee0b02b0 r7:0000019c r6:ee163780
r5:00000670 r4:ee0b0000
[ 2192.126683 ] [<c02aa8e8>] (arc_emac_poll) from [<c0339ed8>]
(net_rx_action+0x1f0/0x2ec)
[ 2192.134590 ] r10:c0599df8 r9:c059a100 r8:00073760 r7:0000012c
r6:00000028 r5:c02aa8e8
[ 2192.142483 ] r4:ee0b04e0
[ 2192.145040 ] [<c0339ce8>] (net_rx_action) from [<c0026f5c>]
(__do_softirq+0x134/0x258)
[ 2192.152860 ] r10:c059a080 r9:40000003 r8:00000003 r7:00000100
r6:c0598000 r5:c059a08c
[ 2192.160751 ] r4:00000000
...
Signed-off-by: Shuyu Wei <sy.w@outlook.com>
Tested-by: Michael Niewoehner <linux@mniewoehner.de>
Tested-by: Xing Zheng <zhengxing@rock-chips.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Alexander Kochetkov <al.kochet@gmail.com>
Cc: netdev@vger.kernel.org
Signed-off-by: Caesar Wang <wxt@rock-chips.com>
---
drivers/net/ethernet/arc/emac_main.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index a3a9392..4f4e25e 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -311,12 +311,10 @@ static int arc_emac_poll(struct napi_struct *napi, int budget)
struct arc_emac_priv *priv = netdev_priv(ndev);
unsigned int work_done;
- arc_emac_tx_clean(ndev);
-
work_done = arc_emac_rx(ndev, budget);
if (work_done < budget) {
napi_complete(napi);
- arc_reg_or(priv, R_ENABLE, RXINT_MASK | TXINT_MASK);
+ arc_reg_or(priv, R_ENABLE, RXINT_MASK);
}
return work_done;
@@ -345,9 +343,9 @@ static irqreturn_t arc_emac_intr(int irq, void *dev_instance)
/* Reset all flags except "MDIO complete" */
arc_reg_set(priv, R_STATUS, status);
- if (status & (RXINT_MASK | TXINT_MASK)) {
+ if (status & RXINT_MASK) {
if (likely(napi_schedule_prep(&priv->napi))) {
- arc_reg_clr(priv, R_ENABLE, RXINT_MASK | TXINT_MASK);
+ arc_reg_clr(priv, R_ENABLE, RXINT_MASK);
__napi_schedule(&priv->napi);
}
}
@@ -461,7 +459,7 @@ static int arc_emac_open(struct net_device *ndev)
arc_reg_set(priv, R_TX_RING, (unsigned int)priv->txbd_dma);
/* Enable interrupts */
- arc_reg_set(priv, R_ENABLE, RXINT_MASK | TXINT_MASK | ERR_MASK);
+ arc_reg_set(priv, R_ENABLE, RXINT_MASK | ERR_MASK);
/* Set CONTROL */
arc_reg_set(priv, R_CTRL,
@@ -594,7 +592,7 @@ static int arc_emac_stop(struct net_device *ndev)
netif_stop_queue(ndev);
/* Disable interrupts */
- arc_reg_clr(priv, R_ENABLE, RXINT_MASK | TXINT_MASK | ERR_MASK);
+ arc_reg_clr(priv, R_ENABLE, RXINT_MASK | ERR_MASK);
/* Disable EMAC */
arc_reg_clr(priv, R_CTRL, EN_MASK);
@@ -656,6 +654,8 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
__le32 *info = &priv->txbd[*txbd_curr].info;
dma_addr_t addr;
+ arc_emac_tx_clean(ndev);
+
if (skb_padto(skb, ETH_ZLEN))
return NETDEV_TX_OK;
--
1.9.1
^ permalink raw reply related
* Re: OpenWRT wrong adjustment of fq_codel defaults (Was: fq_codel_drop vs a udp flood)
From: Jesper Dangaard Brouer @ 2016-05-06 12:47 UTC (permalink / raw)
To: Felix Fietkau, Dave Taht
Cc: make-wifi-fast, zajec5, ath10k, codel@lists.bufferbloat.net,
netdev@vger.kernel.org, Jonathan Morton, Roman Yeryomin,
openwrt-devel
In-Reply-To: <20160506114243.4eb4f95e@redhat.com>
I've created a OpenWRT ticket[1] on this issue, as it seems that someone[2]
closed Felix'es OpenWRT email account (bad choice! emails bouncing).
Sounds like OpenWRT and the LEDE https://www.lede-project.org/ project
is in some kind of conflict.
OpenWRT ticket [1] https://dev.openwrt.org/ticket/22349
[2] http://thread.gmane.org/gmane.comp.embedded.openwrt.devel/40298/focus=40335
On Fri, 6 May 2016 11:42:43 +0200
Jesper Dangaard Brouer <brouer@redhat.com> wrote:
> Hi Felix,
>
> This is an important fix for OpenWRT, please read!
>
> OpenWRT changed the default fq_codel sch->limit from 10240 to 1024,
> without also adjusting q->flows_cnt. Eric explains below that you must
> also adjust the buckets (q->flows_cnt) for this not to break. (Just
> adjust it to 128)
>
> Problematic OpenWRT commit in question:
> http://git.openwrt.org/?p=openwrt.git;a=patch;h=12cd6578084e
> 12cd6578084e ("kernel: revert fq_codel quantum override to prevent it from causing too much cpu load with higher speed (#21326)")
>
>
> I also highly recommend you cherry-pick this very recent commit:
> net-next: 9d18562a2278 ("fq_codel: add batch ability to fq_codel_drop()")
> https://git.kernel.org/davem/net-next/c/9d18562a227
>
> This should fix very high CPU usage in-case fq_codel goes into drop mode.
> The problem is that drop mode was considered rare, and implementation
> wise it was chosen to be more expensive (to save cycles on normal mode).
> Unfortunately is it easy to trigger with an UDP flood. Drop mode is
> especially expensive for smaller devices, as it scans a 4K big array,
> thus 64 cache misses for small devices!
>
> The fix is to allow drop-mode to bulk-drop more packets when entering
> drop-mode (default 64 bulk drop). That way we don't suddenly
> experience a significantly higher processing cost per packet, but
> instead can amortize this.
>
> To Eric, should we recommend OpenWRT to adjust default (max) 64 bulk
> drop, given we also recommend bucket size to be 128 ? (thus the amount
> of memory to scan is less, but their CPU is also much smaller).
>
> --Jesper
>
>
> On Thu, 05 May 2016 12:23:27 -0700 Eric Dumazet <eric.dumazet@gmail.com> wrote:
>
> > On Thu, 2016-05-05 at 19:25 +0300, Roman Yeryomin wrote:
> > > On 5 May 2016 at 19:12, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> > > > On Thu, 2016-05-05 at 17:53 +0300, Roman Yeryomin wrote:
> > > >
> > > >>
> > > >> qdisc fq_codel 0: dev eth0 root refcnt 2 limit 1024p flows 1024
> > > >> quantum 1514 target 5.0ms interval 100.0ms ecn
> > > >> Sent 12306 bytes 128 pkt (dropped 0, overlimits 0 requeues 0)
> > > >> backlog 0b 0p requeues 0
> > > >> maxpacket 0 drop_overlimit 0 new_flow_count 0 ecn_mark 0
> > > >> new_flows_len 0 old_flows_len 0
> > > >
> > > >
> > > > Limit of 1024 packets and 1024 flows is not wise I think.
> > > >
> > > > (If all buckets are in use, each bucket has a virtual queue of 1 packet,
> > > > which is almost the same than having no queue at all)
> > > >
> > > > I suggest to have at least 8 packets per bucket, to let Codel have a
> > > > chance to trigger.
> > > >
> > > > So you could either reduce number of buckets to 128 (if memory is
> > > > tight), or increase limit to 8192.
> > >
> > > Will try, but what I've posted is default, I didn't change/configure that.
> >
> > fq_codel has a default of 10240 packets and 1024 buckets.
> >
> > http://lxr.free-electrons.com/source/net/sched/sch_fq_codel.c#L413
> >
> > If someone changed that in the linux variant you use, he probably should
> > explain the rationale.
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Principal Kernel Engineer at Red Hat
Author of http://www.iptv-analyzer.org
LinkedIn: http://www.linkedin.com/in/brouer
_______________________________________________
Codel mailing list
Codel@lists.bufferbloat.net
https://lists.bufferbloat.net/listinfo/codel
^ permalink raw reply
* [PATCH net] macvtap: segmented packet is consumed
From: Eric Dumazet @ 2016-05-06 12:58 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Vlad Yasevich
From: Eric Dumazet <edumazet@google.com>
If GSO packet is segmented and its segments are properly queued,
we call consume_skb() instead of kfree_skb() to be drop monitor
friendly.
Fixes: 3e4f8b7873709 ("macvtap: Perform GSO on forwarding path.")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Vlad Yasevich <vyasevic@redhat.com>
---
drivers/net/macvtap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 95394edd1ed5..9a35aa462314 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -373,7 +373,7 @@ static rx_handler_result_t macvtap_handle_frame(struct sk_buff **pskb)
goto wake_up;
}
- kfree_skb(skb);
+ consume_skb(skb);
while (segs) {
struct sk_buff *nskb = segs->next;
^ permalink raw reply related
* [PATCH net v3] vlan: Propagate MAC address to VLANs
From: Mike Manning @ 2016-05-06 13:26 UTC (permalink / raw)
To: netdev
In-Reply-To: <572C99FB.1060905@brocade.com>
The MAC address of the physical interface is only copied to the VLAN
when it is first created, resulting in an inconsistency after MAC
address changes of only newly created VLANs having an up-to-date MAC.
The VLANs should continue inheriting the MAC address of the physical
interface, unless explicitly changed to be different from this.
This allows IPv6 EUI64 addresses for the VLAN to reflect any changes
to the MAC of the physical interface and thus for DAD to behave as
expected.
Signed-off-by: Mike Manning <mmanning@brocade.com>
---
include/linux/if_vlan.h | 2 ++
net/8021q/vlan.c | 17 +++++++++++------
net/8021q/vlan_dev.c | 13 ++++++++++---
3 files changed, 23 insertions(+), 9 deletions(-)
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -138,6 +138,7 @@ struct netpoll;
* @flags: device flags
* @real_dev: underlying netdevice
* @real_dev_addr: address of underlying netdevice
+ * @addr_assign_type: address assignment type
* @dent: proc dir entry
* @vlan_pcpu_stats: ptr to percpu rx stats
*/
@@ -153,6 +154,7 @@ struct vlan_dev_priv {
struct net_device *real_dev;
unsigned char real_dev_addr[ETH_ALEN];
+ unsigned char addr_assign_type;
struct proc_dir_entry *dent;
struct vlan_pcpu_stats __percpu *vlan_pcpu_stats;
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -291,6 +291,15 @@ static void vlan_sync_address(struct net
if (ether_addr_equal(vlan->real_dev_addr, dev->dev_addr))
return;
+ /* vlan continues to inherit address of parent interface */
+ if (vlan->addr_assign_type == NET_ADDR_STOLEN) {
+ ether_addr_copy(vlandev->dev_addr, dev->dev_addr);
+ goto out;
+ }
+
+ if (!(vlandev->flags & IFF_UP))
+ goto out;
+
/* vlan address was different from the old address and is equal to
* the new address */
if (!ether_addr_equal(vlandev->dev_addr, vlan->real_dev_addr) &&
@@ -303,6 +312,7 @@ static void vlan_sync_address(struct net
!ether_addr_equal(vlandev->dev_addr, dev->dev_addr))
dev_uc_add(dev, vlandev->dev_addr);
+out:
ether_addr_copy(vlan->real_dev_addr, dev->dev_addr);
}
@@ -389,13 +399,8 @@ static int vlan_device_event(struct noti
case NETDEV_CHANGEADDR:
/* Adjust unicast filters on underlying device */
- vlan_group_for_each_dev(grp, i, vlandev) {
- flgs = vlandev->flags;
- if (!(flgs & IFF_UP))
- continue;
-
+ vlan_group_for_each_dev(grp, i, vlandev)
vlan_sync_address(dev, vlandev);
- }
break;
case NETDEV_CHANGEMTU:
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -315,17 +315,21 @@ static int vlan_dev_stop(struct net_devi
static int vlan_dev_set_mac_address(struct net_device *dev, void *p)
{
- struct net_device *real_dev = vlan_dev_priv(dev)->real_dev;
+ struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
+ struct net_device *real_dev = vlan->real_dev;
struct sockaddr *addr = p;
+ bool is_real_addr;
int err;
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
+ is_real_addr = ether_addr_equal(addr->sa_data, real_dev->dev_addr);
+
if (!(dev->flags & IFF_UP))
goto out;
- if (!ether_addr_equal(addr->sa_data, real_dev->dev_addr)) {
+ if (!is_real_addr) {
err = dev_uc_add(real_dev, addr->sa_data);
if (err < 0)
return err;
@@ -336,6 +340,7 @@ static int vlan_dev_set_mac_address(stru
out:
ether_addr_copy(dev->dev_addr, addr->sa_data);
+ vlan->addr_assign_type = is_real_addr ? NET_ADDR_STOLEN : NET_ADDR_SET;
return 0;
}
@@ -558,8 +563,10 @@ static int vlan_dev_init(struct net_devi
/* ipv6 shared card related stuff */
dev->dev_id = real_dev->dev_id;
- if (is_zero_ether_addr(dev->dev_addr))
+ if (is_zero_ether_addr(dev->dev_addr)) {
eth_hw_addr_inherit(dev, real_dev);
+ vlan_dev_priv(dev)->addr_assign_type = NET_ADDR_STOLEN;
+ }
if (is_zero_ether_addr(dev->broadcast))
memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len);
--
1.7.10.4
^ permalink raw reply
* [PATCH v4 1/2] soc: qcom: smd: Introduce compile stubs
From: Bjorn Andersson @ 2016-05-06 14:09 UTC (permalink / raw)
To: David S. Miller, Andy Gross
Cc: linux-kernel, netdev, linux-arm-msm, Courtney Cavin
Introduce compile stubs for the SMD API, allowing consumers to be
compile tested.
Acked-by: Andy Gross <andy.gross@linaro.org>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
Changes since v3:
- None
Changes since v2:
- Introduce this patch, to allow compile testing of QRTR_SMD
include/linux/soc/qcom/smd.h | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/include/linux/soc/qcom/smd.h b/include/linux/soc/qcom/smd.h
index d0cb6d189a0a..46a984f5e3a3 100644
--- a/include/linux/soc/qcom/smd.h
+++ b/include/linux/soc/qcom/smd.h
@@ -45,13 +45,39 @@ struct qcom_smd_driver {
int (*callback)(struct qcom_smd_device *, const void *, size_t);
};
+#if IS_ENABLED(CONFIG_QCOM_SMD)
+
int qcom_smd_driver_register(struct qcom_smd_driver *drv);
void qcom_smd_driver_unregister(struct qcom_smd_driver *drv);
+int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len);
+
+#else
+
+static inline int qcom_smd_driver_register(struct qcom_smd_driver *drv)
+{
+ return -ENXIO;
+}
+
+static inline void qcom_smd_driver_unregister(struct qcom_smd_driver *drv)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+}
+
+static inline int qcom_smd_send(struct qcom_smd_channel *channel,
+ const void *data, int len)
+{
+ /* This shouldn't be possible */
+ WARN_ON(1);
+ return -ENXIO;
+}
+
+#endif
+
#define module_qcom_smd_driver(__smd_driver) \
module_driver(__smd_driver, qcom_smd_driver_register, \
qcom_smd_driver_unregister)
-int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len);
#endif
--
2.5.0
^ permalink raw reply related
* [PATCH v4 2/2] net: Add Qualcomm IPC router
From: Bjorn Andersson @ 2016-05-06 14:09 UTC (permalink / raw)
To: David S. Miller, Andy Gross
Cc: linux-kernel, netdev, linux-arm-msm, Courtney Cavin,
Courtney Cavin, Bjorn Andersson
In-Reply-To: <1462543748-29187-1-git-send-email-bjorn.andersson@linaro.org>
From: Courtney Cavin <courtney.cavin@sonymobile.com>
Add an implementation of Qualcomm's IPC router protocol, used to
communicate with service providing remote processors.
Signed-off-by: Courtney Cavin <courtney.cavin@sonymobile.com>
Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
[bjorn: Cope with 0 being a valid node id and implement RTM_NEWADDR]
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
---
Changes since v3:
- Made it possible to compile qrtr as module
Changes since v2:
- Altered Kconfig dependency for QRTR_SMD to be compile testable
Changes since v1:
- Made node 0 (normally the Qualcomm modem) a valid node
- Implemented RTM_NEWADDR for specifying the local node id
include/linux/socket.h | 4 +-
include/uapi/linux/qrtr.h | 12 +
net/Kconfig | 1 +
net/Makefile | 1 +
net/qrtr/Kconfig | 24 ++
net/qrtr/Makefile | 2 +
net/qrtr/qrtr.c | 1007 +++++++++++++++++++++++++++++++++++++++++++++
net/qrtr/qrtr.h | 31 ++
net/qrtr/smd.c | 117 ++++++
9 files changed, 1198 insertions(+), 1 deletion(-)
create mode 100644 include/uapi/linux/qrtr.h
create mode 100644 net/qrtr/Kconfig
create mode 100644 net/qrtr/Makefile
create mode 100644 net/qrtr/qrtr.c
create mode 100644 net/qrtr/qrtr.h
create mode 100644 net/qrtr/smd.c
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 73bf6c6a833b..b5cc5a6d7011 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -201,8 +201,9 @@ struct ucred {
#define AF_NFC 39 /* NFC sockets */
#define AF_VSOCK 40 /* vSockets */
#define AF_KCM 41 /* Kernel Connection Multiplexor*/
+#define AF_QIPCRTR 42 /* Qualcomm IPC Router */
-#define AF_MAX 42 /* For now.. */
+#define AF_MAX 43 /* For now.. */
/* Protocol families, same as address families. */
#define PF_UNSPEC AF_UNSPEC
@@ -249,6 +250,7 @@ struct ucred {
#define PF_NFC AF_NFC
#define PF_VSOCK AF_VSOCK
#define PF_KCM AF_KCM
+#define PF_QIPCRTR AF_QIPCRTR
#define PF_MAX AF_MAX
/* Maximum queue length specifiable by listen. */
diff --git a/include/uapi/linux/qrtr.h b/include/uapi/linux/qrtr.h
new file mode 100644
index 000000000000..66c0748d26e2
--- /dev/null
+++ b/include/uapi/linux/qrtr.h
@@ -0,0 +1,12 @@
+#ifndef _LINUX_QRTR_H
+#define _LINUX_QRTR_H
+
+#include <linux/socket.h>
+
+struct sockaddr_qrtr {
+ __kernel_sa_family_t sq_family;
+ __u32 sq_node;
+ __u32 sq_port;
+};
+
+#endif /* _LINUX_QRTR_H */
diff --git a/net/Kconfig b/net/Kconfig
index a8934d8c8fda..b841c42e5c9b 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -236,6 +236,7 @@ source "net/mpls/Kconfig"
source "net/hsr/Kconfig"
source "net/switchdev/Kconfig"
source "net/l3mdev/Kconfig"
+source "net/qrtr/Kconfig"
config RPS
bool
diff --git a/net/Makefile b/net/Makefile
index 81d14119eab5..bdd14553a774 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -78,3 +78,4 @@ endif
ifneq ($(CONFIG_NET_L3_MASTER_DEV),)
obj-y += l3mdev/
endif
+obj-$(CONFIG_QRTR) += qrtr/
diff --git a/net/qrtr/Kconfig b/net/qrtr/Kconfig
new file mode 100644
index 000000000000..673fd1f86ebe
--- /dev/null
+++ b/net/qrtr/Kconfig
@@ -0,0 +1,24 @@
+# Qualcomm IPC Router configuration
+#
+
+config QRTR
+ tristate "Qualcomm IPC Router support"
+ depends on ARCH_QCOM || COMPILE_TEST
+ ---help---
+ Say Y if you intend to use Qualcomm IPC router protocol. The
+ protocol is used to communicate with services provided by other
+ hardware blocks in the system.
+
+ In order to do service lookups, a userspace daemon is required to
+ maintain a service listing.
+
+if QRTR
+
+config QRTR_SMD
+ tristate "SMD IPC Router channels"
+ depends on QCOM_SMD || COMPILE_TEST
+ ---help---
+ Say Y here to support SMD based ipcrouter channels. SMD is the
+ most common transport for IPC Router.
+
+endif # QRTR
diff --git a/net/qrtr/Makefile b/net/qrtr/Makefile
new file mode 100644
index 000000000000..6c00dc623b7e
--- /dev/null
+++ b/net/qrtr/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_QRTR) := qrtr.o
+obj-$(CONFIG_QRTR_SMD) += smd.o
diff --git a/net/qrtr/qrtr.c b/net/qrtr/qrtr.c
new file mode 100644
index 000000000000..c985ecbe9bd6
--- /dev/null
+++ b/net/qrtr/qrtr.c
@@ -0,0 +1,1007 @@
+/*
+ * Copyright (c) 2015, Sony Mobile Communications Inc.
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/qrtr.h>
+#include <linux/termios.h> /* For TIOCINQ/OUTQ */
+
+#include <net/sock.h>
+
+#include "qrtr.h"
+
+#define QRTR_PROTO_VER 1
+
+/* auto-bind range */
+#define QRTR_MIN_EPH_SOCKET 0x4000
+#define QRTR_MAX_EPH_SOCKET 0x7fff
+
+enum qrtr_pkt_type {
+ QRTR_TYPE_DATA = 1,
+ QRTR_TYPE_HELLO = 2,
+ QRTR_TYPE_BYE = 3,
+ QRTR_TYPE_NEW_SERVER = 4,
+ QRTR_TYPE_DEL_SERVER = 5,
+ QRTR_TYPE_DEL_CLIENT = 6,
+ QRTR_TYPE_RESUME_TX = 7,
+ QRTR_TYPE_EXIT = 8,
+ QRTR_TYPE_PING = 9,
+};
+
+/**
+ * struct qrtr_hdr - (I|R)PCrouter packet header
+ * @version: protocol version
+ * @type: packet type; one of QRTR_TYPE_*
+ * @src_node_id: source node
+ * @src_port_id: source port
+ * @confirm_rx: boolean; whether a resume-tx packet should be send in reply
+ * @size: length of packet, excluding this header
+ * @dst_node_id: destination node
+ * @dst_port_id: destination port
+ */
+struct qrtr_hdr {
+ __le32 version;
+ __le32 type;
+ __le32 src_node_id;
+ __le32 src_port_id;
+ __le32 confirm_rx;
+ __le32 size;
+ __le32 dst_node_id;
+ __le32 dst_port_id;
+} __packed;
+
+#define QRTR_HDR_SIZE sizeof(struct qrtr_hdr)
+#define QRTR_NODE_BCAST ((unsigned int)-1)
+#define QRTR_PORT_CTRL ((unsigned int)-2)
+
+struct qrtr_sock {
+ /* WARNING: sk must be the first member */
+ struct sock sk;
+ struct sockaddr_qrtr us;
+ struct sockaddr_qrtr peer;
+};
+
+static inline struct qrtr_sock *qrtr_sk(struct sock *sk)
+{
+ BUILD_BUG_ON(offsetof(struct qrtr_sock, sk) != 0);
+ return container_of(sk, struct qrtr_sock, sk);
+}
+
+static unsigned int qrtr_local_nid = -1;
+
+/* for node ids */
+static RADIX_TREE(qrtr_nodes, GFP_KERNEL);
+/* broadcast list */
+static LIST_HEAD(qrtr_all_nodes);
+/* lock for qrtr_nodes, qrtr_all_nodes and node reference */
+static DEFINE_MUTEX(qrtr_node_lock);
+
+/* local port allocation management */
+static DEFINE_IDR(qrtr_ports);
+static DEFINE_MUTEX(qrtr_port_lock);
+
+/**
+ * struct qrtr_node - endpoint node
+ * @ep_lock: lock for endpoint management and callbacks
+ * @ep: endpoint
+ * @ref: reference count for node
+ * @nid: node id
+ * @rx_queue: receive queue
+ * @work: scheduled work struct for recv work
+ * @item: list item for broadcast list
+ */
+struct qrtr_node {
+ struct mutex ep_lock;
+ struct qrtr_endpoint *ep;
+ struct kref ref;
+ unsigned int nid;
+
+ struct sk_buff_head rx_queue;
+ struct work_struct work;
+ struct list_head item;
+};
+
+/* Release node resources and free the node.
+ *
+ * Do not call directly, use qrtr_node_release. To be used with
+ * kref_put_mutex. As such, the node mutex is expected to be locked on call.
+ */
+static void __qrtr_node_release(struct kref *kref)
+{
+ struct qrtr_node *node = container_of(kref, struct qrtr_node, ref);
+
+ if (node->nid != QRTR_EP_NID_AUTO)
+ radix_tree_delete(&qrtr_nodes, node->nid);
+
+ list_del(&node->item);
+ mutex_unlock(&qrtr_node_lock);
+
+ skb_queue_purge(&node->rx_queue);
+ kfree(node);
+}
+
+/* Increment reference to node. */
+static struct qrtr_node *qrtr_node_acquire(struct qrtr_node *node)
+{
+ if (node)
+ kref_get(&node->ref);
+ return node;
+}
+
+/* Decrement reference to node and release as necessary. */
+static void qrtr_node_release(struct qrtr_node *node)
+{
+ if (!node)
+ return;
+ kref_put_mutex(&node->ref, __qrtr_node_release, &qrtr_node_lock);
+}
+
+/* Pass an outgoing packet socket buffer to the endpoint driver. */
+static int qrtr_node_enqueue(struct qrtr_node *node, struct sk_buff *skb)
+{
+ int rc = -ENODEV;
+
+ mutex_lock(&node->ep_lock);
+ if (node->ep)
+ rc = node->ep->xmit(node->ep, skb);
+ else
+ kfree_skb(skb);
+ mutex_unlock(&node->ep_lock);
+
+ return rc;
+}
+
+/* Lookup node by id.
+ *
+ * callers must release with qrtr_node_release()
+ */
+static struct qrtr_node *qrtr_node_lookup(unsigned int nid)
+{
+ struct qrtr_node *node;
+
+ mutex_lock(&qrtr_node_lock);
+ node = radix_tree_lookup(&qrtr_nodes, nid);
+ node = qrtr_node_acquire(node);
+ mutex_unlock(&qrtr_node_lock);
+
+ return node;
+}
+
+/* Assign node id to node.
+ *
+ * This is mostly useful for automatic node id assignment, based on
+ * the source id in the incoming packet.
+ */
+static void qrtr_node_assign(struct qrtr_node *node, unsigned int nid)
+{
+ if (node->nid != QRTR_EP_NID_AUTO || nid == QRTR_EP_NID_AUTO)
+ return;
+
+ mutex_lock(&qrtr_node_lock);
+ radix_tree_insert(&qrtr_nodes, nid, node);
+ node->nid = nid;
+ mutex_unlock(&qrtr_node_lock);
+}
+
+/**
+ * qrtr_endpoint_post() - post incoming data
+ * @ep: endpoint handle
+ * @data: data pointer
+ * @len: size of data in bytes
+ *
+ * Return: 0 on success; negative error code on failure
+ */
+int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len)
+{
+ struct qrtr_node *node = ep->node;
+ const struct qrtr_hdr *phdr = data;
+ struct sk_buff *skb;
+ unsigned int psize;
+ unsigned int size;
+ unsigned int type;
+ unsigned int ver;
+ unsigned int dst;
+
+ if (len < QRTR_HDR_SIZE || len & 3)
+ return -EINVAL;
+
+ ver = le32_to_cpu(phdr->version);
+ size = le32_to_cpu(phdr->size);
+ type = le32_to_cpu(phdr->type);
+ dst = le32_to_cpu(phdr->dst_port_id);
+
+ psize = (size + 3) & ~3;
+
+ if (ver != QRTR_PROTO_VER)
+ return -EINVAL;
+
+ if (len != psize + QRTR_HDR_SIZE)
+ return -EINVAL;
+
+ if (dst != QRTR_PORT_CTRL && type != QRTR_TYPE_DATA)
+ return -EINVAL;
+
+ skb = netdev_alloc_skb(NULL, len);
+ if (!skb)
+ return -ENOMEM;
+
+ skb_reset_transport_header(skb);
+ memcpy(skb_put(skb, len), data, len);
+
+ skb_queue_tail(&node->rx_queue, skb);
+ schedule_work(&node->work);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qrtr_endpoint_post);
+
+/* Allocate and construct a resume-tx packet. */
+static struct sk_buff *qrtr_alloc_resume_tx(u32 src_node,
+ u32 dst_node, u32 port)
+{
+ const int pkt_len = 20;
+ struct qrtr_hdr *hdr;
+ struct sk_buff *skb;
+ u32 *buf;
+
+ skb = alloc_skb(QRTR_HDR_SIZE + pkt_len, GFP_KERNEL);
+ if (!skb)
+ return NULL;
+ skb_reset_transport_header(skb);
+
+ hdr = (struct qrtr_hdr *)skb_put(skb, QRTR_HDR_SIZE);
+ hdr->version = cpu_to_le32(QRTR_PROTO_VER);
+ hdr->type = cpu_to_le32(QRTR_TYPE_RESUME_TX);
+ hdr->src_node_id = cpu_to_le32(src_node);
+ hdr->src_port_id = cpu_to_le32(QRTR_PORT_CTRL);
+ hdr->confirm_rx = cpu_to_le32(0);
+ hdr->size = cpu_to_le32(pkt_len);
+ hdr->dst_node_id = cpu_to_le32(dst_node);
+ hdr->dst_port_id = cpu_to_le32(QRTR_PORT_CTRL);
+
+ buf = (u32 *)skb_put(skb, pkt_len);
+ memset(buf, 0, pkt_len);
+ buf[0] = cpu_to_le32(QRTR_TYPE_RESUME_TX);
+ buf[1] = cpu_to_le32(src_node);
+ buf[2] = cpu_to_le32(port);
+
+ return skb;
+}
+
+static struct qrtr_sock *qrtr_port_lookup(int port);
+static void qrtr_port_put(struct qrtr_sock *ipc);
+
+/* Handle and route a received packet.
+ *
+ * This will auto-reply with resume-tx packet as necessary.
+ */
+static void qrtr_node_rx_work(struct work_struct *work)
+{
+ struct qrtr_node *node = container_of(work, struct qrtr_node, work);
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&node->rx_queue)) != NULL) {
+ const struct qrtr_hdr *phdr;
+ u32 dst_node, dst_port;
+ struct qrtr_sock *ipc;
+ u32 src_node;
+ int confirm;
+
+ phdr = (const struct qrtr_hdr *)skb_transport_header(skb);
+ src_node = le32_to_cpu(phdr->src_node_id);
+ dst_node = le32_to_cpu(phdr->dst_node_id);
+ dst_port = le32_to_cpu(phdr->dst_port_id);
+ confirm = !!phdr->confirm_rx;
+
+ qrtr_node_assign(node, src_node);
+
+ ipc = qrtr_port_lookup(dst_port);
+ if (!ipc) {
+ kfree_skb(skb);
+ } else {
+ if (sock_queue_rcv_skb(&ipc->sk, skb))
+ kfree_skb(skb);
+
+ qrtr_port_put(ipc);
+ }
+
+ if (confirm) {
+ skb = qrtr_alloc_resume_tx(dst_node, node->nid, dst_port);
+ if (!skb)
+ break;
+ if (qrtr_node_enqueue(node, skb))
+ break;
+ }
+ }
+}
+
+/**
+ * qrtr_endpoint_register() - register a new endpoint
+ * @ep: endpoint to register
+ * @nid: desired node id; may be QRTR_EP_NID_AUTO for auto-assignment
+ * Return: 0 on success; negative error code on failure
+ *
+ * The specified endpoint must have the xmit function pointer set on call.
+ */
+int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid)
+{
+ struct qrtr_node *node;
+
+ if (!ep || !ep->xmit)
+ return -EINVAL;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+ return -ENOMEM;
+
+ INIT_WORK(&node->work, qrtr_node_rx_work);
+ kref_init(&node->ref);
+ mutex_init(&node->ep_lock);
+ skb_queue_head_init(&node->rx_queue);
+ node->nid = QRTR_EP_NID_AUTO;
+ node->ep = ep;
+
+ qrtr_node_assign(node, nid);
+
+ mutex_lock(&qrtr_node_lock);
+ list_add(&node->item, &qrtr_all_nodes);
+ mutex_unlock(&qrtr_node_lock);
+ ep->node = node;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qrtr_endpoint_register);
+
+/**
+ * qrtr_endpoint_unregister - unregister endpoint
+ * @ep: endpoint to unregister
+ */
+void qrtr_endpoint_unregister(struct qrtr_endpoint *ep)
+{
+ struct qrtr_node *node = ep->node;
+
+ mutex_lock(&node->ep_lock);
+ node->ep = NULL;
+ mutex_unlock(&node->ep_lock);
+
+ qrtr_node_release(node);
+ ep->node = NULL;
+}
+EXPORT_SYMBOL_GPL(qrtr_endpoint_unregister);
+
+/* Lookup socket by port.
+ *
+ * Callers must release with qrtr_port_put()
+ */
+static struct qrtr_sock *qrtr_port_lookup(int port)
+{
+ struct qrtr_sock *ipc;
+
+ if (port == QRTR_PORT_CTRL)
+ port = 0;
+
+ mutex_lock(&qrtr_port_lock);
+ ipc = idr_find(&qrtr_ports, port);
+ if (ipc)
+ sock_hold(&ipc->sk);
+ mutex_unlock(&qrtr_port_lock);
+
+ return ipc;
+}
+
+/* Release acquired socket. */
+static void qrtr_port_put(struct qrtr_sock *ipc)
+{
+ sock_put(&ipc->sk);
+}
+
+/* Remove port assignment. */
+static void qrtr_port_remove(struct qrtr_sock *ipc)
+{
+ int port = ipc->us.sq_port;
+
+ if (port == QRTR_PORT_CTRL)
+ port = 0;
+
+ __sock_put(&ipc->sk);
+
+ mutex_lock(&qrtr_port_lock);
+ idr_remove(&qrtr_ports, port);
+ mutex_unlock(&qrtr_port_lock);
+}
+
+/* Assign port number to socket.
+ *
+ * Specify port in the integer pointed to by port, and it will be adjusted
+ * on return as necesssary.
+ *
+ * Port may be:
+ * 0: Assign ephemeral port in [QRTR_MIN_EPH_SOCKET, QRTR_MAX_EPH_SOCKET]
+ * <QRTR_MIN_EPH_SOCKET: Specified; requires CAP_NET_ADMIN
+ * >QRTR_MIN_EPH_SOCKET: Specified; available to all
+ */
+static int qrtr_port_assign(struct qrtr_sock *ipc, int *port)
+{
+ int rc;
+
+ mutex_lock(&qrtr_port_lock);
+ if (!*port) {
+ rc = idr_alloc(&qrtr_ports, ipc,
+ QRTR_MIN_EPH_SOCKET, QRTR_MAX_EPH_SOCKET + 1,
+ GFP_ATOMIC);
+ if (rc >= 0)
+ *port = rc;
+ } else if (*port < QRTR_MIN_EPH_SOCKET && !capable(CAP_NET_ADMIN)) {
+ rc = -EACCES;
+ } else if (*port == QRTR_PORT_CTRL) {
+ rc = idr_alloc(&qrtr_ports, ipc, 0, 1, GFP_ATOMIC);
+ } else {
+ rc = idr_alloc(&qrtr_ports, ipc, *port, *port + 1, GFP_ATOMIC);
+ if (rc >= 0)
+ *port = rc;
+ }
+ mutex_unlock(&qrtr_port_lock);
+
+ if (rc == -ENOSPC)
+ return -EADDRINUSE;
+ else if (rc < 0)
+ return rc;
+
+ sock_hold(&ipc->sk);
+
+ return 0;
+}
+
+/* Bind socket to address.
+ *
+ * Socket should be locked upon call.
+ */
+static int __qrtr_bind(struct socket *sock,
+ const struct sockaddr_qrtr *addr, int zapped)
+{
+ struct qrtr_sock *ipc = qrtr_sk(sock->sk);
+ struct sock *sk = sock->sk;
+ int port;
+ int rc;
+
+ /* rebinding ok */
+ if (!zapped && addr->sq_port == ipc->us.sq_port)
+ return 0;
+
+ port = addr->sq_port;
+ rc = qrtr_port_assign(ipc, &port);
+ if (rc)
+ return rc;
+
+ /* unbind previous, if any */
+ if (!zapped)
+ qrtr_port_remove(ipc);
+ ipc->us.sq_port = port;
+
+ sock_reset_flag(sk, SOCK_ZAPPED);
+
+ return 0;
+}
+
+/* Auto bind to an ephemeral port. */
+static int qrtr_autobind(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+ struct sockaddr_qrtr addr;
+
+ if (!sock_flag(sk, SOCK_ZAPPED))
+ return 0;
+
+ addr.sq_family = AF_QIPCRTR;
+ addr.sq_node = qrtr_local_nid;
+ addr.sq_port = 0;
+
+ return __qrtr_bind(sock, &addr, 1);
+}
+
+/* Bind socket to specified sockaddr. */
+static int qrtr_bind(struct socket *sock, struct sockaddr *saddr, int len)
+{
+ DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, saddr);
+ struct qrtr_sock *ipc = qrtr_sk(sock->sk);
+ struct sock *sk = sock->sk;
+ int rc;
+
+ if (len < sizeof(*addr) || addr->sq_family != AF_QIPCRTR)
+ return -EINVAL;
+
+ if (addr->sq_node != ipc->us.sq_node)
+ return -EINVAL;
+
+ lock_sock(sk);
+ rc = __qrtr_bind(sock, addr, sock_flag(sk, SOCK_ZAPPED));
+ release_sock(sk);
+
+ return rc;
+}
+
+/* Queue packet to local peer socket. */
+static int qrtr_local_enqueue(struct qrtr_node *node, struct sk_buff *skb)
+{
+ const struct qrtr_hdr *phdr;
+ struct qrtr_sock *ipc;
+
+ phdr = (const struct qrtr_hdr *)skb_transport_header(skb);
+
+ ipc = qrtr_port_lookup(le32_to_cpu(phdr->dst_port_id));
+ if (!ipc || &ipc->sk == skb->sk) { /* do not send to self */
+ kfree_skb(skb);
+ return -ENODEV;
+ }
+
+ if (sock_queue_rcv_skb(&ipc->sk, skb)) {
+ qrtr_port_put(ipc);
+ kfree_skb(skb);
+ return -ENOSPC;
+ }
+
+ qrtr_port_put(ipc);
+
+ return 0;
+}
+
+/* Queue packet for broadcast. */
+static int qrtr_bcast_enqueue(struct qrtr_node *node, struct sk_buff *skb)
+{
+ struct sk_buff *skbn;
+
+ mutex_lock(&qrtr_node_lock);
+ list_for_each_entry(node, &qrtr_all_nodes, item) {
+ skbn = skb_clone(skb, GFP_KERNEL);
+ if (!skbn)
+ break;
+ skb_set_owner_w(skbn, skb->sk);
+ qrtr_node_enqueue(node, skbn);
+ }
+ mutex_unlock(&qrtr_node_lock);
+
+ qrtr_local_enqueue(node, skb);
+
+ return 0;
+}
+
+static int qrtr_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
+{
+ DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, msg->msg_name);
+ int (*enqueue_fn)(struct qrtr_node *, struct sk_buff *);
+ struct qrtr_sock *ipc = qrtr_sk(sock->sk);
+ struct sock *sk = sock->sk;
+ struct qrtr_node *node;
+ struct qrtr_hdr *hdr;
+ struct sk_buff *skb;
+ size_t plen;
+ int rc;
+
+ if (msg->msg_flags & ~(MSG_DONTWAIT))
+ return -EINVAL;
+
+ if (len > 65535)
+ return -EMSGSIZE;
+
+ lock_sock(sk);
+
+ if (addr) {
+ if (msg->msg_namelen < sizeof(*addr)) {
+ release_sock(sk);
+ return -EINVAL;
+ }
+
+ if (addr->sq_family != AF_QIPCRTR) {
+ release_sock(sk);
+ return -EINVAL;
+ }
+
+ rc = qrtr_autobind(sock);
+ if (rc) {
+ release_sock(sk);
+ return rc;
+ }
+ } else if (sk->sk_state == TCP_ESTABLISHED) {
+ addr = &ipc->peer;
+ } else {
+ release_sock(sk);
+ return -ENOTCONN;
+ }
+
+ node = NULL;
+ if (addr->sq_node == QRTR_NODE_BCAST) {
+ enqueue_fn = qrtr_bcast_enqueue;
+ } else if (addr->sq_node == ipc->us.sq_node) {
+ enqueue_fn = qrtr_local_enqueue;
+ } else {
+ enqueue_fn = qrtr_node_enqueue;
+ node = qrtr_node_lookup(addr->sq_node);
+ if (!node) {
+ release_sock(sk);
+ return -ECONNRESET;
+ }
+ }
+
+ plen = (len + 3) & ~3;
+ skb = sock_alloc_send_skb(sk, plen + QRTR_HDR_SIZE,
+ msg->msg_flags & MSG_DONTWAIT, &rc);
+ if (!skb)
+ goto out_node;
+
+ skb_reset_transport_header(skb);
+ skb_put(skb, len + QRTR_HDR_SIZE);
+
+ hdr = (struct qrtr_hdr *)skb_transport_header(skb);
+ hdr->version = cpu_to_le32(QRTR_PROTO_VER);
+ hdr->src_node_id = cpu_to_le32(ipc->us.sq_node);
+ hdr->src_port_id = cpu_to_le32(ipc->us.sq_port);
+ hdr->confirm_rx = cpu_to_le32(0);
+ hdr->size = cpu_to_le32(len);
+ hdr->dst_node_id = cpu_to_le32(addr->sq_node);
+ hdr->dst_port_id = cpu_to_le32(addr->sq_port);
+
+ rc = skb_copy_datagram_from_iter(skb, QRTR_HDR_SIZE,
+ &msg->msg_iter, len);
+ if (rc) {
+ kfree_skb(skb);
+ goto out_node;
+ }
+
+ if (plen != len) {
+ skb_pad(skb, plen - len);
+ skb_put(skb, plen - len);
+ }
+
+ if (ipc->us.sq_port == QRTR_PORT_CTRL) {
+ if (len < 4) {
+ rc = -EINVAL;
+ kfree_skb(skb);
+ goto out_node;
+ }
+
+ /* control messages already require the type as 'command' */
+ skb_copy_bits(skb, QRTR_HDR_SIZE, &hdr->type, 4);
+ } else {
+ hdr->type = cpu_to_le32(QRTR_TYPE_DATA);
+ }
+
+ rc = enqueue_fn(node, skb);
+ if (rc >= 0)
+ rc = len;
+
+out_node:
+ qrtr_node_release(node);
+ release_sock(sk);
+
+ return rc;
+}
+
+static int qrtr_recvmsg(struct socket *sock, struct msghdr *msg,
+ size_t size, int flags)
+{
+ DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, msg->msg_name);
+ const struct qrtr_hdr *phdr;
+ struct sock *sk = sock->sk;
+ struct sk_buff *skb;
+ int copied, rc;
+
+ lock_sock(sk);
+
+ if (sock_flag(sk, SOCK_ZAPPED)) {
+ release_sock(sk);
+ return -EADDRNOTAVAIL;
+ }
+
+ skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
+ flags & MSG_DONTWAIT, &rc);
+ if (!skb) {
+ release_sock(sk);
+ return rc;
+ }
+
+ phdr = (const struct qrtr_hdr *)skb_transport_header(skb);
+ copied = le32_to_cpu(phdr->size);
+ if (copied > size) {
+ copied = size;
+ msg->msg_flags |= MSG_TRUNC;
+ }
+
+ rc = skb_copy_datagram_msg(skb, QRTR_HDR_SIZE, msg, copied);
+ if (rc < 0)
+ goto out;
+ rc = copied;
+
+ if (addr) {
+ addr->sq_family = AF_QIPCRTR;
+ addr->sq_node = le32_to_cpu(phdr->src_node_id);
+ addr->sq_port = le32_to_cpu(phdr->src_port_id);
+ msg->msg_namelen = sizeof(*addr);
+ }
+
+out:
+ skb_free_datagram(sk, skb);
+ release_sock(sk);
+
+ return rc;
+}
+
+static int qrtr_connect(struct socket *sock, struct sockaddr *saddr,
+ int len, int flags)
+{
+ DECLARE_SOCKADDR(struct sockaddr_qrtr *, addr, saddr);
+ struct qrtr_sock *ipc = qrtr_sk(sock->sk);
+ struct sock *sk = sock->sk;
+ int rc;
+
+ if (len < sizeof(*addr) || addr->sq_family != AF_QIPCRTR)
+ return -EINVAL;
+
+ lock_sock(sk);
+
+ sk->sk_state = TCP_CLOSE;
+ sock->state = SS_UNCONNECTED;
+
+ rc = qrtr_autobind(sock);
+ if (rc) {
+ release_sock(sk);
+ return rc;
+ }
+
+ ipc->peer = *addr;
+ sock->state = SS_CONNECTED;
+ sk->sk_state = TCP_ESTABLISHED;
+
+ release_sock(sk);
+
+ return 0;
+}
+
+static int qrtr_getname(struct socket *sock, struct sockaddr *saddr,
+ int *len, int peer)
+{
+ struct qrtr_sock *ipc = qrtr_sk(sock->sk);
+ struct sockaddr_qrtr qaddr;
+ struct sock *sk = sock->sk;
+
+ lock_sock(sk);
+ if (peer) {
+ if (sk->sk_state != TCP_ESTABLISHED) {
+ release_sock(sk);
+ return -ENOTCONN;
+ }
+
+ qaddr = ipc->peer;
+ } else {
+ qaddr = ipc->us;
+ }
+ release_sock(sk);
+
+ *len = sizeof(qaddr);
+ qaddr.sq_family = AF_QIPCRTR;
+
+ memcpy(saddr, &qaddr, sizeof(qaddr));
+
+ return 0;
+}
+
+static int qrtr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ struct qrtr_sock *ipc = qrtr_sk(sock->sk);
+ struct sock *sk = sock->sk;
+ struct sockaddr_qrtr *sq;
+ struct sk_buff *skb;
+ struct ifreq ifr;
+ long len = 0;
+ int rc = 0;
+
+ lock_sock(sk);
+
+ switch (cmd) {
+ case TIOCOUTQ:
+ len = sk->sk_sndbuf - sk_wmem_alloc_get(sk);
+ if (len < 0)
+ len = 0;
+ rc = put_user(len, (int __user *)argp);
+ break;
+ case TIOCINQ:
+ skb = skb_peek(&sk->sk_receive_queue);
+ if (skb)
+ len = skb->len - QRTR_HDR_SIZE;
+ rc = put_user(len, (int __user *)argp);
+ break;
+ case SIOCGIFADDR:
+ if (copy_from_user(&ifr, argp, sizeof(ifr))) {
+ rc = -EFAULT;
+ break;
+ }
+
+ sq = (struct sockaddr_qrtr *)&ifr.ifr_addr;
+ *sq = ipc->us;
+ if (copy_to_user(argp, &ifr, sizeof(ifr))) {
+ rc = -EFAULT;
+ break;
+ }
+ break;
+ case SIOCGSTAMP:
+ rc = sock_get_timestamp(sk, argp);
+ break;
+ case SIOCADDRT:
+ case SIOCDELRT:
+ case SIOCSIFADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCSIFDSTADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCSIFBRDADDR:
+ case SIOCGIFNETMASK:
+ case SIOCSIFNETMASK:
+ rc = -EINVAL;
+ break;
+ default:
+ rc = -ENOIOCTLCMD;
+ break;
+ }
+
+ release_sock(sk);
+
+ return rc;
+}
+
+static int qrtr_release(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+ struct qrtr_sock *ipc;
+
+ if (!sk)
+ return 0;
+
+ lock_sock(sk);
+
+ ipc = qrtr_sk(sk);
+ sk->sk_shutdown = SHUTDOWN_MASK;
+ if (!sock_flag(sk, SOCK_DEAD))
+ sk->sk_state_change(sk);
+
+ sock_set_flag(sk, SOCK_DEAD);
+ sock->sk = NULL;
+
+ if (!sock_flag(sk, SOCK_ZAPPED))
+ qrtr_port_remove(ipc);
+
+ skb_queue_purge(&sk->sk_receive_queue);
+
+ release_sock(sk);
+ sock_put(sk);
+
+ return 0;
+}
+
+static const struct proto_ops qrtr_proto_ops = {
+ .owner = THIS_MODULE,
+ .family = AF_QIPCRTR,
+ .bind = qrtr_bind,
+ .connect = qrtr_connect,
+ .socketpair = sock_no_socketpair,
+ .accept = sock_no_accept,
+ .listen = sock_no_listen,
+ .sendmsg = qrtr_sendmsg,
+ .recvmsg = qrtr_recvmsg,
+ .getname = qrtr_getname,
+ .ioctl = qrtr_ioctl,
+ .poll = datagram_poll,
+ .shutdown = sock_no_shutdown,
+ .setsockopt = sock_no_setsockopt,
+ .getsockopt = sock_no_getsockopt,
+ .release = qrtr_release,
+ .mmap = sock_no_mmap,
+ .sendpage = sock_no_sendpage,
+};
+
+static struct proto qrtr_proto = {
+ .name = "QIPCRTR",
+ .owner = THIS_MODULE,
+ .obj_size = sizeof(struct qrtr_sock),
+};
+
+static int qrtr_create(struct net *net, struct socket *sock,
+ int protocol, int kern)
+{
+ struct qrtr_sock *ipc;
+ struct sock *sk;
+
+ if (sock->type != SOCK_DGRAM)
+ return -EPROTOTYPE;
+
+ sk = sk_alloc(net, AF_QIPCRTR, GFP_KERNEL, &qrtr_proto, kern);
+ if (!sk)
+ return -ENOMEM;
+
+ sock_set_flag(sk, SOCK_ZAPPED);
+
+ sock_init_data(sock, sk);
+ sock->ops = &qrtr_proto_ops;
+
+ ipc = qrtr_sk(sk);
+ ipc->us.sq_family = AF_QIPCRTR;
+ ipc->us.sq_node = qrtr_local_nid;
+ ipc->us.sq_port = 0;
+
+ return 0;
+}
+
+static const struct nla_policy qrtr_policy[IFA_MAX + 1] = {
+ [IFA_LOCAL] = { .type = NLA_U32 },
+};
+
+static int qrtr_addr_doit(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+ struct nlattr *tb[IFA_MAX + 1];
+ struct ifaddrmsg *ifm;
+ int rc;
+
+ if (!netlink_capable(skb, CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (!netlink_capable(skb, CAP_SYS_ADMIN))
+ return -EPERM;
+
+ ASSERT_RTNL();
+
+ rc = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, qrtr_policy);
+ if (rc < 0)
+ return rc;
+
+ ifm = nlmsg_data(nlh);
+ if (!tb[IFA_LOCAL])
+ return -EINVAL;
+
+ qrtr_local_nid = nla_get_u32(tb[IFA_LOCAL]);
+ return 0;
+}
+
+static const struct net_proto_family qrtr_family = {
+ .owner = THIS_MODULE,
+ .family = AF_QIPCRTR,
+ .create = qrtr_create,
+};
+
+static int __init qrtr_proto_init(void)
+{
+ int rc;
+
+ rc = proto_register(&qrtr_proto, 1);
+ if (rc)
+ return rc;
+
+ rc = sock_register(&qrtr_family);
+ if (rc) {
+ proto_unregister(&qrtr_proto);
+ return rc;
+ }
+
+ rtnl_register(PF_QIPCRTR, RTM_NEWADDR, qrtr_addr_doit, NULL, NULL);
+
+ return 0;
+}
+module_init(qrtr_proto_init);
+
+static void __exit qrtr_proto_fini(void)
+{
+ rtnl_unregister(PF_QIPCRTR, RTM_NEWADDR);
+ sock_unregister(qrtr_family.family);
+ proto_unregister(&qrtr_proto);
+}
+module_exit(qrtr_proto_fini);
+
+MODULE_DESCRIPTION("Qualcomm IPC-router driver");
+MODULE_LICENSE("GPL v2");
diff --git a/net/qrtr/qrtr.h b/net/qrtr/qrtr.h
new file mode 100644
index 000000000000..2b848718f8fe
--- /dev/null
+++ b/net/qrtr/qrtr.h
@@ -0,0 +1,31 @@
+#ifndef __QRTR_H_
+#define __QRTR_H_
+
+#include <linux/types.h>
+
+struct sk_buff;
+
+/* endpoint node id auto assignment */
+#define QRTR_EP_NID_AUTO (-1)
+
+/**
+ * struct qrtr_endpoint - endpoint handle
+ * @xmit: Callback for outgoing packets
+ *
+ * The socket buffer passed to the xmit function becomes owned by the endpoint
+ * driver. As such, when the driver is done with the buffer, it should
+ * call kfree_skb() on failure, or consume_skb() on success.
+ */
+struct qrtr_endpoint {
+ int (*xmit)(struct qrtr_endpoint *ep, struct sk_buff *skb);
+ /* private: not for endpoint use */
+ struct qrtr_node *node;
+};
+
+int qrtr_endpoint_register(struct qrtr_endpoint *ep, unsigned int nid);
+
+void qrtr_endpoint_unregister(struct qrtr_endpoint *ep);
+
+int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len);
+
+#endif
diff --git a/net/qrtr/smd.c b/net/qrtr/smd.c
new file mode 100644
index 000000000000..84ebce73aa23
--- /dev/null
+++ b/net/qrtr/smd.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2015, Sony Mobile Communications Inc.
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/soc/qcom/smd.h>
+
+#include "qrtr.h"
+
+struct qrtr_smd_dev {
+ struct qrtr_endpoint ep;
+ struct qcom_smd_channel *channel;
+};
+
+/* from smd to qrtr */
+static int qcom_smd_qrtr_callback(struct qcom_smd_device *sdev,
+ const void *data, size_t len)
+{
+ struct qrtr_smd_dev *qdev = dev_get_drvdata(&sdev->dev);
+ int rc;
+
+ if (!qdev)
+ return -EAGAIN;
+
+ rc = qrtr_endpoint_post(&qdev->ep, data, len);
+ if (rc == -EINVAL) {
+ dev_err(&sdev->dev, "invalid ipcrouter packet\n");
+ /* return 0 to let smd drop the packet */
+ rc = 0;
+ }
+
+ return rc;
+}
+
+/* from qrtr to smd */
+static int qcom_smd_qrtr_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
+{
+ struct qrtr_smd_dev *qdev = container_of(ep, struct qrtr_smd_dev, ep);
+ int rc;
+
+ rc = skb_linearize(skb);
+ if (rc)
+ goto out;
+
+ rc = qcom_smd_send(qdev->channel, skb->data, skb->len);
+
+out:
+ if (rc)
+ kfree_skb(skb);
+ else
+ consume_skb(skb);
+ return rc;
+}
+
+static int qcom_smd_qrtr_probe(struct qcom_smd_device *sdev)
+{
+ struct qrtr_smd_dev *qdev;
+ int rc;
+
+ qdev = devm_kzalloc(&sdev->dev, sizeof(*qdev), GFP_KERNEL);
+ if (!qdev)
+ return -ENOMEM;
+
+ qdev->channel = sdev->channel;
+ qdev->ep.xmit = qcom_smd_qrtr_send;
+
+ rc = qrtr_endpoint_register(&qdev->ep, QRTR_EP_NID_AUTO);
+ if (rc)
+ return rc;
+
+ dev_set_drvdata(&sdev->dev, qdev);
+
+ dev_dbg(&sdev->dev, "Qualcomm SMD QRTR driver probed\n");
+
+ return 0;
+}
+
+static void qcom_smd_qrtr_remove(struct qcom_smd_device *sdev)
+{
+ struct qrtr_smd_dev *qdev = dev_get_drvdata(&sdev->dev);
+
+ qrtr_endpoint_unregister(&qdev->ep);
+
+ dev_set_drvdata(&sdev->dev, NULL);
+}
+
+static const struct qcom_smd_id qcom_smd_qrtr_smd_match[] = {
+ { "IPCRTR" },
+ {}
+};
+
+static struct qcom_smd_driver qcom_smd_qrtr_driver = {
+ .probe = qcom_smd_qrtr_probe,
+ .remove = qcom_smd_qrtr_remove,
+ .callback = qcom_smd_qrtr_callback,
+ .smd_match_table = qcom_smd_qrtr_smd_match,
+ .driver = {
+ .name = "qcom_smd_qrtr",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_qcom_smd_driver(qcom_smd_qrtr_driver);
+
+MODULE_DESCRIPTION("Qualcomm IPC-Router SMD interface driver");
+MODULE_LICENSE("GPL v2");
--
2.5.0
^ permalink raw reply related
* [PATCH iproute2] geneve: fix IPv6 remote address reporting
From: Edward Cree @ 2016-05-06 14:28 UTC (permalink / raw)
To: Stephen Hemminger, netdev; +Cc: John W. Linville
Since we can only configure unicast, we probably want to be able to
display unicast, rather than multicast.
Fixes: 906ac5437ab8 ("geneve: add support for IPv6 link partners")
Signed-off-by: Edward Cree <ecree@solarflare.com>
---
I'm assuming this is what was intended, but tbh I don't know why we
need to check for multicast on the display side at all, rather than
just displaying whatever the kernel gives us.
ip/iplink_geneve.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ip/iplink_geneve.c b/ip/iplink_geneve.c
index 84d948f..65af6b3 100644
--- a/ip/iplink_geneve.c
+++ b/ip/iplink_geneve.c
@@ -204,7 +204,7 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
memcpy(&addr, RTA_DATA(tb[IFLA_GENEVE_REMOTE6]), sizeof(struct in6_addr));
if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) {
- if (IN6_IS_ADDR_MULTICAST(&addr))
+ if (!IN6_IS_ADDR_MULTICAST(&addr))
fprintf(f, "remote %s ",
format_host(AF_INET6, sizeof(struct in6_addr), &addr));
}
--
2.4.3
^ permalink raw reply related
* Re: [PATCH iproute2] geneve: fix IPv6 remote address reporting
From: Phil Sutter @ 2016-05-06 14:43 UTC (permalink / raw)
To: Edward Cree; +Cc: Stephen Hemminger, netdev, John W. Linville
In-Reply-To: <572CAA09.302@solarflare.com>
On Fri, May 06, 2016 at 03:28:25PM +0100, Edward Cree wrote:
> Since we can only configure unicast, we probably want to be able to
> display unicast, rather than multicast.
Furthermore, the kernel even rejects multicast peer addresses.
> I'm assuming this is what was intended, but tbh I don't know why we
> need to check for multicast on the display side at all, rather than
> just displaying whatever the kernel gives us.
Why do you then propose a dubious fix to a dubious check instead of
getting rid of it in the first place? Reminds me a bit of this here (no
offense intended):
http://geekandpoke.typepad.com/geekandpoke/2011/07/good-coders.html
Cheers, Phil
^ permalink raw reply
* Re: [REGRESSION] asix: Lots of asix_rx_fixup() errors and slow transmissions
From: Dean Jenkins @ 2016-05-06 15:00 UTC (permalink / raw)
To: Guodong Xu, Dean Jenkins
Cc: John Stultz, lkml, Mark Craske, David S. Miller, YongQin Liu,
linux-usb, netdev, Ivan Vecera, David B. Robins
In-Reply-To: <CAFGCpxyeXkbQXW6Dm9ZpUXpVDWgaQziPnsC9GcZPqeg5jnbJUA@mail.gmail.com>
On 05/05/16 13:19, Guodong Xu wrote:
> Hi, Dean
>
> I am not sure why do you insist 'not full speed'. Actually, the tests
> I run on ARM-64bit is at USB full speed mode. I pasted my log here:
> http://paste.ubuntu.com/16236442/
> , which includes the information you requested above, ifconfig, dmesg.
> The interval between two consecutive errors varies from 10 to 40ms.
>
Your log from http://paste.ubuntu.com/16236442/ shows high speed for
device 3 is not being used:
[ 3.586968] usb 1-1: new full-speed USB device number 2 using dwc2
[ 3.792091] usb 1-1: not running at top speed; connect to a high
speed hub
[ 3.800477] hub 1-1:1.0: USB hub found
[ 3.803658] hub 1-1:1.0: 3 ports detected
[ 4.086636] usb 1-1.2: new full-speed USB device number 3 using dwc2
[ 4.202209] usb 1-1.2: not running at top speed; connect to a high
speed hub
[ 8.851236] asix 1-1.2:1.0 eth0: register 'asix' at
usb-f72c0000.usb-1.2, ASIX AX88772B USB 2.0 Ethernet, 00:0e:c6:fa:bf:fd
Hopefully, you know USB 2.0 high speed (480Mbps) is faster than full
speed (12Mbps) mode.
Therefore, your USB to Ethernet Adaptor is not running in its optimal
"normal" high speed operation and there is a USB hub in the way that is
not running at USB high speed mode. This is an abnormal configuration
and potentially explains some of your failure observations.
Running at full-speed (12Mbps) mode would explain why the timestamps has
gaps of ms rather than us gaps (for 480Mbps).
In other words, the full-speed hub is restricting the USB to Ethernet
Adaptor to a 12Mbps (half-duplex) bandwidth to support Ethernet 100Mbps
(full-duplex) traffic. That is not going to work very well because
Ethernet frames (perhaps partial Ethernet frames) need to be discarded
within the USB link.
Your ifconfig output from http://paste.ubuntu.com/16236442/ shows 249 errors
eth0 Link encap:Ethernet HWaddr 00:0e:c6:fa:bf:fd
inet addr:192.168.1.11 Bcast:192.168.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:865 errors:249 dropped:0 overruns:0 frame:0
TX packets:880 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1228273 (1.1 MiB) TX bytes:68955 (67.3 KiB)
Before the test
RX packets:28 errors:0 dropped:0 overruns:0 frame:0
After the test
RX packets:865 errors:249 dropped:0 overruns:0 frame:0
Good test packets = 865 - 28 = 837
Detected bad Ethernet frames = 249
Bad to good ratio is 249:837 = 1:3.36 so 1 detected bad Ethernet frame
per 3.36 good Ethernet frames
Your ifconfig output from http://paste.ubuntu.com/16236764/ shows 1282
errors
eth0 Link encap:Ethernet HWaddr 00:0e:c6:fa:bf:fd
inet addr:192.168.1.11 Bcast:192.168.1.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:55 errors:1282 dropped:0 overruns:0 frame:0
TX packets:64 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:14287 (13.9 KiB) TX bytes:7639 (7.4 KiB)
Before the test
RX packets:19 errors:0 dropped:0 overruns:0 frame:0
After the test
RX packets:55 errors:1282 dropped:0 overruns:0 frame:0
Good test packets = 55 - 19 = 36
Detected bad Ethernet frames = 1282
Bad to good ratio is 1282:36 = 1:0.28 so 1 detected bad Ethernet frame
per 0.028 good Ethernet frames
This suggests a very high error rate.
>> It is interesting that the reported "remaining" value is 988. Is 988 always
>> shown ? I mean that do you see any other "remaining" values for the "Data
>> Header synchronisation was lost" error message ?
> Yes and No. When doing iperf test in TCP mode, always 988. I have
> never seen other "remaining" value.
>
> But,
> 1. I tried "ping -f -s 1400 [my.arm.64bit.board.ip]", but this cannot
> trigger the error.
> 2. Tried iperf in UDP mode, I saw "Data Header synchronisation was
> lost" remaining value is 984 (again, seemingly always in several
> tries). Log is pasted here. http://paste.ubuntu.com/16236764/
>
In http://paste.ubuntu.com/16236764/ you see very many
[ 41.938370] asix 1-1.2:1.0 eth0: asix_rx_fixup() Bad Header Length
0x11400040, offset 4
but only a few
[ 42.214607] asix 1-1.2:1.0 eth0: asix_rx_fixup() Data Header
synchronisation was lost, remaining 984
This suggests that the "Bad Header Length" and "Data Header
synchronisation was lost" error messages are not related to consecutive
URBs. The expectation is that a "Data Header synchronisation was lost"
error message is immediately followed by a "Bad Header Length" message
with a timestamp much less than 1ms (for high speed USB). This is
because an Ethernet frame that spans URBs needs low latency so should be
sent quickly in consecutive URBs.
The Bad Header Length error messages with offset 4 indicates that 32-bit
header word was not found in the expected location at the start of the
URB buffer.
[ 41.938370] asix 1-1.2:1.0 eth0: asix_rx_fixup() Bad Header Length
0x11400040, offset 4
This evidence is suggesting either the data stream is garbled such as by
many dropped URBs or lost partial Ethernet frames, or the ASIX protocol
for the AX88772B chipset differs from the AX88772 chipset so the ASIX
driver is looking in the wrong place for the 32-bit header word. I
suspect data is lost due to the restricted 12Mbps bandwidth.
My conclusion is that your USB to Ethernet Adaptor is not running at
high speed (480Mbps) mode which is causing a partial loss (corruption)
of Ethernet frames across the USB link. A USB Protocol Analyser or
software tool usbmon could be used to confirm this scenario.
Therefore please retest with a working high-speed USB hub or remove the
full-speed USB hub from the test environment and directly connect the
USB to Ethernet Adaptor to the root hub of the USB port. Then repeat the
tests to see whether anything improved.
In other words, you need to eliminate the dmesg messages saying "not
running at top speed; connect to a high speed hub".
Best regards,
Dean
> -Guodong Xu
>
>
--
Dean Jenkins
Embedded Software Engineer
Linux Transportation Solutions
Mentor Embedded Software Division
Mentor Graphics (UK) Ltd.
^ permalink raw reply
* Re: [RFC PATCH net-next 14/20] net: dsa: mv88e6xxx: factorize VLAN Ethertype
From: Vivien Didelot @ 2016-05-06 15:12 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, linux-kernel, kernel, David S. Miller, Florian Fainelli
In-Reply-To: <20160506005759.GL7972@lunn.ch>
Hi Andrew,
Andrew Lunn <andrew@lunn.ch> writes:
>> @@ -55,6 +58,7 @@ static const struct mv88e6xxx_info mv88e6131_table[] = {
>> .num_databases = 256,
>> .num_ports = 10,
>> .flags = MV88E6XXX_FLAG_ATU |
>> + MV88E6XXX_FLAG_CORE_TAG_TYPE |
>> MV88E6XXX_FLAG_PPU |
>> MV88E6XXX_FLAG_VLANTABLE |
>> MV88E6XXX_FLAG_VTU,
>
> Rather than repeating these flags again and again, could you add one
> #define containing the flags, and then use that to initialise .flags.
Hum OK, I wasn't sure, but looking at the final mv88e6xxx_info table, I
can see that models from the same family all have the same set of flags,
even if they don't have the same number of ports or databases.
I'll add one MV88E6XXX_FLAGS_xxxx per family.
Thanks,
Vivien
^ permalink raw reply
* Re: [PATCH iproute2] geneve: fix IPv6 remote address reporting
From: Edward Cree @ 2016-05-06 15:14 UTC (permalink / raw)
To: Phil Sutter, Stephen Hemminger, netdev, John W. Linville
In-Reply-To: <20160506144345.GC11058@orbyte.nwl.cc>
On 06/05/16 15:43, Phil Sutter wrote:
> On Fri, May 06, 2016 at 03:28:25PM +0100, Edward Cree wrote:
>> Since we can only configure unicast, we probably want to be able to
>> display unicast, rather than multicast.
> Furthermore, the kernel even rejects multicast peer addresses.
Yes, but a future kernel might not, and iproute2 is meant to be forward-
compatible.
> Why do you then propose a dubious fix to a dubious check instead of
> getting rid of it in the first place?
Because John Linville clearly had some reason for putting a check there,
and he probably knows better than me. Chesterton's fence.
-Ed
^ permalink raw reply
* Re: [REGRESSION] asix: Lots of asix_rx_fixup() errors and slow transmissions
From: Andrew Lunn @ 2016-05-06 15:27 UTC (permalink / raw)
To: Dean Jenkins
Cc: Guodong Xu, John Stultz, lkml, Mark Craske, David S. Miller,
YongQin Liu, linux-usb, netdev, Ivan Vecera, David B. Robins
In-Reply-To: <572CB188.7050203@mentor.com>
> In other words, the full-speed hub is restricting the USB to
> Ethernet Adaptor to a 12Mbps (half-duplex) bandwidth to support
> Ethernet 100Mbps (full-duplex) traffic. That is not going to work
> very well because Ethernet frames (perhaps partial Ethernet frames)
> need to be discarded within the USB link.
If that really is true, the design is broken. I would expect the
adaptor to reliably transfer whole frames over USB, and drop whole
frames from its receive queue when the USB is congested. TCP is also
going to see the USB bottleneck as just like any bottleneck in the
network and back off. So TCP streams should not cause major congestion
on the USB link. Going over a 12Mbps USB link should be no different
to hitting an old Ethernet hub which can only do 10/Half.
> Therefore please retest with a working high-speed USB hub or remove
> the full-speed USB hub from the test environment and directly
> connect the USB to Ethernet Adaptor to the root hub of the USB port.
> Then repeat the tests to see whether anything improved.
>
> In other words, you need to eliminate the dmesg messages saying "not
> running at top speed; connect to a high speed hub".
I would also suggest testing with the Ethernet at 10/half. You should
be able to use Ethtool to set that up. Your USB and Ethernet bandwidth
become more equal. If you still see errors, it suggests a protocol
implementation error somewhere.
Andrew
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox