* Re: [PATCH 1/5] bonding: simplify and use RCU protection for 3ad xmit path
From: Ding Tianhong @ 2013-08-30 1:57 UTC (permalink / raw)
To: Nikolay Aleksandrov
Cc: Jay Vosburgh, Andy Gospodarek, David S. Miller, Veaceslav Falico,
Netdev
In-Reply-To: <521F59E2.8030707@redhat.com>
On 2013/8/29 22:25, Nikolay Aleksandrov wrote:
> On 08/28/2013 06:20 AM, Ding Tianhong wrote:
>> The commit 278b20837511776dc9d5f6ee1c7fabd5479838bb
>> (bonding: initial RCU conversion) has convert the roundrobin, active-backup,
>> broadcast and xor xmit path to rcu protection, the performance will be better
>> for these mode, so this time, convert xmit path for 3ad mode.
>>
>> Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
>> Signed-off-by: Wang Yufen <wangyufen@huawei.com>
>> Cc: Nikolay Aleksandrov <nikolay@redhat.com>
>> Cc: Veaceslav Falico <vfalico@redhat.com>
>> ---
>> drivers/net/bonding/bond_3ad.c | 31 +++++++++++++------------------
>> drivers/net/bonding/bonding.h | 22 ++++++++++++++++++++++
>> 2 files changed, 35 insertions(+), 18 deletions(-)
>>
>> diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
>> index 9010265..52d76a4 100644
>> --- a/drivers/net/bonding/bond_3ad.c
>> +++ b/drivers/net/bonding/bond_3ad.c
>> @@ -143,7 +143,7 @@ static inline struct bonding *__get_bond_by_port(struct port *port)
>> */
>> static inline struct port *__get_first_port(struct bonding *bond)
>> {
>> - struct slave *first_slave = bond_first_slave(bond);
>> + struct slave *first_slave = bond_first_slave_rcu(bond);
>>
>> return first_slave ? &(SLAVE_AD_INFO(first_slave).port) : NULL;
>> }
>> @@ -163,7 +163,7 @@ static inline struct port *__get_next_port(struct port *port)
>> // If there's no bond for this port, or this is the last slave
>> if (bond == NULL)
>> return NULL;
>> - slave_next = bond_next_slave(bond, slave);
>> + slave_next = bond_next_slave_rcu(bond, slave);
>> if (!slave_next || bond_is_first_slave(bond, slave_next))
>> return NULL;
>>
>> @@ -2417,16 +2417,14 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
>>
>> int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
>> {
>> - struct slave *slave, *start_at;
>> + struct slave *slave;
> Please re-arrange longest -> shortest where possible.
>
something wrong with my vim, so fix it, thanks.
>> struct bonding *bond = netdev_priv(dev);
>> int slave_agg_no;
>> int slaves_in_agg;
>> int agg_id;
>> - int i;
>> struct ad_info ad_info;
>> int res = 1;
>>
>> - read_lock(&bond->lock);
>> if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
>> pr_debug("%s: Error: __bond_3ad_get_active_agg_info failed\n",
>> dev->name);
>> @@ -2444,13 +2442,16 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
>>
>> slave_agg_no = bond->xmit_hash_policy(skb, slaves_in_agg);
>>
>> - bond_for_each_slave(bond, slave) {
>> + bond_for_each_slave_rcu(bond, slave) {
>> struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
>>
>> if (agg && (agg->aggregator_identifier == agg_id)) {
>> - slave_agg_no--;
>> - if (slave_agg_no < 0)
>> - break;
>> + if (--slave_agg_no < 0) {
>> + if (SLAVE_IS_OK(slave)) {
>> + res = bond_dev_queue_xmit(bond, skb, slave->dev);
>> + goto out;
>> + }
>> + }
>> }
>> }
>>
>> @@ -2460,23 +2461,17 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
>> goto out;
>> }
>>
>> - start_at = slave;
>> -
>> - bond_for_each_slave_from(bond, slave, i, start_at) {
>> - int slave_agg_id = 0;
>> + bond_for_each_slave_rcu(bond, slave) {
>> struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
>>
>> - if (agg)
>> - slave_agg_id = agg->aggregator_identifier;
>> -
>> - if (SLAVE_IS_OK(slave) && agg && (slave_agg_id == agg_id)) {
>> + if (SLAVE_IS_OK(slave) && agg &&
>> + (agg->aggregator_identifier == agg_id)) {
> Please drop the ( ) from (agg->aggregator_identifier == agg_id), also align it
> properly.
>
my mistake, thanks.
>> res = bond_dev_queue_xmit(bond, skb, slave->dev);
>> break;
>> }
>> }
>>
>> out:
>> - read_unlock(&bond->lock);
>> if (res) {
>> /* no suitable interface, frame not sent */
>> kfree_skb(skb);
>> diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
>> index 4bf52d5..ecb5d1d 100644
>> --- a/drivers/net/bonding/bonding.h
>> +++ b/drivers/net/bonding/bonding.h
>> @@ -74,6 +74,9 @@
>> /* slave list primitives */
>> #define bond_to_slave(ptr) list_entry(ptr, struct slave, list)
>>
>> +/* slave list primitives, Caller must hold rcu_read_lock */
>> +#define bond_to_slave_rcu(ptr) list_entry_rcu(ptr, struct slave, list)
>> +
>> /* IMPORTANT: bond_first/last_slave can return NULL in case of an empty list */
>> #define bond_first_slave(bond) \
>> list_first_entry_or_null(&(bond)->slave_list, struct slave, list)
>> @@ -81,6 +84,16 @@
>> (list_empty(&(bond)->slave_list) ? NULL : \
>> bond_to_slave((bond)->slave_list.prev))
>>
>> +/**
>> + * IMPORTANT: bond_first/last_slave_rcu can return NULL in case of an empty list
>> + * Caller must hold rcu_read_lock
>> + */
> Styling nit: the comments in net/ should be /* text...
miss the net-next. add in resend.
>
>> +#define bond_first_slave_rcu(bond) \
>> + list_first_or_null_rcu(&(bond)->slave_list, struct slave, list)
>> +#define bond_last_slave_rcu(bond) \
>> + (list_emptry(&(bond)->slave_list) ? NULL : \
> ^^^^^^^^^^^^^^^^^^^^^
> Did you compile this ?
oh, I compiled, but the func did not used, so did not show any problem, it's a big error, I will review
and check all above.
>
>> + bond_to_slave_rcu((bond)->slave_list.prev))
>> +
>> #define bond_is_first_slave(bond, pos) ((pos)->list.prev == &(bond)->slave_list)
>> #define bond_is_last_slave(bond, pos) ((pos)->list.next == &(bond)->slave_list)
>>
>> @@ -93,6 +106,15 @@
>> (bond_is_first_slave(bond, pos) ? bond_last_slave(bond) : \
>> bond_to_slave((pos)->list.prev))
>>
>> +/* Since bond_first/last_slave_rcu can return NULL, these can return NULL too */
>> +#define bond_next_slave_rcu(bond, pos) \
>> + (bond_is_last_slave(bond, pos) ? bond_first_slave_rcu(bond) : \
>> + bond_to_slave_rcu((pos)->list.next))
>> +
>> +#define bond_prev_slave_rcu(bond, pos) \
>> + (bond_is_first_slave(bond, pos) ? bond_last_slave_rcu(bond) : \
>> + bond_to_slave_rcu((pos)->list.prev))
>> +
>> /**
>> * bond_for_each_slave_from - iterate the slaves list from a starting point
>> * @bond: the bond holding this list.
>>
>
>
> .
>
^ permalink raw reply
* Re: [PATCH v2 net-next] pkt_sched: fq: Fair Queue packet scheduler
From: David Miller @ 2013-08-30 1:47 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev, ycheng, ncardwell
In-Reply-To: <1377816595.8277.54.camel@edumazet-glaptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Thu, 29 Aug 2013 15:49:55 -0700
> From: Eric Dumazet <edumazet@google.com>
>
> - Uses perfect flow match (not stochastic hash like SFQ/FQ_codel)
> - Uses the new_flow/old_flow separation from FQ_codel
> - New flows get an initial credit allowing IW10 without added delay.
> - Special FIFO queue for high prio packets (no need for PRIO + FQ)
> - Uses a hash table of RB trees to locate the flows at enqueue() time
> - Smart on demand gc (at enqueue() time, RB tree lookup evicts old
> unused flows)
> - Dynamic memory allocations.
> - Designed to allow millions of concurrent flows per Qdisc.
> - Small memory footprint : ~8K per Qdisc, and 104 bytes per flow.
> - Single high resolution timer for throttled flows (if any).
> - One RB tree to link throttled flows.
> - Ability to have a max rate per flow. We might add a socket option
> to add per socket limitation.
>
> Attempts have been made to add TCP pacing in TCP stack, but this
> seems to add complex code to an already complex stack.
>
> TCP pacing is welcomed for flows having idle times, as the cwnd
> permits TCP stack to queue a possibly large number of packets.
>
> This removes the 'slow start after idle' choice, hitting badly
> large BDP flows, and applications delivering chunks of data
> as video streams.
>
> Nicely spaced packets :
> Here interface is 10Gbit, but flow bottleneck is ~20Mbit
>
> cwin is big, yet FQ avoids the typical bursts generated by TCP
> (as in netperf TCP_RR -- -r 100000,100000)
...
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Applied, thanks Eric!
^ permalink raw reply
* Re: [PATCH 0/5] bonding: Patchset for rcu use in bonding
From: Ding Tianhong @ 2013-08-30 1:37 UTC (permalink / raw)
To: Nikolay Aleksandrov
Cc: Jay Vosburgh, Andy Gospodarek, David S. Miller, Veaceslav Falico,
Netdev
In-Reply-To: <521F5AA3.4030105@redhat.com>
On 2013/8/29 22:28, Nikolay Aleksandrov wrote:
> On 08/28/2013 06:20 AM, Ding Tianhong wrote:
>> Hi:
>>
>> The Patch Set convert the xmit of 3ad and alb mode to use rcu lock.
>> replace and add more rcu list function.
>> fix a bug to protect bonding_store_xmit_hash().
>>
>> I test well and no problems found till now.
>>
>> Ding Tianhong (3):
>> Wang Yufen (1):
>> Yang Yingliang (1):
>> bonding: simplify and use RCU protection for 3ad xmit path
>> bonding: replace read_lock to rcu_read_lock for
>> bond_3ad_get_active_agg_info()
>> bonding: add rtnl lock for bonding_store_xmit_hash
>> bonding: restructure and simplify bond_for_each_slave_next()
>> bonding: use RCU protection for alb xmit path
>>
>> drivers/net/bonding/bond_3ad.c | 35 +++++++++++++++-------------------
>> drivers/net/bonding/bond_alb.c | 23 ++++++++++------------
>> drivers/net/bonding/bond_main.c | 6 ++----
>> drivers/net/bonding/bond_sysfs.c | 4 ++++
>> drivers/net/bonding/bonding.h | 41 ++++++++++++++++++++++++++++++++++++----
>> 5 files changed, 68 insertions(+), 41 deletions(-)
>>
> Thanks for the work, I was on vacation and travelling after my initial RCU
> conversion so I got a little behind with these conversions, my idea was quite
> different :-)
> Anyway, I'd also appreciate some benchmarks, also some more information on what
> type of testing did you run ?
> I've given some preliminary comments to the patches, I'll have to think more
> about them in this form.
>
> Cheers,
> Nik
>
> .
It looks like a wonderful vocation :).
I focus on the 3ad and alb mode, because the modify was manly for xmit, so my test environment was consist of 4 Intel82599 10G card, and use mode lacp ,alb.
I use iperf to test, after the patch, the performance was a little better and no problem
occurs.
>
^ permalink raw reply
* Re: [PATCH net-next] tcp: Remove needless check of return value
From: David Miller @ 2013-08-30 1:36 UTC (permalink / raw)
To: subramanian.vijay; +Cc: netdev, eric.dumazet
In-Reply-To: <1377825558-8800-1-git-send-email-subramanian.vijay@gmail.com>
From: Vijay Subramanian <subramanian.vijay@gmail.com>
Date: Thu, 29 Aug 2013 18:19:18 -0700
> After commit 0c24604b (tcp: implement RFC 5961 4.2), tcp_rcv_established() only
> returns 0 since we no longer send RSTs in response to SYNs. We can remove the
> check on the return value.
>
> Signed-off-by: Vijay Subramanian <subramanian.vijay@gmail.com>
Always returning the same value is the same as returning no value at all.
Make tcp_rcv_established() return void please.
^ permalink raw reply
* [PATCH net-next] tcp: Remove needless check of return value
From: Vijay Subramanian @ 2013-08-30 1:19 UTC (permalink / raw)
To: netdev; +Cc: davem, eric.dumazet, Vijay Subramanian
After commit 0c24604b (tcp: implement RFC 5961 4.2), tcp_rcv_established() only
returns 0 since we no longer send RSTs in response to SYNs. We can remove the
check on the return value.
Signed-off-by: Vijay Subramanian <subramanian.vijay@gmail.com>
---
net/ipv4/tcp_ipv4.c | 5 +----
net/ipv6/tcp_ipv6.c | 3 +--
2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 09d45d7..b14266b 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1799,10 +1799,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
sk->sk_rx_dst = NULL;
}
}
- if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {
- rsk = sk;
- goto reset;
- }
+ tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len);
return 0;
}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 5bcfadf..9acdced 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1360,8 +1360,7 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
}
}
- if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
- goto reset;
+ tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len);
if (opt_skb)
goto ipv6_pktoptions;
return 0;
--
1.7.9.5
^ permalink raw reply related
* Re: [-next] openvswitch BUILD_BUG_ON failed
From: Jesse Gross @ 2013-08-30 1:11 UTC (permalink / raw)
To: David Miller
Cc: geert, Andy Zhou, dev@openvswitch.org, netdev,
Linux Kernel Mailing List, linux-next
In-Reply-To: <20130829.181001.145658561677052552.davem@davemloft.net>
On Thu, Aug 29, 2013 at 3:10 PM, David Miller <davem@davemloft.net> wrote:
> From: Jesse Gross <jesse@nicira.com>
> Date: Thu, 29 Aug 2013 14:42:22 -0700
>
>> On Thu, Aug 29, 2013 at 2:21 PM, Geert Uytterhoeven
>> <geert@linux-m68k.org> wrote:
>>> However, I have some doubts about other alignment "enforcements":
>>>
>>> "__aligned(__alignof__(long))" makes the whole struct aligned to the
>>> alignment rule for "long":
>>> 1. This is only 2 bytes on m68k, i.e. != sizeof(long).
>>> 2. This is 4 bytes on many 32-bit platforms, which may be less than the
>>> default alignment for "__be64" (cfr. some members of struct
>>> ovs_key_ipv4_tunnel), so this may make those 64-bit members unaligned.
>>
>> Do any of those 32-bit architectures actually care about alignment of
>> 64 bit values? On 32-bit x86, a long is 32 bits but the alignment
>> requirement of __be64 is also 32 bit.
>
> All except x86-32 do, it is in fact the odd man out with respect to this
> issue.
Thanks, good to know.
Andy, do you want to modify your patch to just drop the alignment
specification as Geert suggested (but definitely keep the new build
assert that you added)? It's probably better to just send the patch to
netdev (against net-next) as well since you'll likely get better
comments there and we can fix this faster if you cut out the
middleman.
^ permalink raw reply
* Re:Very Urgent!!!
From: Doris Omar @ 2013-08-30 0:55 UTC (permalink / raw)
Greetings from BURKINA FASO:
Let me start by introduce myself,I am Mrs Doris Omar, BILL AND EXCHANGE MANAGER (Bank of Africa) Ouagadougou, Burkina Faso.I am writting you this letter based on the latest development at our bank which I will like to bring to your personal edification. $12,250million transfer claims. this is a legitimate transaction and I agreed to offer you 40% of this money as my foreign partner after confirmation of the fund in your bank account,If you are interested, please get back to me for more clarification.
Yours faithful,
Mrs Doris Omar.
^ permalink raw reply
* Re: [PATCH net-next 1/2] sh_eth: Fix cache invalidation omission of receive buffer
From: Simon Horman @ 2013-08-30 0:16 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-sh, magnus.damm, sergei.shtylyov, kouei.abe.cp
In-Reply-To: <20130829.161553.755954777649764863.davem@davemloft.net>
On Thu, Aug 29, 2013 at 04:15:53PM -0400, David Miller wrote:
> From: Simon Horman <horms+renesas@verge.net.au>
> Date: Wed, 28 Aug 2013 09:43:08 +0900
>
> > From: Kouei Abe <kouei.abe.cp@renesas.com>
> >
> > Signed-off-by: Kouei Abe <kouei.abe.cp@renesas.com>
> > Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
> > ---
> > drivers/net/ethernet/renesas/sh_eth.c | 2 ++
> > 1 file changed, 2 insertions(+)
> >
> > diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
> > index c357076..f386a8f 100644
> > --- a/drivers/net/ethernet/renesas/sh_eth.c
> > +++ b/drivers/net/ethernet/renesas/sh_eth.c
> > @@ -1342,6 +1342,8 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
> > mdp->rx_skbuff[entry] = NULL;
> > if (mdp->cd->rpadir)
> > skb_reserve(skb, NET_IP_ALIGN);
> > + dma_sync_single_for_cpu(&ndev->dev, rxdesc->addr,
> > + mdp->rx_buf_sz, DMA_FROM_DEVICE);
>
> Please indent the second line of the dma sync call properly.
>
> The arguments should start at the first column after the openning
> parenthesis of the function call on the first line, using the
> appropriate number of TAB then space characters (as needed).
Sorry for missing that. I'll fix it up and re-post.
^ permalink raw reply
* Re: [PATCH net-next v2] net: neighbour: Remove CONFIG_ARPD
From: Eric W. Biederman @ 2013-08-29 23:39 UTC (permalink / raw)
To: Tim Gardner
Cc: netdev, linux-kernel, David S. Miller, Alexey Kuznetsov,
James Morris, Hideaki YOSHIFUJI, Patrick McHardy, Gao feng,
Joe Perches, Veaceslav Falico
In-Reply-To: <1377779927-28500-1-git-send-email-tim.gardner@canonical.com>
Tim Gardner <tim.gardner@canonical.com> writes:
> This config option is superfluous in that it only guards a call
> to neigh_app_ns(). Enabling CONFIG_ARPD by default has no
> change in behavior. There will now be call to __neigh_notify()
> for each ARP resolution, which has no impact unless there is a
> user space daemon waiting to receive the notification, i.e.,
> the case for which CONFIG_ARPD was designed anyways.
This looks good to me, and much less magic to maintain.
Eric
> Suggested-by: Eric W. Biederman <ebiederm@xmission.com>
Reviewed-by: "Eric W. Biederman" <ebiederm@xmission.com>
> 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>
> Cc: "Eric W. Biederman" <ebiederm@xmission.com>
> Cc: Gao feng <gaofeng@cn.fujitsu.com>
> Cc: Joe Perches <joe@perches.com>
> Cc: Veaceslav Falico <vfalico@redhat.com>
> Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
> ---
>
> Eric's suggestion to simply remove the config option makes sense
> to me. If acceptable then I'll submit a patch series that also removes
> CONFIG_ARPD from the various arch defconfigs.
>
> net/core/neighbour.c | 2 --
> net/ipv4/Kconfig | 16 ----------------
> net/ipv4/arp.c | 2 --
> net/ipv6/ndisc.c | 2 --
> 4 files changed, 22 deletions(-)
>
> diff --git a/net/core/neighbour.c b/net/core/neighbour.c
> index 60533db..6072610 100644
> --- a/net/core/neighbour.c
> +++ b/net/core/neighbour.c
> @@ -2759,13 +2759,11 @@ errout:
> rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
> }
>
> -#ifdef CONFIG_ARPD
> void neigh_app_ns(struct neighbour *n)
> {
> __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
> }
> EXPORT_SYMBOL(neigh_app_ns);
> -#endif /* CONFIG_ARPD */
>
> #ifdef CONFIG_SYSCTL
> static int zero;
> diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
> index 37cf1a6..05c57f0 100644
> --- a/net/ipv4/Kconfig
> +++ b/net/ipv4/Kconfig
> @@ -259,22 +259,6 @@ config IP_PIMSM_V2
> gated-5). This routing protocol is not used widely, so say N unless
> you want to play with it.
>
> -config ARPD
> - bool "IP: ARP daemon support"
> - ---help---
> - The kernel maintains an internal cache which maps IP addresses to
> - hardware addresses on the local network, so that Ethernet
> - frames are sent to the proper address on the physical networking
> - layer. Normally, kernel uses the ARP protocol to resolve these
> - mappings.
> -
> - Saying Y here adds support to have an user space daemon to do this
> - resolution instead. This is useful for implementing an alternate
> - address resolution protocol (e.g. NHRP on mGRE tunnels) and also for
> - testing purposes.
> -
> - If unsure, say N.
> -
> config SYN_COOKIES
> bool "IP: TCP syncookie support"
> ---help---
> diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
> index 4429b01..7808093 100644
> --- a/net/ipv4/arp.c
> +++ b/net/ipv4/arp.c
> @@ -368,9 +368,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
> } else {
> probes -= neigh->parms->app_probes;
> if (probes < 0) {
> -#ifdef CONFIG_ARPD
> neigh_app_ns(neigh);
> -#endif
> return;
> }
> }
> diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
> index 04d31c2..d5693ad 100644
> --- a/net/ipv6/ndisc.c
> +++ b/net/ipv6/ndisc.c
> @@ -663,9 +663,7 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
> }
> ndisc_send_ns(dev, neigh, target, target, saddr);
> } else if ((probes -= neigh->parms->app_probes) < 0) {
> -#ifdef CONFIG_ARPD
> neigh_app_ns(neigh);
> -#endif
> } else {
> addrconf_addr_solict_mult(target, &mcaddr);
> ndisc_send_ns(dev, NULL, target, &mcaddr, saddr);
^ permalink raw reply
* Re: [PATCH] USB2NET : SR9700 : One Chip USB 1.1 USB2NET SR9700 Device Driver Support
From: Francois Romieu @ 2013-08-29 23:06 UTC (permalink / raw)
To: liujunliang_ljl
Cc: davem, horms, joe, gregkh, netdev, linux-usb, linux-kernel,
sunhecheng
In-Reply-To: <1377746832-6201-1-git-send-email-liujunliang_ljl@163.com>
Keep it small though literate.
---
drivers/net/usb/sr9700.c | 30 ++++++++++++------------------
1 file changed, 12 insertions(+), 18 deletions(-)
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
index f7f46e6..3f05b35 100644
--- a/drivers/net/usb/sr9700.c
+++ b/drivers/net/usb/sr9700.c
@@ -71,31 +71,25 @@ static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
static int wait_phy_eeprom_ready(struct usbnet *dev, int phy)
{
- int i, ret;
+ int i;
- ret = 0;
for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
u8 tmp = 0;
+ int ret;
udelay(1);
ret = sr_read_reg(dev, EPCR, &tmp);
if (ret < 0)
- goto out;
+ return ret;
/* ready */
- if ((tmp & EPCR_ERRE) == 0)
- break;
+ if (!(tmp & EPCR_ERRE))
+ return 0;
}
- if (i >= SR_SHARE_TIMEOUT) {
- netdev_err(dev->net, "%s write timed out!\n",
- phy ? "phy" : "eeprom");
- ret = -EIO;
- goto out;
- }
+ netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom");
-out:
- return ret;
+ return -EIO;
}
static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg,
@@ -110,7 +104,7 @@ static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg,
ret = wait_phy_eeprom_ready(dev, phy);
if (ret < 0)
- goto out;
+ goto out_unlock;
sr_write_reg(dev, EPCR, 0x0);
ret = sr_read(dev, EPDR, 2, value);
@@ -118,7 +112,7 @@ static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg,
netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
phy, reg, *value, ret);
-out:
+out_unlock:
mutex_unlock(&dev->phy_mutex);
return ret;
}
@@ -132,18 +126,18 @@ static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg,
ret = sr_write(dev, EPDR, 2, &value);
if (ret < 0)
- goto out;
+ goto out_unlock;
sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
sr_write_reg(dev, EPCR, phy ? 0x1a : 0x12);
ret = wait_phy_eeprom_ready(dev, phy);
if (ret < 0)
- goto out;
+ goto out_unlock;
sr_write_reg(dev, EPCR, 0x0);
-out:
+out_unlock:
mutex_unlock(&dev->phy_mutex);
return ret;
}
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH] USB2NET : SR9700 : One Chip USB 1.1 USB2NET SR9700 Device Driver Support
From: Francois Romieu @ 2013-08-29 23:06 UTC (permalink / raw)
To: liujunliang_ljl
Cc: davem, horms, joe, gregkh, netdev, linux-usb, linux-kernel,
sunhecheng
In-Reply-To: <1377746832-6201-1-git-send-email-liujunliang_ljl@163.com>
Liu, please check those.
---
drivers/net/usb/sr9700.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
index 3f05b35..3ae3caf 100644
--- a/drivers/net/usb/sr9700.c
+++ b/drivers/net/usb/sr9700.c
@@ -99,8 +99,9 @@ static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg,
mutex_lock(&dev->phy_mutex);
+ // FIXME: the mistery 0x40 appears in sr_share_write_word as well.
sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
- sr_write_reg(dev, EPCR, phy ? 0xc : 0x4);
+ sr_write_reg(dev, EPCR, phy ? (EPCR_EPOS | EPCR_ERPRR) : EPCR_ERPRR);
ret = wait_phy_eeprom_ready(dev, phy);
if (ret < 0)
@@ -128,7 +129,10 @@ static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg,
if (ret < 0)
goto out_unlock;
+ // FIXME: see sr_share_read_word above.
sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+ // 0x1a -> EPCR_WEP | EPCR_EPOS | EPCR_ERPRW ?
+ // 0x12 -> EPCR_WEP | EPCR_ERPRW ?
sr_write_reg(dev, EPCR, phy ? 0x1a : 0x12);
ret = wait_phy_eeprom_ready(dev, phy);
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH] USB2NET : SR9700 : One Chip USB 1.1 USB2NET SR9700 Device Driver Support
From: Francois Romieu @ 2013-08-29 23:06 UTC (permalink / raw)
To: liujunliang_ljl
Cc: davem, horms, joe, gregkh, netdev, linux-usb, linux-kernel,
sunhecheng
In-Reply-To: <1377746832-6201-1-git-send-email-liujunliang_ljl@163.com>
- use all columns
- the driver uses both 'netdev' and 'net'. Let's use 'netdev' ('net' is
shorter but it tastes of network namespaces)
- don't dereference dev->net when there is a local netdev at hand
- use some existing #define (please check those)
- skb_set_tail_pointer to avoid compiler cast warnings
Pick whatever you want. skb_set_tail_pointer if nothing else.
---
drivers/net/usb/sr9700.c | 113 +++++++++++++++++++++++++----------------------
1 file changed, 60 insertions(+), 53 deletions(-)
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
index 76e11f5..f7f46e6 100644
--- a/drivers/net/usb/sr9700.c
+++ b/drivers/net/usb/sr9700.c
@@ -28,8 +28,8 @@ static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
{
int err;
- err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG,
- 0, reg, data, length);
+ err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG, 0, reg, data,
+ length);
if ((err != length) && (err >= 0))
err = -EINVAL;
return err;
@@ -39,8 +39,8 @@ static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
{
int err;
- err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
- 0, reg, data, length);
+ err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG, 0, reg, data,
+ length);
if ((err >= 0) && (err < length))
err = -EINVAL;
return err;
@@ -158,11 +158,11 @@ static int sr9700_get_eeprom_len(struct net_device *dev)
return SR_EEPROM_LEN;
}
-static int sr9700_get_eeprom(struct net_device *net,
+static int sr9700_get_eeprom(struct net_device *netdev,
struct ethtool_eeprom *eeprom, u8 *data)
{
- struct usbnet *dev = netdev_priv(net);
- __le16 *ebuf = (__le16 *)data;
+ struct usbnet *dev = netdev_priv(netdev);
+ __le16 *buf = (__le16 *)data;
int ret = 0;
int i;
@@ -170,9 +170,11 @@ static int sr9700_get_eeprom(struct net_device *net,
if ((eeprom->offset & 0x01) || (eeprom->len & 0x01))
return -EINVAL;
- for (i = 0; i < eeprom->len / 2; i++)
- ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i,
- &ebuf[i]);
+ for (i = 0; i < eeprom->len / 2; i++) {
+ ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, buf + i);
+ if (ret < 0)
+ break;
+ }
return ret;
}
@@ -184,7 +186,7 @@ static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
int rc = 0;
if (phy_id) {
- netdev_dbg(dev->net, "Only internal phy supported\n");
+ netdev_dbg(netdev, "Only internal phy supported\n");
return 0;
}
@@ -202,7 +204,7 @@ static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
else
res = le16_to_cpu(res) & ~BMSR_LSTATUS;
- netdev_dbg(dev->net, "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
+ netdev_dbg(netdev, "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
phy_id, loc, res);
return res;
@@ -215,19 +217,19 @@ static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc,
__le16 res = cpu_to_le16(val);
if (phy_id) {
- netdev_dbg(dev->net, "Only internal phy supported\n");
+ netdev_dbg(netdev, "Only internal phy supported\n");
return;
}
- netdev_dbg(dev->net, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
+ netdev_dbg(netdev, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
phy_id, loc, val);
sr_share_write_word(dev, 1, loc, res);
}
-static u32 sr9700_get_link(struct net_device *net)
+static u32 sr9700_get_link(struct net_device *netdev)
{
- struct usbnet *dev = netdev_priv(net);
+ struct usbnet *dev = netdev_priv(netdev);
u8 value = 0;
int rc = 0;
@@ -239,9 +241,9 @@ static u32 sr9700_get_link(struct net_device *net)
return rc;
}
-static int sr9700_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+static int sr9700_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
{
- struct usbnet *dev = netdev_priv(net);
+ struct usbnet *dev = netdev_priv(netdev);
return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
}
@@ -258,9 +260,9 @@ static const struct ethtool_ops sr9700_ethtool_ops = {
.nway_reset = usbnet_nway_reset,
};
-static void sr9700_set_multicast(struct net_device *net)
+static void sr9700_set_multicast(struct net_device *netdev)
{
- struct usbnet *dev = netdev_priv(net);
+ struct usbnet *dev = netdev_priv(netdev);
/* We use the 20 byte dev->data for our 8 byte filter buffer
* to avoid allocating memory that is tricky to free later
*/
@@ -271,14 +273,15 @@ static void sr9700_set_multicast(struct net_device *net)
memset(hashes, 0x00, SR_MCAST_SIZE);
/* broadcast address */
hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG;
- if (net->flags & IFF_PROMISC) {
+ if (netdev->flags & IFF_PROMISC) {
rx_ctl |= RCR_PRMSC;
- } else if (net->flags & IFF_ALLMULTI ||
- netdev_mc_count(net) > SR_MCAST_MAX) {
+ } else if (netdev->flags & IFF_ALLMULTI ||
+ netdev_mc_count(netdev) > SR_MCAST_MAX) {
rx_ctl |= RCR_RUNT;
- } else if (!netdev_mc_empty(net)) {
+ } else if (!netdev_mc_empty(netdev)) {
struct netdev_hw_addr *ha;
- netdev_for_each_mc_addr(ha, net) {
+
+ netdev_for_each_mc_addr(ha, netdev) {
u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
hashes[crc >> 3] |= 1 << (crc & 0x7);
}
@@ -288,19 +291,19 @@ static void sr9700_set_multicast(struct net_device *net)
sr_write_reg_async(dev, RCR, rx_ctl);
}
-static int sr9700_set_mac_address(struct net_device *net, void *p)
+static int sr9700_set_mac_address(struct net_device *netdev, void *p)
{
- struct usbnet *dev = netdev_priv(net);
+ struct usbnet *dev = netdev_priv(netdev);
struct sockaddr *addr = p;
if (!is_valid_ether_addr(addr->sa_data)) {
- netdev_err(net, "not setting invalid mac address %pM\n",
+ netdev_err(netdev, "not setting invalid mac address %pM\n",
addr->sa_data);
return -EINVAL;
}
- memcpy(net->dev_addr, addr->sa_data, net->addr_len);
- sr_write_async(dev, PAR, 6, dev->net->dev_addr);
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ sr_write_async(dev, PAR, 6, netdev->dev_addr);
return 0;
}
@@ -319,26 +322,31 @@ static const struct net_device_ops sr9700_netdev_ops = {
static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
{
+ struct net_device *netdev;
+ struct mii_if_info *mii;
int ret;
ret = usbnet_get_endpoints(dev, intf);
if (ret)
goto out;
- dev->net->netdev_ops = &sr9700_netdev_ops;
- dev->net->ethtool_ops = &sr9700_ethtool_ops;
- dev->net->hard_header_len += SR_TX_OVERHEAD;
- dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+ netdev = dev->net;
+
+ netdev->netdev_ops = &sr9700_netdev_ops;
+ netdev->ethtool_ops = &sr9700_ethtool_ops;
+ netdev->hard_header_len += SR_TX_OVERHEAD;
+ dev->hard_mtu = netdev->mtu + netdev->hard_header_len;
/* bulkin buffer is preferably not less than 3K */
dev->rx_urb_size = 3072;
- dev->mii.dev = dev->net;
- dev->mii.mdio_read = sr_mdio_read;
- dev->mii.mdio_write = sr_mdio_write;
- dev->mii.phy_id_mask = 0x1f;
- dev->mii.reg_num_mask = 0x1f;
-
- /* reset the sr9700 */
- sr_write_reg(dev, NCR, 1);
+
+ mii = &dev->mii;
+ mii->dev = netdev;
+ mii->mdio_read = sr_mdio_read;
+ mii->mdio_write = sr_mdio_write;
+ mii->phy_id_mask = 0x1f;
+ mii->reg_num_mask = 0x1f;
+
+ sr_write_reg(dev, NCR, NCR_RST);
udelay(20);
/* read MAC
@@ -346,14 +354,14 @@ static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
* EEPROM automatically to PAR. In case there is no EEPROM externally,
* a default MAC address is stored in PAR for making chip work properly.
*/
- if (sr_read(dev, PAR, ETH_ALEN, dev->net->dev_addr) < 0) {
- netdev_err(dev->net, "Error reading MAC address\n");
+ if (sr_read(dev, PAR, ETH_ALEN, netdev->dev_addr) < 0) {
+ netdev_err(netdev, "Error reading MAC address\n");
ret = -ENODEV;
goto out;
}
/* power up and reset phy */
- sr_write_reg(dev, PRR, 1);
+ sr_write_reg(dev, PRR, PRR_PHY_RST);
/* at least 10ms, here 20ms for safe */
mdelay(20);
sr_write_reg(dev, PRR, 0);
@@ -361,13 +369,12 @@ static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
udelay(2 * 1000);
/* receive broadcast packets */
- sr9700_set_multicast(dev->net);
+ sr9700_set_multicast(netdev);
- sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
- sr_mdio_write(dev->net, dev->mii.phy_id,
- (MII_ADVERTISE, ADVERTISE_ALL |
- ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP));
- mii_nway_restart(&dev->mii);
+ sr_mdio_write(netdev, mii->phy_id, MII_BMCR, BMCR_RESET);
+ sr_mdio_write(netdev, mii->phy_id, MII_ADVERTISE, ADVERTISE_ALL |
+ ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+ mii_nway_restart(mii);
out:
return ret;
@@ -415,7 +422,7 @@ static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
if (skb->len == (len + SR_RX_OVERHEAD)) {
skb_pull(skb, 3);
skb->len = len;
- skb->tail = skb->data + len;
+ skb_set_tail_pointer(skb, len);
skb->truesize = len + sizeof(struct sk_buff);
return 2;
}
@@ -427,7 +434,7 @@ static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
sr_skb->len = len;
sr_skb->data = skb->data + 3;
- sr_skb->tail = skb->data + len;
+ skb_set_tail_pointer(sr_skb, len - 3);
sr_skb->truesize = len + sizeof(struct sk_buff);
usbnet_skb_return(dev, sr_skb);
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 net-next] pkt_sched: fq: Fair Queue packet scheduler
From: Eric Dumazet @ 2013-08-29 22:49 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Yuchung Cheng, Neal Cardwell
From: Eric Dumazet <edumazet@google.com>
- Uses perfect flow match (not stochastic hash like SFQ/FQ_codel)
- Uses the new_flow/old_flow separation from FQ_codel
- New flows get an initial credit allowing IW10 without added delay.
- Special FIFO queue for high prio packets (no need for PRIO + FQ)
- Uses a hash table of RB trees to locate the flows at enqueue() time
- Smart on demand gc (at enqueue() time, RB tree lookup evicts old
unused flows)
- Dynamic memory allocations.
- Designed to allow millions of concurrent flows per Qdisc.
- Small memory footprint : ~8K per Qdisc, and 104 bytes per flow.
- Single high resolution timer for throttled flows (if any).
- One RB tree to link throttled flows.
- Ability to have a max rate per flow. We might add a socket option
to add per socket limitation.
Attempts have been made to add TCP pacing in TCP stack, but this
seems to add complex code to an already complex stack.
TCP pacing is welcomed for flows having idle times, as the cwnd
permits TCP stack to queue a possibly large number of packets.
This removes the 'slow start after idle' choice, hitting badly
large BDP flows, and applications delivering chunks of data
as video streams.
Nicely spaced packets :
Here interface is 10Gbit, but flow bottleneck is ~20Mbit
cwin is big, yet FQ avoids the typical bursts generated by TCP
(as in netperf TCP_RR -- -r 100000,100000)
15:01:23.545279 IP A > B: . 78193:81089(2896) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.545394 IP B > A: . ack 81089 win 3668 <nop,nop,timestamp 11597985 1115>
15:01:23.546488 IP A > B: . 81089:83985(2896) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.546565 IP B > A: . ack 83985 win 3668 <nop,nop,timestamp 11597986 1115>
15:01:23.547713 IP A > B: . 83985:86881(2896) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.547778 IP B > A: . ack 86881 win 3668 <nop,nop,timestamp 11597987 1115>
15:01:23.548911 IP A > B: . 86881:89777(2896) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.548949 IP B > A: . ack 89777 win 3668 <nop,nop,timestamp 11597988 1115>
15:01:23.550116 IP A > B: . 89777:92673(2896) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.550182 IP B > A: . ack 92673 win 3668 <nop,nop,timestamp 11597989 1115>
15:01:23.551333 IP A > B: . 92673:95569(2896) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.551406 IP B > A: . ack 95569 win 3668 <nop,nop,timestamp 11597991 1115>
15:01:23.552539 IP A > B: . 95569:98465(2896) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.552576 IP B > A: . ack 98465 win 3668 <nop,nop,timestamp 11597992 1115>
15:01:23.553756 IP A > B: . 98465:99913(1448) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.554138 IP A > B: P 99913:100001(88) ack 65248 win 3125 <nop,nop,timestamp 1115 11597805>
15:01:23.554204 IP B > A: . ack 100001 win 3668 <nop,nop,timestamp 11597993 1115>
15:01:23.554234 IP B > A: . 65248:68144(2896) ack 100001 win 3668 <nop,nop,timestamp 11597993 1115>
15:01:23.555620 IP B > A: . 68144:71040(2896) ack 100001 win 3668 <nop,nop,timestamp 11597993 1115>
15:01:23.557005 IP B > A: . 71040:73936(2896) ack 100001 win 3668 <nop,nop,timestamp 11597993 1115>
15:01:23.558390 IP B > A: . 73936:76832(2896) ack 100001 win 3668 <nop,nop,timestamp 11597993 1115>
15:01:23.559773 IP B > A: . 76832:79728(2896) ack 100001 win 3668 <nop,nop,timestamp 11597993 1115>
15:01:23.561158 IP B > A: . 79728:82624(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.562543 IP B > A: . 82624:85520(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.563928 IP B > A: . 85520:88416(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.565313 IP B > A: . 88416:91312(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.566698 IP B > A: . 91312:94208(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.568083 IP B > A: . 94208:97104(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.569467 IP B > A: . 97104:100000(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.570852 IP B > A: . 100000:102896(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.572237 IP B > A: . 102896:105792(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.573639 IP B > A: . 105792:108688(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.575024 IP B > A: . 108688:111584(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.576408 IP B > A: . 111584:114480(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
15:01:23.577793 IP B > A: . 114480:117376(2896) ack 100001 win 3668 <nop,nop,timestamp 11597994 1115>
TCP timestamps show that most packets from B were queued in the same ms
timeframe (TSval 1159799{3,4}), but FQ managed to send them right
in time to avoid a big burst.
In slow start or steady state, very few packets are throttled [1]
FQ gets a bunch of tunables as :
limit : max number of packets on whole Qdisc (default 10000)
flow_limit : max number of packets per flow (default 100)
quantum : the credit per RR round (default is 2 MTU)
initial_quantum : initial credit for new flows (default is 10 MTU)
maxrate : max per flow rate (default : unlimited)
buckets : number of RB trees (default : 1024) in hash table.
(consumes 8 bytes per bucket)
[no]pacing : disable/enable pacing (default is enable)
All of them can be changed on a live qdisc.
$ tc qd add dev eth0 root fq help
Usage: ... fq [ limit PACKETS ] [ flow_limit PACKETS ]
[ quantum BYTES ] [ initial_quantum BYTES ]
[ maxrate RATE ] [ buckets NUMBER ]
[ [no]pacing ]
$ tc -s -d qd
qdisc fq 8002: dev eth0 root refcnt 32 limit 10000p flow_limit 100p buckets 256 quantum 3028 initial_quantum 15140
Sent 216532416 bytes 148395 pkt (dropped 0, overlimits 0 requeues 14)
backlog 0b 0p requeues 14
511 flows, 511 inactive, 0 throttled
110 gc, 0 highprio, 0 retrans, 1143 throttled, 0 flows_plimit
[1] Except if initial srtt is overestimated, as if using
cached srtt in tcp metrics. We'll provide a fix for this issue.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Yuchung Cheng <ycheng@google.com>
Cc: Neal Cardwell <ncardwell@google.com>
---
v2: added initial_quantum support
include/uapi/linux/pkt_sched.h | 41 +
net/sched/Kconfig | 14
net/sched/Makefile | 1
net/sched/sch_fq.c | 792 +++++++++++++++++++++++++++++++
4 files changed, 848 insertions(+)
diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h
index 09d62b92..9b82913 100644
--- a/include/uapi/linux/pkt_sched.h
+++ b/include/uapi/linux/pkt_sched.h
@@ -744,4 +744,45 @@ struct tc_fq_codel_xstats {
};
};
+/* FQ */
+
+enum {
+ TCA_FQ_UNSPEC,
+
+ TCA_FQ_PLIMIT, /* limit of total number of packets in queue */
+
+ TCA_FQ_FLOW_PLIMIT, /* limit of packets per flow */
+
+ TCA_FQ_QUANTUM, /* RR quantum */
+
+ TCA_FQ_INITIAL_QUANTUM, /* RR quantum for new flow */
+
+ TCA_FQ_RATE_ENABLE, /* enable/disable rate limiting */
+
+ TCA_FQ_FLOW_DEFAULT_RATE,/* for sockets with unspecified sk_rate,
+ * use the following rate
+ */
+
+ TCA_FQ_FLOW_MAX_RATE, /* per flow max rate */
+
+ TCA_FQ_BUCKETS_LOG, /* log2(number of buckets) */
+ __TCA_FQ_MAX
+};
+
+#define TCA_FQ_MAX (__TCA_FQ_MAX - 1)
+
+struct tc_fq_qd_stats {
+ __u64 gc_flows;
+ __u64 highprio_packets;
+ __u64 tcp_retrans;
+ __u64 throttled;
+ __u64 flows_plimit;
+ __u64 pkts_too_long;
+ __u64 allocation_errors;
+ __s64 time_next_delayed_flow;
+ __u32 flows;
+ __u32 inactive_flows;
+ __u32 throttled_flows;
+ __u32 pad;
+};
#endif
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 235e01a..c03a32a 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -272,6 +272,20 @@ config NET_SCH_FQ_CODEL
If unsure, say N.
+config NET_SCH_FQ
+ tristate "Fair Queue"
+ help
+ Say Y here if you want to use the FQ packet scheduling algorithm.
+
+ FQ does flow separation, and is able to respect pacing requirements
+ set by TCP stack into sk->sk_pacing_rate (for localy generated
+ traffic)
+
+ To compile this driver as a module, choose M here: the module
+ will be called sch_fq.
+
+ If unsure, say N.
+
config NET_SCH_INGRESS
tristate "Ingress Qdisc"
depends on NET_CLS_ACT
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 978cbf0..e5f9abe 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_NET_SCH_CHOKE) += sch_choke.o
obj-$(CONFIG_NET_SCH_QFQ) += sch_qfq.o
obj-$(CONFIG_NET_SCH_CODEL) += sch_codel.o
obj-$(CONFIG_NET_SCH_FQ_CODEL) += sch_fq_codel.o
+obj-$(CONFIG_NET_SCH_FQ) += sch_fq.o
obj-$(CONFIG_NET_CLS_U32) += cls_u32.o
obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c
new file mode 100644
index 0000000..d46d0ec
--- /dev/null
+++ b/net/sched/sch_fq.c
@@ -0,0 +1,792 @@
+/*
+ * net/sched/sch_fq.c Fair Queue Packet Scheduler (per flow pacing)
+ *
+ * Copyright (C) 2013 Eric Dumazet <edumazet@google.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Meant to be mostly used for localy generated traffic :
+ * Fast classification depends on skb->sk being set before reaching us.
+ * If not, (router workload), we use rxhash as fallback, with 32 bits wide hash.
+ * All packets belonging to a socket are considered as a 'flow'.
+ *
+ * Flows are dynamically allocated and stored in a hash table of RB trees
+ * They are also part of one Round Robin 'queues' (new or old flows)
+ *
+ * Burst avoidance (aka pacing) capability :
+ *
+ * Transport (eg TCP) can set in sk->sk_pacing_rate a rate, enqueue a
+ * bunch of packets, and this packet scheduler adds delay between
+ * packets to respect rate limitation.
+ *
+ * enqueue() :
+ * - lookup one RB tree (out of 1024 or more) to find the flow.
+ * If non existent flow, create it, add it to the tree.
+ * Add skb to the per flow list of skb (fifo).
+ * - Use a special fifo for high prio packets
+ *
+ * dequeue() : serves flows in Round Robin
+ * Note : When a flow becomes empty, we do not immediately remove it from
+ * rb trees, for performance reasons (its expected to send additional packets,
+ * or SLAB cache will reuse socket for another flow)
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/rbtree.h>
+#include <linux/hash.h>
+#include <net/netlink.h>
+#include <net/pkt_sched.h>
+#include <net/sock.h>
+#include <net/tcp_states.h>
+
+/*
+ * Per flow structure, dynamically allocated
+ */
+struct fq_flow {
+ struct sk_buff *head; /* list of skbs for this flow : first skb */
+ union {
+ struct sk_buff *tail; /* last skb in the list */
+ unsigned long age; /* jiffies when flow was emptied, for gc */
+ };
+ struct rb_node fq_node; /* anchor in fq_root[] trees */
+ struct sock *sk;
+ int qlen; /* number of packets in flow queue */
+ int credit;
+ u32 socket_hash; /* sk_hash */
+ struct fq_flow *next; /* next pointer in RR lists, or &detached */
+
+ struct rb_node rate_node; /* anchor in q->delayed tree */
+ u64 time_next_packet;
+};
+
+struct fq_flow_head {
+ struct fq_flow *first;
+ struct fq_flow *last;
+};
+
+struct fq_sched_data {
+ struct fq_flow_head new_flows;
+
+ struct fq_flow_head old_flows;
+
+ struct rb_root delayed; /* for rate limited flows */
+ u64 time_next_delayed_flow;
+
+ struct fq_flow internal; /* for non classified or high prio packets */
+ u32 quantum;
+ u32 initial_quantum;
+ u32 flow_default_rate;/* rate per flow : bytes per second */
+ u32 flow_max_rate; /* optional max rate per flow */
+ u32 flow_plimit; /* max packets per flow */
+ struct rb_root *fq_root;
+ u8 rate_enable;
+ u8 fq_trees_log;
+
+ u32 flows;
+ u32 inactive_flows;
+ u32 throttled_flows;
+
+ u64 stat_gc_flows;
+ u64 stat_internal_packets;
+ u64 stat_tcp_retrans;
+ u64 stat_throttled;
+ u64 stat_flows_plimit;
+ u64 stat_pkts_too_long;
+ u64 stat_allocation_errors;
+ struct qdisc_watchdog watchdog;
+};
+
+/* special value to mark a detached flow (not on old/new list) */
+static struct fq_flow detached, throttled;
+
+static void fq_flow_set_detached(struct fq_flow *f)
+{
+ f->next = &detached;
+}
+
+static bool fq_flow_is_detached(const struct fq_flow *f)
+{
+ return f->next == &detached;
+}
+
+static void fq_flow_set_throttled(struct fq_sched_data *q, struct fq_flow *f)
+{
+ struct rb_node **p = &q->delayed.rb_node, *parent = NULL;
+
+ while (*p) {
+ struct fq_flow *aux;
+
+ parent = *p;
+ aux = container_of(parent, struct fq_flow, rate_node);
+ if (f->time_next_packet >= aux->time_next_packet)
+ p = &parent->rb_right;
+ else
+ p = &parent->rb_left;
+ }
+ rb_link_node(&f->rate_node, parent, p);
+ rb_insert_color(&f->rate_node, &q->delayed);
+ q->throttled_flows++;
+ q->stat_throttled++;
+
+ f->next = &throttled;
+ if (q->time_next_delayed_flow > f->time_next_packet)
+ q->time_next_delayed_flow = f->time_next_packet;
+}
+
+
+static struct kmem_cache *fq_flow_cachep __read_mostly;
+
+static void fq_flow_add_tail(struct fq_flow_head *head, struct fq_flow *flow)
+{
+ if (head->first)
+ head->last->next = flow;
+ else
+ head->first = flow;
+ head->last = flow;
+ flow->next = NULL;
+}
+
+/* limit number of collected flows per round */
+#define FQ_GC_MAX 8
+#define FQ_GC_AGE (3*HZ)
+
+static bool fq_gc_candidate(const struct fq_flow *f)
+{
+ return fq_flow_is_detached(f) &&
+ time_after(jiffies, f->age + FQ_GC_AGE);
+}
+
+static void fq_gc(struct fq_sched_data *q,
+ struct rb_root *root,
+ struct sock *sk)
+{
+ struct fq_flow *f, *tofree[FQ_GC_MAX];
+ struct rb_node **p, *parent;
+ int fcnt = 0;
+
+ p = &root->rb_node;
+ parent = NULL;
+ while (*p) {
+ parent = *p;
+
+ f = container_of(parent, struct fq_flow, fq_node);
+ if (f->sk == sk)
+ break;
+
+ if (fq_gc_candidate(f)) {
+ tofree[fcnt++] = f;
+ if (fcnt == FQ_GC_MAX)
+ break;
+ }
+
+ if (f->sk > sk)
+ p = &parent->rb_right;
+ else
+ p = &parent->rb_left;
+ }
+
+ q->flows -= fcnt;
+ q->inactive_flows -= fcnt;
+ q->stat_gc_flows += fcnt;
+ while (fcnt) {
+ struct fq_flow *f = tofree[--fcnt];
+
+ rb_erase(&f->fq_node, root);
+ kmem_cache_free(fq_flow_cachep, f);
+ }
+}
+
+static const u8 prio2band[TC_PRIO_MAX + 1] = {
+ 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q)
+{
+ struct rb_node **p, *parent;
+ struct sock *sk = skb->sk;
+ struct rb_root *root;
+ struct fq_flow *f;
+ int band;
+
+ /* warning: no starvation prevention... */
+ band = prio2band[skb->priority & TC_PRIO_MAX];
+ if (unlikely(band == 0))
+ return &q->internal;
+
+ if (unlikely(!sk)) {
+ /* By forcing low order bit to 1, we make sure to not
+ * collide with a local flow (socket pointers are word aligned)
+ */
+ sk = (struct sock *)(skb_get_rxhash(skb) | 1L);
+ }
+
+ root = &q->fq_root[hash_32((u32)(long)sk, q->fq_trees_log)];
+
+ if (q->flows >= (2U << q->fq_trees_log) &&
+ q->inactive_flows > q->flows/2)
+ fq_gc(q, root, sk);
+
+ p = &root->rb_node;
+ parent = NULL;
+ while (*p) {
+ parent = *p;
+
+ f = container_of(parent, struct fq_flow, fq_node);
+ if (f->sk == sk) {
+ /* socket might have been reallocated, so check
+ * if its sk_hash is the same.
+ * It not, we need to refill credit with
+ * initial quantum
+ */
+ if (unlikely(skb->sk &&
+ f->socket_hash != sk->sk_hash)) {
+ f->credit = q->initial_quantum;
+ f->socket_hash = sk->sk_hash;
+ }
+ return f;
+ }
+ if (f->sk > sk)
+ p = &parent->rb_right;
+ else
+ p = &parent->rb_left;
+ }
+
+ f = kmem_cache_zalloc(fq_flow_cachep, GFP_ATOMIC | __GFP_NOWARN);
+ if (unlikely(!f)) {
+ q->stat_allocation_errors++;
+ return &q->internal;
+ }
+ fq_flow_set_detached(f);
+ f->sk = sk;
+ if (skb->sk)
+ f->socket_hash = sk->sk_hash;
+ f->credit = q->initial_quantum;
+
+ rb_link_node(&f->fq_node, parent, p);
+ rb_insert_color(&f->fq_node, root);
+
+ q->flows++;
+ q->inactive_flows++;
+ return f;
+}
+
+
+/* remove one skb from head of flow queue */
+static struct sk_buff *fq_dequeue_head(struct fq_flow *flow)
+{
+ struct sk_buff *skb = flow->head;
+
+ if (skb) {
+ flow->head = skb->next;
+ skb->next = NULL;
+ flow->qlen--;
+ }
+ return skb;
+}
+
+/* We might add in the future detection of retransmits
+ * For the time being, just return false
+ */
+static bool skb_is_retransmit(struct sk_buff *skb)
+{
+ return false;
+}
+
+/* add skb to flow queue
+ * flow queue is a linked list, kind of FIFO, except for TCP retransmits
+ * We special case tcp retransmits to be transmitted before other packets.
+ * We rely on fact that TCP retransmits are unlikely, so we do not waste
+ * a separate queue or a pointer.
+ * head-> [retrans pkt 1]
+ * [retrans pkt 2]
+ * [ normal pkt 1]
+ * [ normal pkt 2]
+ * [ normal pkt 3]
+ * tail-> [ normal pkt 4]
+ */
+static void flow_queue_add(struct fq_flow *flow, struct sk_buff *skb)
+{
+ struct sk_buff *prev, *head = flow->head;
+
+ skb->next = NULL;
+ if (!head) {
+ flow->head = skb;
+ flow->tail = skb;
+ return;
+ }
+ if (likely(!skb_is_retransmit(skb))) {
+ flow->tail->next = skb;
+ flow->tail = skb;
+ return;
+ }
+
+ /* This skb is a tcp retransmit,
+ * find the last retrans packet in the queue
+ */
+ prev = NULL;
+ while (skb_is_retransmit(head)) {
+ prev = head;
+ head = head->next;
+ if (!head)
+ break;
+ }
+ if (!prev) { /* no rtx packet in queue, become the new head */
+ skb->next = flow->head;
+ flow->head = skb;
+ } else {
+ if (prev == flow->tail)
+ flow->tail = skb;
+ else
+ skb->next = prev->next;
+ prev->next = skb;
+ }
+}
+
+static int fq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+ struct fq_sched_data *q = qdisc_priv(sch);
+ struct fq_flow *f;
+
+ if (unlikely(sch->q.qlen >= sch->limit))
+ return qdisc_drop(skb, sch);
+
+ f = fq_classify(skb, q);
+ if (unlikely(f->qlen >= q->flow_plimit && f != &q->internal)) {
+ q->stat_flows_plimit++;
+ return qdisc_drop(skb, sch);
+ }
+
+ f->qlen++;
+ flow_queue_add(f, skb);
+ if (skb_is_retransmit(skb))
+ q->stat_tcp_retrans++;
+ sch->qstats.backlog += qdisc_pkt_len(skb);
+ if (fq_flow_is_detached(f)) {
+ fq_flow_add_tail(&q->new_flows, f);
+ if (q->quantum > f->credit)
+ f->credit = q->quantum;
+ q->inactive_flows--;
+ qdisc_unthrottled(sch);
+ }
+ if (unlikely(f == &q->internal)) {
+ q->stat_internal_packets++;
+ qdisc_unthrottled(sch);
+ }
+ sch->q.qlen++;
+
+ return NET_XMIT_SUCCESS;
+}
+
+static void fq_check_throttled(struct fq_sched_data *q, u64 now)
+{
+ struct rb_node *p;
+
+ if (q->time_next_delayed_flow > now)
+ return;
+
+ q->time_next_delayed_flow = ~0ULL;
+ while ((p = rb_first(&q->delayed)) != NULL) {
+ struct fq_flow *f = container_of(p, struct fq_flow, rate_node);
+
+ if (f->time_next_packet > now) {
+ q->time_next_delayed_flow = f->time_next_packet;
+ break;
+ }
+ rb_erase(p, &q->delayed);
+ q->throttled_flows--;
+ fq_flow_add_tail(&q->old_flows, f);
+ }
+}
+
+static struct sk_buff *fq_dequeue(struct Qdisc *sch)
+{
+ struct fq_sched_data *q = qdisc_priv(sch);
+ u64 now = ktime_to_ns(ktime_get());
+ struct fq_flow_head *head;
+ struct sk_buff *skb;
+ struct fq_flow *f;
+
+ skb = fq_dequeue_head(&q->internal);
+ if (skb)
+ goto out;
+ fq_check_throttled(q, now);
+begin:
+ head = &q->new_flows;
+ if (!head->first) {
+ head = &q->old_flows;
+ if (!head->first) {
+ if (q->time_next_delayed_flow != ~0ULL)
+ qdisc_watchdog_schedule_ns(&q->watchdog,
+ q->time_next_delayed_flow);
+ return NULL;
+ }
+ }
+ f = head->first;
+
+ if (f->credit <= 0) {
+ f->credit += q->quantum;
+ head->first = f->next;
+ fq_flow_add_tail(&q->old_flows, f);
+ goto begin;
+ }
+
+ if (unlikely(f->head && now < f->time_next_packet)) {
+ head->first = f->next;
+ fq_flow_set_throttled(q, f);
+ goto begin;
+ }
+
+ skb = fq_dequeue_head(f);
+ if (!skb) {
+ head->first = f->next;
+ /* force a pass through old_flows to prevent starvation */
+ if ((head == &q->new_flows) && q->old_flows.first) {
+ fq_flow_add_tail(&q->old_flows, f);
+ } else {
+ fq_flow_set_detached(f);
+ f->age = jiffies;
+ q->inactive_flows++;
+ }
+ goto begin;
+ }
+ f->time_next_packet = now;
+ f->credit -= qdisc_pkt_len(skb);
+
+ if (f->credit <= 0 &&
+ q->rate_enable &&
+ skb->sk && skb->sk->sk_state != TCP_TIME_WAIT) {
+ u32 rate = skb->sk->sk_pacing_rate ?: q->flow_default_rate;
+
+ rate = min(rate, q->flow_max_rate);
+ if (rate) {
+ u64 len = (u64)qdisc_pkt_len(skb) * NSEC_PER_SEC;
+
+ do_div(len, rate);
+ /* Since socket rate can change later,
+ * clamp the delay to 125 ms.
+ * TODO: maybe segment the too big skb, as in commit
+ * e43ac79a4bc ("sch_tbf: segment too big GSO packets")
+ */
+ if (unlikely(len > 125 * NSEC_PER_MSEC)) {
+ len = 125 * NSEC_PER_MSEC;
+ q->stat_pkts_too_long++;
+ }
+
+ f->time_next_packet = now + len;
+ }
+ }
+out:
+ prefetch(&skb->end);
+ sch->qstats.backlog -= qdisc_pkt_len(skb);
+ qdisc_bstats_update(sch, skb);
+ sch->q.qlen--;
+ qdisc_unthrottled(sch);
+ return skb;
+}
+
+static void fq_reset(struct Qdisc *sch)
+{
+ struct sk_buff *skb;
+
+ while ((skb = fq_dequeue(sch)) != NULL)
+ kfree_skb(skb);
+}
+
+static void fq_rehash(struct fq_sched_data *q,
+ struct rb_root *old_array, u32 old_log,
+ struct rb_root *new_array, u32 new_log)
+{
+ struct rb_node *op, **np, *parent;
+ struct rb_root *oroot, *nroot;
+ struct fq_flow *of, *nf;
+ int fcnt = 0;
+ u32 idx;
+
+ for (idx = 0; idx < (1U << old_log); idx++) {
+ oroot = &old_array[idx];
+ while ((op = rb_first(oroot)) != NULL) {
+ rb_erase(op, oroot);
+ of = container_of(op, struct fq_flow, fq_node);
+ if (fq_gc_candidate(of)) {
+ fcnt++;
+ kmem_cache_free(fq_flow_cachep, of);
+ continue;
+ }
+ nroot = &new_array[hash_32((u32)(long)of->sk, new_log)];
+
+ np = &nroot->rb_node;
+ parent = NULL;
+ while (*np) {
+ parent = *np;
+
+ nf = container_of(parent, struct fq_flow, fq_node);
+ BUG_ON(nf->sk == of->sk);
+
+ if (nf->sk > of->sk)
+ np = &parent->rb_right;
+ else
+ np = &parent->rb_left;
+ }
+
+ rb_link_node(&of->fq_node, parent, np);
+ rb_insert_color(&of->fq_node, nroot);
+ }
+ }
+ q->flows -= fcnt;
+ q->inactive_flows -= fcnt;
+ q->stat_gc_flows += fcnt;
+}
+
+static int fq_resize(struct fq_sched_data *q, u32 log)
+{
+ struct rb_root *array;
+ u32 idx;
+
+ if (q->fq_root && log == q->fq_trees_log)
+ return 0;
+
+ array = kmalloc(sizeof(struct rb_root) << log, GFP_KERNEL);
+ if (!array)
+ return -ENOMEM;
+
+ for (idx = 0; idx < (1U << log); idx++)
+ array[idx] = RB_ROOT;
+
+ if (q->fq_root) {
+ fq_rehash(q, q->fq_root, q->fq_trees_log, array, log);
+ kfree(q->fq_root);
+ }
+ q->fq_root = array;
+ q->fq_trees_log = log;
+
+ return 0;
+}
+
+static const struct nla_policy fq_policy[TCA_FQ_MAX + 1] = {
+ [TCA_FQ_PLIMIT] = { .type = NLA_U32 },
+ [TCA_FQ_FLOW_PLIMIT] = { .type = NLA_U32 },
+ [TCA_FQ_QUANTUM] = { .type = NLA_U32 },
+ [TCA_FQ_INITIAL_QUANTUM] = { .type = NLA_U32 },
+ [TCA_FQ_RATE_ENABLE] = { .type = NLA_U32 },
+ [TCA_FQ_FLOW_DEFAULT_RATE] = { .type = NLA_U32 },
+ [TCA_FQ_FLOW_MAX_RATE] = { .type = NLA_U32 },
+ [TCA_FQ_BUCKETS_LOG] = { .type = NLA_U32 },
+};
+
+static int fq_change(struct Qdisc *sch, struct nlattr *opt)
+{
+ struct fq_sched_data *q = qdisc_priv(sch);
+ struct nlattr *tb[TCA_FQ_MAX + 1];
+ int err, drop_count = 0;
+ u32 fq_log;
+
+ if (!opt)
+ return -EINVAL;
+
+ err = nla_parse_nested(tb, TCA_FQ_MAX, opt, fq_policy);
+ if (err < 0)
+ return err;
+
+ sch_tree_lock(sch);
+
+ fq_log = q->fq_trees_log;
+
+ if (tb[TCA_FQ_BUCKETS_LOG]) {
+ u32 nval = nla_get_u32(tb[TCA_FQ_BUCKETS_LOG]);
+
+ if (nval >= 1 && nval <= ilog2(256*1024))
+ fq_log = nval;
+ else
+ err = -EINVAL;
+ }
+ if (tb[TCA_FQ_PLIMIT])
+ sch->limit = nla_get_u32(tb[TCA_FQ_PLIMIT]);
+
+ if (tb[TCA_FQ_FLOW_PLIMIT])
+ q->flow_plimit = nla_get_u32(tb[TCA_FQ_FLOW_PLIMIT]);
+
+ if (tb[TCA_FQ_QUANTUM])
+ q->quantum = nla_get_u32(tb[TCA_FQ_QUANTUM]);
+
+ if (tb[TCA_FQ_INITIAL_QUANTUM])
+ q->quantum = nla_get_u32(tb[TCA_FQ_INITIAL_QUANTUM]);
+
+ if (tb[TCA_FQ_FLOW_DEFAULT_RATE])
+ q->flow_default_rate = nla_get_u32(tb[TCA_FQ_FLOW_DEFAULT_RATE]);
+
+ if (tb[TCA_FQ_FLOW_MAX_RATE])
+ q->flow_max_rate = nla_get_u32(tb[TCA_FQ_FLOW_MAX_RATE]);
+
+ if (tb[TCA_FQ_RATE_ENABLE]) {
+ u32 enable = nla_get_u32(tb[TCA_FQ_RATE_ENABLE]);
+
+ if (enable <= 1)
+ q->rate_enable = enable;
+ else
+ err = -EINVAL;
+ }
+
+ if (!err)
+ err = fq_resize(q, fq_log);
+
+ while (sch->q.qlen > sch->limit) {
+ struct sk_buff *skb = fq_dequeue(sch);
+
+ kfree_skb(skb);
+ drop_count++;
+ }
+ qdisc_tree_decrease_qlen(sch, drop_count);
+
+ sch_tree_unlock(sch);
+ return err;
+}
+
+static void fq_destroy(struct Qdisc *sch)
+{
+ struct fq_sched_data *q = qdisc_priv(sch);
+ struct rb_root *root;
+ struct rb_node *p;
+ unsigned int idx;
+
+ if (q->fq_root) {
+ for (idx = 0; idx < (1U << q->fq_trees_log); idx++) {
+ root = &q->fq_root[idx];
+ while ((p = rb_first(root)) != NULL) {
+ rb_erase(p, root);
+ kmem_cache_free(fq_flow_cachep,
+ container_of(p, struct fq_flow, fq_node));
+ }
+ }
+ kfree(q->fq_root);
+ }
+ qdisc_watchdog_cancel(&q->watchdog);
+}
+
+static int fq_init(struct Qdisc *sch, struct nlattr *opt)
+{
+ struct fq_sched_data *q = qdisc_priv(sch);
+ int err;
+
+ sch->limit = 10000;
+ q->flow_plimit = 100;
+ q->quantum = 2 * psched_mtu(qdisc_dev(sch));
+ q->initial_quantum = 10 * psched_mtu(qdisc_dev(sch));
+ q->flow_default_rate = 0;
+ q->flow_max_rate = ~0U;
+ q->rate_enable = 1;
+ q->new_flows.first = NULL;
+ q->old_flows.first = NULL;
+ q->delayed = RB_ROOT;
+ q->fq_root = NULL;
+ q->fq_trees_log = ilog2(1024);
+ qdisc_watchdog_init(&q->watchdog, sch);
+
+ if (opt)
+ err = fq_change(sch, opt);
+ else
+ err = fq_resize(q, q->fq_trees_log);
+
+ return err;
+}
+
+static int fq_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+ struct fq_sched_data *q = qdisc_priv(sch);
+ struct nlattr *opts;
+
+ opts = nla_nest_start(skb, TCA_OPTIONS);
+ if (opts == NULL)
+ goto nla_put_failure;
+
+ if (nla_put_u32(skb, TCA_FQ_PLIMIT, sch->limit) ||
+ nla_put_u32(skb, TCA_FQ_FLOW_PLIMIT, q->flow_plimit) ||
+ nla_put_u32(skb, TCA_FQ_QUANTUM, q->quantum) ||
+ nla_put_u32(skb, TCA_FQ_INITIAL_QUANTUM, q->initial_quantum) ||
+ nla_put_u32(skb, TCA_FQ_RATE_ENABLE, q->rate_enable) ||
+ nla_put_u32(skb, TCA_FQ_FLOW_DEFAULT_RATE, q->flow_default_rate) ||
+ nla_put_u32(skb, TCA_FQ_FLOW_MAX_RATE, q->flow_max_rate) ||
+ nla_put_u32(skb, TCA_FQ_BUCKETS_LOG, q->fq_trees_log))
+ goto nla_put_failure;
+
+ nla_nest_end(skb, opts);
+ return skb->len;
+
+nla_put_failure:
+ return -1;
+}
+
+static int fq_dump_stats(struct Qdisc *sch, struct gnet_dump *d)
+{
+ struct fq_sched_data *q = qdisc_priv(sch);
+ u64 now = ktime_to_ns(ktime_get());
+ struct tc_fq_qd_stats st = {
+ .gc_flows = q->stat_gc_flows,
+ .highprio_packets = q->stat_internal_packets,
+ .tcp_retrans = q->stat_tcp_retrans,
+ .throttled = q->stat_throttled,
+ .flows_plimit = q->stat_flows_plimit,
+ .pkts_too_long = q->stat_pkts_too_long,
+ .allocation_errors = q->stat_allocation_errors,
+ .flows = q->flows,
+ .inactive_flows = q->inactive_flows,
+ .throttled_flows = q->throttled_flows,
+ .time_next_delayed_flow = q->time_next_delayed_flow - now,
+ };
+
+ return gnet_stats_copy_app(d, &st, sizeof(st));
+}
+
+static struct Qdisc_ops fq_qdisc_ops __read_mostly = {
+ .id = "fq",
+ .priv_size = sizeof(struct fq_sched_data),
+
+ .enqueue = fq_enqueue,
+ .dequeue = fq_dequeue,
+ .peek = qdisc_peek_dequeued,
+ .init = fq_init,
+ .reset = fq_reset,
+ .destroy = fq_destroy,
+ .change = fq_change,
+ .dump = fq_dump,
+ .dump_stats = fq_dump_stats,
+ .owner = THIS_MODULE,
+};
+
+static int __init fq_module_init(void)
+{
+ int ret;
+
+ fq_flow_cachep = kmem_cache_create("fq_flow_cache",
+ sizeof(struct fq_flow),
+ 0, 0, NULL);
+ if (!fq_flow_cachep)
+ return -ENOMEM;
+
+ ret = register_qdisc(&fq_qdisc_ops);
+ if (ret)
+ kmem_cache_destroy(fq_flow_cachep);
+ return ret;
+}
+
+static void __exit fq_module_exit(void)
+{
+ unregister_qdisc(&fq_qdisc_ops);
+ kmem_cache_destroy(fq_flow_cachep);
+}
+
+module_init(fq_module_init)
+module_exit(fq_module_exit)
+MODULE_AUTHOR("Eric Dumazet");
+MODULE_LICENSE("GPL");
^ permalink raw reply related
* Re: [PATCH net-next] net: ipv6: mldv1/v2: fix switchback timeout to rfc3810, 9.12.
From: David Miller @ 2013-08-29 22:14 UTC (permalink / raw)
To: dborkman; +Cc: netdev, dlstevens, hannes
In-Reply-To: <521FBC29.2090700@redhat.com>
From: Daniel Borkmann <dborkman@redhat.com>
Date: Thu, 29 Aug 2013 23:24:57 +0200
> Dave, please hold on with this one. This is already better, but
> it still needs to be improved slightly. Will send an update tomorrow
> or at latest at the beginning of next week.
Ok.
^ permalink raw reply
* Re: [-next] openvswitch BUILD_BUG_ON failed
From: David Miller @ 2013-08-29 22:10 UTC (permalink / raw)
To: jesse; +Cc: geert, azhou, dev, netdev, linux-kernel, linux-next
In-Reply-To: <CAEP_g=-XvRiHPzSAp2rgC9Hxdd+pGEHvSTEJ1A1SkWnk1-6xZA@mail.gmail.com>
From: Jesse Gross <jesse@nicira.com>
Date: Thu, 29 Aug 2013 14:42:22 -0700
> On Thu, Aug 29, 2013 at 2:21 PM, Geert Uytterhoeven
> <geert@linux-m68k.org> wrote:
>> However, I have some doubts about other alignment "enforcements":
>>
>> "__aligned(__alignof__(long))" makes the whole struct aligned to the
>> alignment rule for "long":
>> 1. This is only 2 bytes on m68k, i.e. != sizeof(long).
>> 2. This is 4 bytes on many 32-bit platforms, which may be less than the
>> default alignment for "__be64" (cfr. some members of struct
>> ovs_key_ipv4_tunnel), so this may make those 64-bit members unaligned.
>
> Do any of those 32-bit architectures actually care about alignment of
> 64 bit values? On 32-bit x86, a long is 32 bits but the alignment
> requirement of __be64 is also 32 bit.
All except x86-32 do, it is in fact the odd man out with respect to this
issue.
^ permalink raw reply
* [PATCH net] net: bridge: convert MLDv2 Query MRC into msecs_to_jiffies for max_delay
From: Daniel Borkmann @ 2013-08-29 21:55 UTC (permalink / raw)
To: davem; +Cc: netdev, Linus Lüssing, Hannes Frederic Sowa
While looking into MLDv1/v2 code, I noticed that bridging code does
not convert it's max delay into jiffies for MLDv2 messages as we do
in core IPv6' multicast code.
RFC3810, 5.1.3. Maximum Response Code says:
The Maximum Response Code field specifies the maximum time allowed
before sending a responding Report. The actual time allowed, called
the Maximum Response Delay, is represented in units of milliseconds,
and is derived from the Maximum Response Code as follows: [...]
As we update timers that work with jiffies, we need to convert it.
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Cc: Linus Lüssing <linus.luessing@web.de>
Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
---
net/bridge/br_multicast.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 08e576a..08d2921 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1203,7 +1203,8 @@ static int br_ip6_multicast_query(struct net_bridge *br,
mld2q = (struct mld2_query *)icmp6_hdr(skb);
if (!mld2q->mld2q_nsrcs)
group = &mld2q->mld2q_mca;
- max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(ntohs(mld2q->mld2q_mrc)) : 1;
+
+ max_delay = max(msecs_to_jiffies(MLDV2_MRC(ntohs(mld2q->mld2q_mrc))), 1UL);
}
br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr),
--
1.7.11.7
^ permalink raw reply related
* Re: [-next] openvswitch BUILD_BUG_ON failed
From: Jesse Gross @ 2013-08-29 21:42 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Andy Zhou, dev@openvswitch.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org, Linux-Next
In-Reply-To: <CAMuHMdVG9FmZNayrf7HMz4kC4X5QELeXUFjjzpAM80ND_QOm8A@mail.gmail.com>
On Thu, Aug 29, 2013 at 2:21 PM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> However, I have some doubts about other alignment "enforcements":
>
> "__aligned(__alignof__(long))" makes the whole struct aligned to the
> alignment rule for "long":
> 1. This is only 2 bytes on m68k, i.e. != sizeof(long).
> 2. This is 4 bytes on many 32-bit platforms, which may be less than the
> default alignment for "__be64" (cfr. some members of struct
> ovs_key_ipv4_tunnel), so this may make those 64-bit members unaligned.
Do any of those 32-bit architectures actually care about alignment of
64 bit values? On 32-bit x86, a long is 32 bits but the alignment
requirement of __be64 is also 32 bit.
^ permalink raw reply
* Re: [-next] openvswitch BUILD_BUG_ON failed
From: Andy Zhou @ 2013-08-29 21:40 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: dev-yBygre7rU0TnMu66kgdUjQ@public.gmane.org,
netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Linux-Next,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CAMuHMdVG9FmZNayrf7HMz4kC4X5QELeXUFjjzpAM80ND_QOm8A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
[-- Attachment #1.1: Type: text/plain, Size: 3350 bytes --]
Yes, fengguan.Wu has reported the issue. Just sent out a patch for review.
You are welcome to review it.
http://openvswitch.org/pipermail/dev/2013-August/031247.html
On Thu, Aug 29, 2013 at 2:21 PM, Geert Uytterhoeven <geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org>wrote:
> On m68k, where the alignment of 32-bit words is 2 bytes:
>
> net/openvswitch/flow.c:1984:2: error: call to
> '__compiletime_assert_1984' declared with attribute error:
> BUILD_BUG_ON failed: sizeof(struct sw_flow_key) % sizeof(long)
>
> (http://kisskb.ellerman.id.au/kisskb/buildresult/9422860/)
>
> This was introduced by commit 5828cd9a68873df1340b420371c02c47647878fb
> Author: Andy Zhou <azhou-l0M0P4e3n4LQT0dZR+AlfA@public.gmane.org>
> Date: Tue Aug 27 13:02:21 2013 -0700
>
> openvswitch: optimize flow compare and mask functions
>
> Make sure the sw_flow_key structure and valid mask boundaries are
> always
> machine word aligned. Optimize the flow compare and mask operations
> using machine word size operations. This patch improves throughput on
> average by 15% when CPU is the bottleneck of forwarding packets.
>
> This patch is inspired by ideas and code from a patch submitted by
> Peter
> Klausler titled "replace memcmp() with specialized comparator".
> However, The original patch only optimizes for architectures
> support unaligned machine word access. This patch optimizes for all
> architectures.
>
> A quick fix to satisfy the build check is to make the padding explicit
> (gmail-whitespace-damaged diff):
>
> diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h
> index b65f885..15f08d9 100644
> --- a/net/openvswitch/flow.h
> +++ b/net/openvswitch/flow.h
> @@ -78,6 +78,7 @@ struct sw_flow_key {
> u32 priority; /* Packet QoS priority. */
> u32 skb_mark; /* SKB mark. */
> u16 in_port; /* Input switch port (or
> DP_MAX_PORTS).
> + u16 pad;
> } phy;
> struct {
> u8 src[ETH_ALEN]; /* Ethernet source address. */
>
> However, I have some doubts about other alignment "enforcements":
>
> "__aligned(__alignof__(long))" makes the whole struct aligned to the
> alignment rule for "long":
> 1. This is only 2 bytes on m68k, i.e. != sizeof(long).
> 2. This is 4 bytes on many 32-bit platforms, which may be less than the
> default alignment for "__be64" (cfr. some members of struct
> ovs_key_ipv4_tunnel), so this may make those 64-bit members
> unaligned.
> I guess you want (at least) 4 byte alignment on 32-bit, and prefer 8 byte
> alignment on 64-bit?
> Not specifying any alignment constraint will give you most of that (except
> on 64-bit platforms where 64-bit words must be only 4-byte aligned).
>
> There's another build check "BUILD_BUG_ON(sizeof(long) % sizeof(u32))".
> Isn't this always true on Linux, as "long" is never smaller than 4 bytes?
>
Gr{oetje,eeting}s,
>
> Geert
>
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 --
> geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org
>
> In personal conversations with technical people, I call myself a hacker.
> But
> when I'm talking to journalists I just say "programmer" or something like
> that.
> -- Linus Torvalds
>
[-- Attachment #1.2: Type: text/html, Size: 4410 bytes --]
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply
* [PATCH net-next 2/2] bonding: use rlb_client_info->vlan_id instead of ->tag
From: Veaceslav Falico @ 2013-08-29 21:38 UTC (permalink / raw)
To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek
In-Reply-To: <1377812337-19551-1-git-send-email-vfalico@redhat.com>
Store VID in ->vlan_id (if any), and remove the useless ->tag.
CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
drivers/net/bonding/bond_alb.c | 8 ++++----
drivers/net/bonding/bond_alb.h | 1 -
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 27b03fa..91f179d 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -512,7 +512,7 @@ static void rlb_update_client(struct rlb_client_info *client_info)
skb->dev = client_info->slave->dev;
- if (client_info->tag) {
+ if (client_info->vlan_id) {
skb = vlan_put_tag(skb, htons(ETH_P_8021Q), client_info->vlan_id);
if (!skb) {
pr_err("%s: Error: failed to insert VLAN tag\n",
@@ -695,7 +695,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
}
if (!vlan_get_tag(skb, &client_info->vlan_id))
- client_info->tag = 1;
+ client_info->vlan_id = 0;
if (!client_info->assigned) {
u32 prev_tbl_head = bond_info->rx_hashtbl_used_head;
@@ -801,7 +801,7 @@ static void rlb_init_table_entry_dst(struct rlb_client_info *entry)
entry->used_prev = RLB_NULL_INDEX;
entry->assigned = 0;
entry->slave = NULL;
- entry->tag = 0;
+ entry->vlan_id = 0;
}
static void rlb_init_table_entry_src(struct rlb_client_info *entry)
{
@@ -958,7 +958,7 @@ static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
struct rlb_client_info *curr = &(bond_info->rx_hashtbl[curr_index]);
u32 next_index = bond_info->rx_hashtbl[curr_index].used_next;
- if (curr->tag && (curr->vlan_id == vlan_id))
+ if (curr->vlan_id == vlan_id)
rlb_delete_table_entry(bond, curr_index);
curr_index = next_index;
diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h
index e02c9c5..28d8e4c 100644
--- a/drivers/net/bonding/bond_alb.h
+++ b/drivers/net/bonding/bond_alb.h
@@ -125,7 +125,6 @@ struct rlb_client_info {
u8 assigned; /* checking whether this entry is assigned */
u8 ntt; /* flag - need to transmit client info */
struct slave *slave; /* the slave assigned to this client */
- u8 tag; /* flag - need to tag skb */
unsigned short vlan_id; /* VLAN tag associated with IP address */
};
--
1.8.4
^ permalink raw reply related
* [PATCH net-next 1/2] bonding: remove bond_vlan_used()
From: Veaceslav Falico @ 2013-08-29 21:38 UTC (permalink / raw)
To: netdev; +Cc: Veaceslav Falico, Jay Vosburgh, Andy Gospodarek
In-Reply-To: <1377812337-19551-1-git-send-email-vfalico@redhat.com>
We're using it currently to verify if we have vlans before getting the tag
from the skb we're about to send. It's useless because the vlan_get_tag()
verifies if the skb has the tag (and returns an error if not), and we can
receive tagged skbs only if we *already* have vlans.
Plus, the current RCUed implementation is kind of useless anyway - the we
can remove the last vlan in the moment we return from the function.
So remove the only usage of it and the whole function.
CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
drivers/net/bonding/bond_alb.c | 6 ++----
drivers/net/bonding/bonding.h | 18 ------------------
2 files changed, 2 insertions(+), 22 deletions(-)
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 0182352..27b03fa 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -694,10 +694,8 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
client_info->ntt = 0;
}
- if (bond_vlan_used(bond)) {
- if (!vlan_get_tag(skb, &client_info->vlan_id))
- client_info->tag = 1;
- }
+ if (!vlan_get_tag(skb, &client_info->vlan_id))
+ client_info->tag = 1;
if (!client_info->assigned) {
u32 prev_tbl_head = bond_info->rx_hashtbl_used_head;
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 4abc925..f7ab161 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -261,24 +261,6 @@ struct bonding {
#endif /* CONFIG_DEBUG_FS */
};
-/* if we hold rtnl_lock() - call vlan_uses_dev() */
-static inline bool bond_vlan_used(struct bonding *bond)
-{
- struct net_device *upper;
- struct list_head *iter;
-
- rcu_read_lock();
- netdev_for_each_upper_dev_rcu(bond->dev, upper, iter) {
- if (upper->priv_flags & IFF_802_1Q_VLAN) {
- rcu_read_unlock();
- return true;
- }
- }
- rcu_read_unlock();
-
- return false;
-}
-
#define bond_slave_get_rcu(dev) \
((struct slave *) rcu_dereference(dev->rx_handler_data))
--
1.8.4
^ permalink raw reply related
* [PATCH net-next 0/2] bonding: clean rlb vlan use
From: Veaceslav Falico @ 2013-08-29 21:38 UTC (permalink / raw)
To: netdev; +Cc: Jay Vosburgh, Andy Gospodarek, Veaceslav Falico
Finish the vlan cleanup, only rlb left.
Remove the bond_vlan_used() function, it's useless anyway, and
rlb_client_info->tag, cause we can use only ->vlan_id.
CC: Jay Vosburgh <fubar@us.ibm.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
---
drivers/net/bonding/bond_alb.c | 12 +++++-------
drivers/net/bonding/bond_alb.h | 1 -
drivers/net/bonding/bonding.h | 18 ------------------
3 files changed, 5 insertions(+), 26 deletions(-)
^ permalink raw reply
* Re: [PATCH v3 net-next] tcp: TSO packets automatic sizing
From: Eric Dumazet @ 2013-08-29 21:26 UTC (permalink / raw)
To: David Miller; +Cc: netdev, ncardwell, ycheng, vanj, therbert
In-Reply-To: <20130829.163528.638691969523130618.davem@davemloft.net>
On Thu, 2013-08-29 at 16:35 -0400, David Miller wrote:
>
> No objections from me.
We'll cook a different patch.
Idea is to feed tcp_set_rto() with the srtt found in the tcp metric
cache, and let tp->srtt value found in SYN/SYNACK (if available) as is.
(Be conservative for initial rto value, yet allow tp->srtt be the
current rtt on the network)
Thanks
^ permalink raw reply
* Re: [PATCH net-next] net: ipv6: mldv1/v2: fix switchback timeout to rfc3810, 9.12.
From: Daniel Borkmann @ 2013-08-29 21:24 UTC (permalink / raw)
To: davem; +Cc: netdev, David Stevens, Hannes Frederic Sowa
In-Reply-To: <1377792578-32642-1-git-send-email-dborkman@redhat.com>
Dave, please hold on with this one. This is already better, but
it still needs to be improved slightly. Will send an update tomorrow
or at latest at the beginning of next week.
^ permalink raw reply
* [-next] openvswitch BUILD_BUG_ON failed
From: Geert Uytterhoeven @ 2013-08-29 21:21 UTC (permalink / raw)
To: Andy Zhou, Jesse Gross
Cc: dev-yBygre7rU0TnMu66kgdUjQ,
netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Linux-Next,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
On m68k, where the alignment of 32-bit words is 2 bytes:
net/openvswitch/flow.c:1984:2: error: call to
'__compiletime_assert_1984' declared with attribute error:
BUILD_BUG_ON failed: sizeof(struct sw_flow_key) % sizeof(long)
(http://kisskb.ellerman.id.au/kisskb/buildresult/9422860/)
This was introduced by commit 5828cd9a68873df1340b420371c02c47647878fb
Author: Andy Zhou <azhou-l0M0P4e3n4LQT0dZR+AlfA@public.gmane.org>
Date: Tue Aug 27 13:02:21 2013 -0700
openvswitch: optimize flow compare and mask functions
Make sure the sw_flow_key structure and valid mask boundaries are always
machine word aligned. Optimize the flow compare and mask operations
using machine word size operations. This patch improves throughput on
average by 15% when CPU is the bottleneck of forwarding packets.
This patch is inspired by ideas and code from a patch submitted by Peter
Klausler titled "replace memcmp() with specialized comparator".
However, The original patch only optimizes for architectures
support unaligned machine word access. This patch optimizes for all
architectures.
A quick fix to satisfy the build check is to make the padding explicit
(gmail-whitespace-damaged diff):
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h
index b65f885..15f08d9 100644
--- a/net/openvswitch/flow.h
+++ b/net/openvswitch/flow.h
@@ -78,6 +78,7 @@ struct sw_flow_key {
u32 priority; /* Packet QoS priority. */
u32 skb_mark; /* SKB mark. */
u16 in_port; /* Input switch port (or DP_MAX_PORTS).
+ u16 pad;
} phy;
struct {
u8 src[ETH_ALEN]; /* Ethernet source address. */
However, I have some doubts about other alignment "enforcements":
"__aligned(__alignof__(long))" makes the whole struct aligned to the
alignment rule for "long":
1. This is only 2 bytes on m68k, i.e. != sizeof(long).
2. This is 4 bytes on many 32-bit platforms, which may be less than the
default alignment for "__be64" (cfr. some members of struct
ovs_key_ipv4_tunnel), so this may make those 64-bit members unaligned.
I guess you want (at least) 4 byte alignment on 32-bit, and prefer 8 byte
alignment on 64-bit?
Not specifying any alignment constraint will give you most of that (except
on 64-bit platforms where 64-bit words must be only 4-byte aligned).
There's another build check "BUILD_BUG_ON(sizeof(long) % sizeof(u32))".
Isn't this always true on Linux, as "long" is never smaller than 4 bytes?
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply related
* Re: [PATCH net-next v10 10/11] vxlan: respect scope_id for ll addr
From: David Stevens @ 2013-08-29 21:20 UTC (permalink / raw)
To: Cong Wang; +Cc: Cong Wang, David S. Miller, netdev, netdev-owner
In-Reply-To: <1377667379-2315-11-git-send-email-amwang@redhat.com>
netdev-owner@vger.kernel.org wrote on 08/28/2013 01:22:58 AM:
> From: Cong Wang <amwang@redhat.com>
> As pointed out by David, we should take care of scope id for ll
> addr, and use it for route lookup.
It is an error to have a zero scope_id for an LL addr, but
this code is not correct, because it only honors scope_id for
LL addrs. Multicast addresses also require scope_id be set.
This shouldn't be in the transmit path. The netlink code
that sets it should require it be nonzero for LL addrs and multicast
addrs when it is set, and the transmit path should *always* use scope_id,
whether for an lladdr or not, whether scope_id is zero or not.
I'm away this week and won't be able to review these in
detail until next week, but wanted to get that comment in.
+-DLS
^ 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