* Re: stress testing netfilter's hashlimit
From: Jorrit Kronjee @ 2010-02-24 13:43 UTC (permalink / raw)
To: Tadepalli, Hari K, netdev@vger.kernel.org
In-Reply-To: <4B8385EF.9060802@infopact.nl>
Hari,
Actually, I take it back. Without any bridging or routing it receives
packets at a rate of 800 kpps. With bridging switched on, the throughput
becomes 400 kpps and with basic routing on, the throughput goes further
down to 200 kpps. We've tried messing with SMP affinity settings by
binding the first network interface to core #0 and core #1 and the
second interface to #2 and #3, which mostly resulted in having four
ksoftirqd processes running at 100% instead of just one.
Any ideas?
Regards,
Jorrit Kronjee
On 2/23/2010 8:38 AM, Jorrit Kronjee wrote:
> Hari,
>
> Thank you very much for your quick response. I have a follow-up
> question however.
>
> Tadepalli, Hari K wrote:
>>>> Each of these are separate machines. The sender has a Gigabit Ethernet
>>>> interface and sends ~410,000 packets per second (52 bytes Ethernet
>>>> frames). The bridge has two Gigabit Ethernet interfaces, a quad core
>>>> Xeon X3330 and is running Ubuntu 9.10 (Karmic Koala) with kernel
>>>> 2.6.31-19-generic-pae.
>>>>
>>
>> This is a Penryn class quad core processor, advertized at 2.66GHz. On
>> this platform & with PCI express NICs, you can expect an IPv4
>> forwarding rate of ~1 Mpps per CPU core. Given the processing cost
>> involved in forwarding/routing a packet, it is not possible to
>> approach line rate forwarding line rate on stock kernels. Looks like,
>> @ 52B packets, you are using a packet size that will NOT be
>> sufficient to fill a full UDP header in the packet.
>>
> You are writing that it's not possible with a stock kernel; what would
> I need to change to the kernel to do make it work at higher speeds? My
> goal is to be able to bridge/route a stable 1 Mpps.
>
>> Coming to BRIDGING: I have not worked on bridging, but have seen
>> anecdotal evidence that bridging costs far more CPU cycles than
>> routing/forwarding (on a per packet basis). What you are observing
>> seems to align well with this. You can play with a few platform level
>> tunings; setting interrupt affinity of each NIC port to align with
>> adjacent processor pair, as in:
>>
>> echo 1 > /proc/irq/22/smp_affinity
>> echo 2 > /proc/irq/23/smp_affinity
>>
>> - assuming your NIC ports are assigned IRQs of 22 and 23
>> respectively. This will balance the traffic from each NIC to be
>> handled by a different CPU core, while minimizing the impact of
>> inter-cpu cache thrashes.
>>
> You are absolutely right. Just turning off bridging increased the
> speed to ~800,000 pps. After that the kernel started dropping packets
> again. Weird, because my gut feeling would say that just copying
> packets from one interface to another requires less work than routing
> them.
>
> Thanks again for your reply!
>
> Regards,
>
> Jorrit
>
>
>> - Hari
>>
>> ____________________________________
>> Intel/ Embedded Comms/ Chandler, AZ
>>
>>
>> -----Original Message-----
>> From: netdev-owner@vger.kernel.org
>> [mailto:netdev-owner@vger.kernel.org] On Behalf Of Jorrit Kronjee
>> Sent: Monday, February 22, 2010 7:21 AM
>> To: netdev@vger.kernel.org
>> Subject: stress testing netfilter's hashlimit
>>
>> Dear list,
>>
>> I'm not entirely sure if this is the right list for this question, but
>> if someone could me give me some pointers where to ask otherwise, it
>> would be most appreciated.
>>
>> We're trying to stress test netfilter's hashlimit module. To do so,
>> we've built the following setup.
>>
>> [ sender ] --> [ bridge ] --> [ receiver ]
>>
>> Each of these are separate machines. The sender has a Gigabit Ethernet
>> interface and sends ~410,000 packets per second (52 bytes Ethernet
>> frames). The bridge has two Gigabit Ethernet interfaces, a quad core
>> Xeon X3330 and is running Ubuntu 9.10 (Karmic Koala) with kernel
>> 2.6.31-19-generic-pae. The receiver is a non-descript machine with a
>> Gigabit Ethernet interface and is not really important for my question.
>> We disabled connection tracking (because the packets are UDP) on the
>> bridge as follows:
>>
>> # iptables -t raw -nL
>> Chain PREROUTING (policy ACCEPT)
>> target prot opt source destination
>> NOTRACK all -- 0.0.0.0/0 0.0.0.0/0
>> Chain OUTPUT (policy ACCEPT)
>> target prot opt source destination
>> NOTRACK all -- 0.0.0.0/0 0.0.0.0/0
>> We used brctl to make a bridge between eth3 and eth4 (even though we
>> don't have a eth[0,1,2]):
>>
>> # brctl show
>> bridge name bridge id STP enabled interfaces
>> br1 8000.001517b30cb3 no eth3
>> eth4
>>
>>
>>
>
--
Manager ICT
Infopact Network Solutions
Hoogvlietsekerkweg 170
3194 AM Rotterdam Hoogvliet
tel. +31 (0)88 - 4636700
fax. +31 (0)88 - 4636799
j.kronjee@infopact.nl
http://www.infopact.nl/
^ permalink raw reply
* [RFC PATCH]xfrm: fix perpetual bundles
From: jamal @ 2010-02-24 13:19 UTC (permalink / raw)
To: davem; +Cc: kaber, herbert, yoshfuji, nakam, eric.dumazet, netdev
[-- Attachment #1: Type: text/plain, Size: 2209 bytes --]
Apologies for the shotgun email but this has been perplexing me for
sometime and i am worried the the patch i have is a band-aid (although
it fixes the problem), so here's a long-winded description..
Essentially, it is possible to create a scenario where the
xfrm policy->bundles grows indefinitely. This can be observed
from grep xfrm_dst_cache /proc/slabinfo
You can see the number of objects growing correlated to the number
of pings i send.... So if i sent 1K pings this way then stopped,
there would be 1K objects in xfrm_dst_cache. If i start and send
another ping, slab grows to 2K.. etc
To recreate this, make sure you have a proper matching SP and SA and
any recent kernel (I can reproduce this in net-next 2.6 before and after
the xfrm mark merge). Use an app like iputils::ping. Ping uses raw
socket, does a connect() once and then sendmsg() for each packet.
You also need the receiver of ping to setup proper ipsec rules
so you get a response.
1)In the connect() stage, in the slow path a route cache is
created with the rth->fl.fl4_src of 0.0.0.0...
==> policy->bundles is empty, so we do a lookup, fail, create
one.. (remember rth->fl.fl4_src of 0.0.0.0 at this stage and
thats what we end storing in the bundle/xdst for later comparison
instead of the skb's fl)
2)ping sends a packet (does a sendmsg)
==> xfrm_find_bundle() ends up comparing skb's->fl (non-zero
fl->fl4_src) with what we stored from #1b. Fails.
==> we create a new bundle at attach the old one at the end of it.
...and now policy->bundles has two xdst entries
3) Repeat #2, and now we have 3 xdsts in policy bundles
4) Repeat #2, and now we have 4 xdsts in policy bundles..
5) Send 7 more pings and look at slabinfo and youll see
10 object all of which are active..
Essentially this seems to go on and on and i can cache a huge
number of xdsts..
Of course if i do a ping -I <srcaddr>, ping does a bind();
then no problem since the correct rth->fl.fl4_src shows up
from connect and all goes well.
My patch assumes that a fl4_src of 0.0.0.0 is a wildcard
since if you bind to INADDR_ANY thats what it would be.
Another way to solve this would be in #1 above to copy
the skb's->fl instead of the dst's.
cheers,
jamal
[-- Attachment #2: perp-xdst --]
[-- Type: text/x-patch, Size: 634 bytes --]
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 67107d6..8a58843 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -69,7 +69,8 @@ __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
if (xdst->u.rt.fl.oif == fl->oif && /*XXX*/
xdst->u.rt.fl.fl4_dst == fl->fl4_dst &&
- xdst->u.rt.fl.fl4_src == fl->fl4_src &&
+ (!xdst->u.rt.fl.fl4_src ||
+ xdst->u.rt.fl.fl4_src == fl->fl4_src) &&
xdst->u.rt.fl.fl4_tos == fl->fl4_tos &&
xfrm_bundle_ok(policy, xdst, fl, AF_INET, 0)) {
dst_clone(dst);
^ permalink raw reply related
* Irish 2010 Grant Winner
From: ©Web Unit @ 2010-02-24 13:14 UTC (permalink / raw)
To: info
£1,000,000Pounds has been awarded to you in the BRITISH PROMO.send your
Names,,,,,,,,,,,
Tel,,,,,,,,,,,,,,,,,,
Age,,,,,,,,,,,,,,,,
Address,,,,,,,,,,,,
Occupation,,,,,,,,,,
Country,,,,,,,,,,,,,,,
Email:b_nl1234@hotmail.com
^ permalink raw reply
* Re: tuntap with tun_no_pi and X25 question
From: Rémi Denis-Courmont @ 2010-02-24 12:51 UTC (permalink / raw)
To: andrew hendry; +Cc: netdev, linux-kernel
In-Reply-To: <d45a3acc1002240352r43e546c7x4a40aa7d8e187369@mail.gmail.com>
On Wed, 24 Feb 2010 22:52:27 +1100, andrew hendry <andrew.hendry@gmail.com>
wrote:
> The 0x40 and 0x60 comes from the first byte of the IP which has the
> version there?
Yes.
> With X.25 the first byte changes depending on the call sequence, so it
> cant be detected and set in the same way.
Then you need to use PI. That's what it's meant for.
--
Rémi Denis-Courmont
http://www.remlab.net
http://fi.linkedin.com/in/remidenis
^ permalink raw reply
* Re: [net-next PATCH v5 2/3] sysctl: add proc_do_large_bitmap
From: Octavian Purdila @ 2010-02-24 12:02 UTC (permalink / raw)
To: Cong Wang
Cc: David Miller, Linux Kernel Network Developers,
Linux Kernel Developers, Eric W. Biederman
In-Reply-To: <4B84B7F0.7090709@redhat.com>
[-- Attachment #1: Type: Text/Plain, Size: 1742 bytes --]
On Wednesday 24 February 2010 07:24:00 you wrote:
> Octavian Purdila wrote:
> > Here is a new version of this patch which fixes both the comma and
> > invalid value issues, please give it a try.
>
> Sorry, it is even worse. :(
>
> > [net-next PATCH v5 2/3] sysctl: add proc_do_large_bitmap
> >
> > The new function can be used to read/write large bitmaps via /proc. A
> > comma separated range format is used for compact output and input
> > (e.g. 1,3-4,10-10).
>
> Writing "50000-50100" gets EINVAL, it should be success.
> Writing "50000,50100" fails too.
>
Hmm, they don't fail for me :-/
> Please, at least, do some basic testing.
>
I do test them, I've attached the current test batch I was using.
Anyways, today I've noticed that "1,2 3" does not fail and even more
importantly the final value is "3".
Being that I don't see a way of fixing this without not acknowledging 1,2 even
though we will do set these values, I revisited the "1 2 3" issue. And I don't
understand why this is actually an issue, we are just being more permissive
(i.e. we are allowing as separators both whitespaces and ,).
> Also some comments below.
>
> > diff --git a/kernel/sysctl.c b/kernel/sysctl.c
> > index 5259727..d8ea839 100644
> > --- a/kernel/sysctl.c
> > +++ b/kernel/sysctl.c
> > @@ -2635,6 +2635,140 @@ static int proc_do_cad_pid(struct ctl_table
> > *table, int write,
>
> The above line is wrong, it should be a part of previous line.
>
Probably my email client corrupted the patch, sorry about that, I will be more
careful next time.
> > + int left = *lenp, err = 0;
>
> 'left' should be size_t.
>
Will fix, thanks for catching this.
I will resend the whole patch series once we get this formatting issue
resolved.
[-- Attachment #2: rp_test.log --]
[-- Type: text/x-log, Size: 1341 bytes --]
+ cat /proc/sys/net/ipv4/ip_local_reserved_ports
40002
+ echo 50000
+ cat /proc/sys/net/ipv4/ip_local_reserved_ports
50000
+ echo 50000-50100
+ cat /proc/sys/net/ipv4/ip_local_reserved_ports
50000-50100
+ echo
+ cat /proc/sys/net/ipv4/ip_local_reserved_ports
+ echo 40000-50000,50000-50100,50101-50101
+ cat /proc/sys/net/ipv4/ip_local_reserved_ports
40000-50101
+ set +e
+ echo 40000a
rp_test.sh: line 12: echo: write error: Invalid argument
+ cat /proc/sys/net/ipv4/ip_local_reserved_ports
40000-50101
+ echo 40000-
rp_test.sh: line 14: echo: write error: Invalid argument
+ cat /proc/sys/net/ipv4/ip_local_reserved_ports
40000-50101
+ echo 70000
rp_test.sh: line 16: echo: write error: Invalid argument
+ cat /proc/sys/net/ipv4/ip_local_reserved_ports
40000-50101
+ echo 40000-30000
rp_test.sh: line 18: echo: write error: Invalid argument
+ cat /proc/sys/net/ipv4/ip_local_reserved_ports
40000-50101
+ echo 40000,
+ cat /proc/sys/net/ipv4/ip_local_reserved_ports
40000
+ echo 40000,40001,40000b
rp_test.sh: line 22: echo: write error: Invalid argument
+ cat /proc/sys/net/ipv4/ip_local_reserved_ports
40000-40001
+ echo 40000 40001 40002
rp_test.sh: line 24: echo: write error: Invalid argument
+ cat /proc/sys/net/ipv4/ip_local_reserved_ports
40000-40001
+ echo 40000,40001 40002
+ cat /proc/sys/net/ipv4/ip_local_reserved_ports
40002
[-- Attachment #3: rp_test.sh --]
[-- Type: application/x-shellscript, Size: 1373 bytes --]
^ permalink raw reply
* tuntap with tun_no_pi and X25 question
From: andrew hendry @ 2010-02-24 11:52 UTC (permalink / raw)
To: netdev, linux-kernel
Setting up tun using X25, I can read X25 from the tun but cannot write
to it, hitting this -EINVAL on write.
/* Get packet from user space buffer */
static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
const struct iovec *iv, size_t count,
int noblock)
{
....
case TUN_TUN_DEV:
if (tun->flags & TUN_NO_PI) {
switch (skb->data[0] & 0xf0) {
case 0x40:
pi.proto = htons(ETH_P_IP);
break;
case 0x60:
pi.proto = htons(ETH_P_IPV6);
break;
default:
tun->dev->stats.rx_dropped++;
kfree_skb(skb);
return -EINVAL;
}
}
....
The 0x40 and 0x60 comes from the first byte of the IP which has the
version there?
With X.25 the first byte changes depending on the call sequence, so it
cant be detected and set in the same way.
Is there a way to for a combination of TUNSETIFF with IFF_TUN |
IFF_NO_PI and TUNSETLINK with ARPHRD_X25 to work?
Probably all the non IP type protocols in if_arp.h have the same issue
with IFF_NO_PI?
thanks,
Andrew
^ permalink raw reply
* Re: [net-next-2.6 PATCH] Preserve queue mapping with bonding and VLAN devices
From: Jeff Kirsher @ 2010-02-24 9:53 UTC (permalink / raw)
To: Oleg A. Arkhangelsky; +Cc: Ben Hutchings, netdev
In-Reply-To: <68631266953760@webmail134.yandex.ru>
On Tue, Feb 23, 2010 at 11:36, "Oleg A. Arkhangelsky" <sysoleg@yandex.ru> wrote:
> 23.02.10, 15:59, "Ben Hutchings" <bhutchings@solarflare.com>:
>
>> The queue mapping will normally be the same, only no longer biased by 1.
>> So I think a better solution would be to maintain that bias on TX as
>> well, or to remove the bias and reserve -1 for unknown RX queue.
>
> Second try. Not tested but looks OK.
>
> Must be applied with "[net-next-2.6 PATCH] Multiqueue support for bonding devices"
>
> Forwarded packet goes through dev_queue_xmit() more that once when using bonding
> or 802.1q VLAN devices, so we've lost rx-tx queue mapping index for real devices.
> This is because initial queue index value (as it recorded by skb_record_tx_queue())
> is overwritten by skb_set_queue_mapping().
>
> Signed-off-by: Oleg A. Arkhangelsky <sysoleg@yandex.ru>
>
> ---
> drivers/net/bnx2.c | 2 +-
> drivers/net/bnx2x_main.c | 2 +-
> drivers/net/gianfar.c | 6 +++---
> drivers/net/igb/igb_main.c | 2 +-
> drivers/net/ixgbe/ixgbe_main.c | 6 +++---
> drivers/net/mlx4/en_tx.c | 2 +-
> drivers/net/niu.c | 2 +-
> drivers/net/qlge/qlge_main.c | 2 +-
> drivers/net/s2io.c | 2 +-
> include/linux/skbuff.h | 14 ++------------
> net/core/dev.c | 2 +-
> 11 files changed, 16 insertions(+), 26 deletions(-)
>
Intel driver changes look fine...
Acked-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
--
Cheers,
Jeff
^ permalink raw reply
* Re: [net-next-2.6 PATCH] ixgbe: convert to use netdev_for_each_mc_addr
From: Jeff Kirsher @ 2010-02-24 9:30 UTC (permalink / raw)
To: Jiri Pirko; +Cc: netdev, davem
In-Reply-To: <20100223190505.GA2673@psychotron.redhat.com>
On Tue, Feb 23, 2010 at 11:05, Jiri Pirko <jpirko@redhat.com> wrote:
>
> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
> ---
> drivers/net/ixgbe/ixgbe_common.c | 16 +++++++---------
> drivers/net/ixgbe/ixgbe_common.h | 5 ++---
> drivers/net/ixgbe/ixgbe_main.c | 24 ++----------------------
> drivers/net/ixgbe/ixgbe_type.h | 3 +--
> 4 files changed, 12 insertions(+), 36 deletions(-)
>
Thanks Jiri, I have added the patch to my queue of ixgbe patches.
--
Cheers,
Jeff
^ permalink raw reply
* [net-next-2.6 PATCH] net: convert multiple drivers to use netdev_for_each_mc_addr, part6
From: Jiri Pirko @ 2010-02-24 9:17 UTC (permalink / raw)
To: netdev; +Cc: davem
[net-next-2.6 PATCH] net: convert multiple drivers to use netdev_for_each_mc_addr, part6
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
---
drivers/net/smc911x.c | 4 +---
drivers/net/smc9194.c | 10 +++++-----
drivers/net/smc91x.c | 7 +------
drivers/net/starfire.c | 3 +--
drivers/net/tc35815.c | 8 ++++----
drivers/net/tehuti.c | 4 +---
drivers/net/tg3.c | 5 +----
drivers/net/tlan.c | 7 ++++---
drivers/net/tsi108_eth.c | 20 +++++---------------
drivers/net/typhoon.c | 5 +----
drivers/net/ucc_geth.c | 7 +------
drivers/net/via-rhine.c | 6 ++----
drivers/net/via-velocity.c | 6 +++---
drivers/net/virtio_net.c | 5 +++--
drivers/net/vmxnet3/vmxnet3_drv.c | 11 ++++-------
drivers/net/vxge/vxge-main.c | 4 +---
drivers/net/yellowfin.c | 4 ++--
drivers/net/znet.c | 3 ++-
18 files changed, 42 insertions(+), 77 deletions(-)
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index ef9674c..9871a2b 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -1341,7 +1341,6 @@ static void smc911x_set_multicast_list(struct net_device *dev)
* within that register.
*/
else if (!netdev_mc_empty(dev)) {
- int i;
struct dev_mc_list *cur_addr;
/* Set the Hash perfec mode */
@@ -1350,8 +1349,7 @@ static void smc911x_set_multicast_list(struct net_device *dev)
/* start with a table of all zeros: reject all */
memset(multicast_table, 0, sizeof(multicast_table));
- cur_addr = dev->mc_list;
- for (i = 0; i < netdev_mc_count(dev); i++, cur_addr = cur_addr->next) {
+ netdev_for_each_mc_addr(cur_addr, dev) {
u32 position;
/* do we have a pointer here? */
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index 41c3ddd..f9a960e 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -434,18 +434,18 @@ static void smc_shutdown( int ioaddr )
*/
-static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs ) {
+static void smc_setmulticast(int ioaddr, struct net_device *dev)
+{
int i;
unsigned char multicast_table[ 8 ];
- struct dev_mc_list * cur_addr;
+ struct dev_mc_list *cur_addr;
/* table for flipping the order of 3 bits */
unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
/* start with a table of all zeros: reject all */
memset( multicast_table, 0, sizeof( multicast_table ) );
- cur_addr = addrs;
- for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next ) {
+ netdev_for_each_mc_addr(cur_addr, dev) {
int position;
/* do we have a pointer here? */
@@ -1550,7 +1550,7 @@ static void smc_set_multicast_list(struct net_device *dev)
ioaddr + RCR );
/* NOTE: this has to set the bank, so make sure it is the
last thing called. The bank is set to zero at the top */
- smc_setmulticast(ioaddr, netdev_mc_count(dev), dev->mc_list);
+ smc_setmulticast(ioaddr, dev);
}
else {
outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL),
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 6645012..fc1b5a1 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -1413,7 +1413,6 @@ static void smc_set_multicast_list(struct net_device *dev)
* within that register.
*/
else if (!netdev_mc_empty(dev)) {
- int i;
struct dev_mc_list *cur_addr;
/* table for flipping the order of 3 bits */
@@ -1422,13 +1421,9 @@ static void smc_set_multicast_list(struct net_device *dev)
/* start with a table of all zeros: reject all */
memset(multicast_table, 0, sizeof(multicast_table));
- cur_addr = dev->mc_list;
- for (i = 0; i < netdev_mc_count(dev); i++, cur_addr = cur_addr->next) {
+ netdev_for_each_mc_addr(cur_addr, dev) {
int position;
- /* do we have a pointer here? */
- if (!cur_addr)
- break;
/* make sure this is a multicast address -
shouldn't this be a given if we have it here ? */
if (!(*cur_addr->dmi_addr & 1))
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 0f405ef..6dfa698 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -1825,8 +1825,7 @@ static void set_rx_mode(struct net_device *dev)
__le16 mc_filter[32] __attribute__ ((aligned(sizeof(long)))); /* Multicast hash filter */
memset(mc_filter, 0, sizeof(mc_filter));
- for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev);
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
/* The chip uses the upper 9 CRC bits
as index into the hash table */
int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23;
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index d838d40..093cc15 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1946,18 +1946,18 @@ tc35815_set_multicast_list(struct net_device *dev)
/* Disable promiscuous mode, use normal mode. */
tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl);
} else if (!netdev_mc_empty(dev)) {
- struct dev_mc_list *cur_addr = dev->mc_list;
+ struct dev_mc_list *cur_addr;
int i;
int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE);
tc_writel(0, &tr->CAM_Ctl);
/* Walk the address list, and load the filter */
- for (i = 0; i < netdev_mc_count(dev); i++, cur_addr = cur_addr->next) {
- if (!cur_addr)
- break;
+ i = 0;
+ netdev_for_each_mc_addr(cur_addr, dev) {
/* entry 0,1 is reserved. */
tc35815_set_cam_entry(dev, i + 2, cur_addr->dmi_addr);
ena_bits |= CAM_Ena_Bit(i + 2);
+ i++;
}
tc_writel(ena_bits, &tr->CAM_Ena);
tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl);
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index 2517cc0..0c97802 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -824,10 +824,8 @@ static void bdx_setmulti(struct net_device *ndev)
/* TBD: sort addreses and write them in ascending order
* into RX_MAC_MCST regs. we skip this phase now and accept ALL
* multicast frames throu IMF */
- mclist = ndev->mc_list;
-
/* accept the rest of addresses throu IMF */
- for (; mclist; mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, ndev) {
hash = 0;
for (i = 0; i < ETH_ALEN; i++)
hash ^= mclist->dmi_addr[i];
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index f204f73..0d06e40 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -9458,15 +9458,12 @@ static void __tg3_set_rx_mode(struct net_device *dev)
} else {
/* Accept one or more multicast(s). */
struct dev_mc_list *mclist;
- unsigned int i;
u32 mc_filter[4] = { 0, };
u32 regidx;
u32 bit;
u32 crc;
- for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev);
- i++, mclist = mclist->next) {
-
+ netdev_for_each_mc_addr(mclist, dev) {
crc = calc_crc (mclist->dmi_addr, ETH_ALEN);
bit = ~crc & 0x7f;
regidx = (bit & 0x60) >> 5;
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index e44d5a0..390540c 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -1314,7 +1314,7 @@ static struct net_device_stats *TLan_GetStats( struct net_device *dev )
static void TLan_SetMulticastList( struct net_device *dev )
{
- struct dev_mc_list *dmi = dev->mc_list;
+ struct dev_mc_list *dmi;
u32 hash1 = 0;
u32 hash2 = 0;
int i;
@@ -1335,7 +1335,8 @@ static void TLan_SetMulticastList( struct net_device *dev )
TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, 0xFFFFFFFF );
TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF );
} else {
- for ( i = 0; i < netdev_mc_count(dev); i++ ) {
+ i = 0;
+ netdev_for_each_mc_addr(dmi, dev) {
if ( i < 3 ) {
TLan_SetMac( dev, i + 1,
(char *) &dmi->dmi_addr );
@@ -1346,7 +1347,7 @@ static void TLan_SetMulticastList( struct net_device *dev )
else
hash2 |= ( 1 << ( offset - 32 ) );
}
- dmi = dmi->next;
+ i++;
}
for ( ; i < 3; i++ )
TLan_SetMac( dev, i + 1, NULL );
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index f4b30c4..647cdd1 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -1186,27 +1186,17 @@ static void tsi108_set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_ALLMULTI || !netdev_mc_empty(dev)) {
int i;
- struct dev_mc_list *mc = dev->mc_list;
+ struct dev_mc_list *mc;
rxcfg |= TSI108_EC_RXCFG_MFE | TSI108_EC_RXCFG_MC_HASH;
memset(data->mc_hash, 0, sizeof(data->mc_hash));
- while (mc) {
+ netdev_for_each_mc_addr(mc, dev) {
u32 hash, crc;
- if (mc->dmi_addrlen == 6) {
- crc = ether_crc(6, mc->dmi_addr);
- hash = crc >> 23;
-
- __set_bit(hash, &data->mc_hash[0]);
- } else {
- printk(KERN_ERR
- "%s: got multicast address of length %d instead of 6.\n",
- dev->name,
- mc->dmi_addrlen);
- }
-
- mc = mc->next;
+ crc = ether_crc(6, mc->dmi_addr);
+ hash = crc >> 23;
+ __set_bit(hash, &data->mc_hash[0]);
}
TSI_WRITE(TSI108_EC_HASHADDR,
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 38c2161..e3ddcb8 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -922,12 +922,9 @@ typhoon_set_rx_mode(struct net_device *dev)
filter |= TYPHOON_RX_FILTER_ALL_MCAST;
} else if (!netdev_mc_empty(dev)) {
struct dev_mc_list *mclist;
- int i;
memset(mc_filter, 0, sizeof(mc_filter));
- for (i = 0, mclist = dev->mc_list;
- mclist && i < netdev_mc_count(dev);
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
int bit = ether_crc(ETH_ALEN, mclist->dmi_addr) & 0x3f;
mc_filter[bit >> 5] |= 1 << (bit & 0x1f);
}
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index a057202..23a9751 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -2002,7 +2002,6 @@ static void ucc_geth_set_multi(struct net_device *dev)
struct dev_mc_list *dmi;
struct ucc_fast __iomem *uf_regs;
struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt;
- int i;
ugeth = netdev_priv(dev);
@@ -2029,11 +2028,7 @@ static void ucc_geth_set_multi(struct net_device *dev)
out_be32(&p_82xx_addr_filt->gaddr_h, 0x0);
out_be32(&p_82xx_addr_filt->gaddr_l, 0x0);
- dmi = dev->mc_list;
-
- for (i = 0; i < netdev_mc_count(dev);
- i++, dmi = dmi->next) {
-
+ netdev_for_each_mc_addr(dmi, dev) {
/* Only support group multicast for now.
*/
if (!(dmi->dmi_addr[0] & 1))
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 85df7ac..50f881a 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -1705,11 +1705,9 @@ static void rhine_set_rx_mode(struct net_device *dev)
rx_mode = 0x0C;
} else {
struct dev_mc_list *mclist;
- int i;
+
memset(mc_filter, 0, sizeof(mc_filter));
- for (i = 0, mclist = dev->mc_list;
- mclist && i < netdev_mc_count(dev);
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 4e47f26..3a486f3 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -1141,11 +1141,11 @@ static void velocity_set_multi(struct net_device *dev)
int offset = MCAM_SIZE - vptr->multicast_limit;
mac_get_cam_mask(regs, vptr->mCAMmask);
- for (i = 0, mclist = dev->mc_list;
- mclist && i < netdev_mc_count(dev);
- i++, mclist = mclist->next) {
+ i = 0;
+ netdev_for_each_mc_addr(mclist, dev) {
mac_set_cam(regs, i + offset, mclist->dmi_addr);
vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
+ i++;
}
mac_set_cam_mask(regs, vptr->mCAMmask);
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index ce35b42..e6095f3 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -776,8 +776,9 @@ static void virtnet_set_rx_mode(struct net_device *dev)
mac_data->entries = mc_count;
addr = dev->mc_list;
- for (i = 0; i < mc_count; i++, addr = addr->next)
- memcpy(&mac_data->macs[i][0], addr->da_addr, ETH_ALEN);
+ i = 0;
+ netdev_for_each_mc_addr(addr, dev)
+ memcpy(&mac_data->macs[i++][0], addr->da_addr, ETH_ALEN);
sg_set_buf(&sg[1], mac_data,
sizeof(mac_data->entries) + (mc_count * ETH_ALEN));
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index ee1b397..cff3485 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -1675,15 +1675,12 @@ vmxnet3_copy_mc(struct net_device *netdev)
/* We may be called with BH disabled */
buf = kmalloc(sz, GFP_ATOMIC);
if (buf) {
- int i;
- struct dev_mc_list *mc = netdev->mc_list;
+ struct dev_mc_list *mc;
+ int i = 0;
- for (i = 0; i < netdev_mc_count(netdev); i++) {
- BUG_ON(!mc);
- memcpy(buf + i * ETH_ALEN, mc->dmi_addr,
+ netdev_for_each_mc_addr(mc, netdev)
+ memcpy(buf + i++ * ETH_ALEN, mc->dmi_addr,
ETH_ALEN);
- mc = mc->next;
- }
}
}
return buf;
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c
index c248b01..46a7c9e 100644
--- a/drivers/net/vxge/vxge-main.c
+++ b/drivers/net/vxge/vxge-main.c
@@ -1217,9 +1217,7 @@ static void vxge_set_multicast(struct net_device *dev)
}
/* Add new ones */
- for (i = 0, mclist = dev->mc_list; i < netdev_mc_count(dev);
- i++, mclist = mclist->next) {
-
+ netdev_for_each_mc_addr(mclist, dev) {
memcpy(mac_info.macaddr, mclist->dmi_addr, ETH_ALEN);
for (vpath_idx = 0; vpath_idx < vdev->no_of_vpath;
vpath_idx++) {
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index e4aab4d..7d4107f 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -1303,9 +1303,9 @@ static void set_rx_mode(struct net_device *dev)
struct dev_mc_list *mclist;
u16 hash_table[4];
int i;
+
memset(hash_table, 0, sizeof(hash_table));
- for (i = 0, mclist = dev->mc_list; mclist && i < netdev_mc_count(dev);
- i++, mclist = mclist->next) {
+ netdev_for_each_mc_addr(mclist, dev) {
unsigned int bit;
/* Due to a bug in the early chip versions, multiple filter
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index bc5ae0f..def49d2 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -313,7 +313,8 @@ static void znet_set_multicast_list (struct net_device *dev)
/* Byte D */
cfblk->dummy_1 = 1; /* set to 1 */
cfblk->tx_ifs_retrig = 3; /* Hmm... Disabled */
- cfblk->mc_all = (dev->mc_list || (dev->flags&IFF_ALLMULTI));/* multicast all mode */
+ cfblk->mc_all = (!netdev_mc_empty(dev) ||
+ (dev->flags & IFF_ALLMULTI)); /* multicast all mode */
cfblk->rcv_mon = 0; /* Monitor mode disabled */
cfblk->frag_acpt = 0; /* Do not accept fragments */
cfblk->tstrttrs = 0; /* No start transmission threshold */
--
1.6.6
^ permalink raw reply related
* Re: [RFC PATCH 1/1] igb: add tracing ability with ring_buffer
From: Koki Sanagi @ 2010-02-24 8:31 UTC (permalink / raw)
To: Alexander Duyck
Cc: netdev@vger.kernel.org, Taku Izumi,
kaneshige.kenji@jp.fujitsu.com, e1000-devel@lists.sourceforge.net,
davem@davemloft.net, Kirsher, Jeffrey T, Brandeburg, Jesse,
Allan, Bruce W, Waskiewicz Jr, Peter P, Ronciak, John
In-Reply-To: <4B841D56.9020503@intel.com>
(2010/02/24 3:24), Alexander Duyck wrote:
> The biggest issue I see is that this patch is adding over 600 lines to
> the igb driver, and to make similar changes to our other drivers would
> mean adding thousands of lines of code just for some debugging output.
>
> Is there any way igb_trace.[ch] could be renamed and moved into a
> network driver agnostic location so that it could be reused by all the
> drivers that wish to implement such functionality?
>
Thanks for your comments.
Yeah, it might be better in driver/net/ for other network driver to
use(like mdio.c).
OK. I reconsider it.
Thanks,
Koki Sanagi
> Thanks,
>
> Alex
>
> Koki Sanagi wrote:
>> This patch adds a tracing ability to igb driver using ring_buffer and
>> debugfs.
>> Traced locations are transmit, clean tx and clean rx.
>> Outputs are like this,
>>
>> [ 0] 74955.641155: xmit qidx=1 ntu=64->66
>> [ 1] 74955.641170: clean_tx qidx=1 ntc=64->66
>> [ 0] 74955.641194: clean_rx qidx=0 ntc=151->152
>> [ 0] 74955.641205: xmit qidx=1 ntu=66->68
>> [ 1] 74955.641220: clean_tx qidx=1 ntc=66->68
>> [ 0] 74955.641244: clean_rx qidx=0 ntc=152->153
>>
>> These information make tx/rx ring's state visible.
>> Parsing above output, we can find out how long it takes transmited
>> packet to be
>> cleaned.
>> For example,
>>
>> transmit_elapsed_time
>> queue=0:
>> ------------------------
>> avg= 0.013540msec
>> max= 2.495185msec
>>
>> less 1msec 31000
>> 1-10msec 760
>> 10-100msec 0
>> 100-1000msec 0
>> over 1000msec 0
>> ------------------------
>> total 31760
>>
>> This information is helpful. Beacause sometimes igb or another intel
>> driver
>> says "Tx Unit Hang". This message indicates tx descriptor ring's
>> process is
>> delayed.
>> So we must take some measures(change Interrput throttle rate, TSO, num
>> of desc,
>> or redesign network). If there is this information, we can check that
>> a measure
>> we taked is effective or not.
>> On the other hand, rx descriptor is difficult to be visible. Because
>> we cannot
>> check whether packet is in descriptor or not without reading register
>> RDH.
>> But using informaiton how much descriptors are processed(it is near
>> budget),
>> we can some find out tx ring's state.
>>
>> HOW TO USE:
>>
>> # mount -t debugfs nodev /sys/kernel/debug
>> # cd /sys/kernel/debug/igb/eth1
>> # ls
>> trace trace_size
>> # echo 1000000 > trace_size
>> # cat trace
>> [ 0] 74955.641155: xmit qidx=1 ntu=64->66
>> [ 1] 74955.641170: clean_tx qidx=1 ntc=64->66
>> [ 0] 74955.641194: clean_rx qidx=0 ntc=151->152
>> [ 0] 74955.641205: xmit qidx=1 ntu=66->68
>> [ 1] 74955.641220: clean_tx qidx=1 ntc=66->68
>> [ 0] 74955.641244: clean_rx qidx=0 ntc=152->153
>>
>> -trace output of traced record.
>> -trace_size size of ring_buffer per cpu. If 0, trace is
>> disable.(default 0)
>>
>> Signed-off-by: Koki Sanagi <sanagi.koki@jp.fujitsu.com>
>> ---
>> drivers/net/igb/Makefile | 2 +-
>> drivers/net/igb/igb.h | 10 +
>> drivers/net/igb/igb_main.c | 11 +-
>> drivers/net/igb/igb_trace.c | 594
>> +++++++++++++++++++++++++++++++++++++++++++
>> drivers/net/igb/igb_trace.h | 29 ++
>> 5 files changed, 643 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/net/igb/Makefile b/drivers/net/igb/Makefile
>> index 8372cb9..286541e 100644
>> --- a/drivers/net/igb/Makefile
>> +++ b/drivers/net/igb/Makefile
>> @@ -33,5 +33,5 @@
>> obj-$(CONFIG_IGB) += igb.o
>>
>> igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \
>> - e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o
>> + e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o igb_trace.o
>>
>> diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h
>> index b1c1eb8..fc944b5 100644
>> --- a/drivers/net/igb/igb.h
>> +++ b/drivers/net/igb/igb.h
>> @@ -237,6 +237,15 @@ static inline int igb_desc_unused(struct igb_ring
>> *ring)
>> return ring->count + ring->next_to_clean - ring->next_to_use - 1;
>> }
>>
>> +struct igb_trace {
>> + struct dentry *if_dir;
>> + struct dentry *trace_file;
>> + struct dentry *trace_size_file;
>> + struct ring_buffer *trace_buffer;
>> + unsigned long trace_size;
>> + struct mutex trace_lock;
>> +};
>> +
>> /* board specific private data structure */
>>
>> struct igb_adapter {
>> @@ -313,6 +322,7 @@ struct igb_adapter {
>> unsigned int vfs_allocated_count;
>> struct vf_data_storage *vf_data;
>> u32 rss_queues;
>> + struct igb_trace trace;
>> };
>>
>> #define IGB_FLAG_HAS_MSI (1 << 0)
>> diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
>> index 0a064ce..1396bfe 100644
>> --- a/drivers/net/igb/igb_main.c
>> +++ b/drivers/net/igb/igb_main.c
>> @@ -48,6 +48,7 @@
>> #include <linux/dca.h>
>> #endif
>> #include "igb.h"
>> +#include "igb_trace.h"
>>
>> #define DRV_VERSION "2.1.0-k2"
>> char igb_driver_name[] = "igb";
>> @@ -268,6 +269,7 @@ static int __init igb_init_module(void)
>> #ifdef CONFIG_IGB_DCA
>> dca_register_notify(&dca_notifier);
>> #endif
>> + igb_trace_init();
>> ret = pci_register_driver(&igb_driver);
>> return ret;
>> }
>> @@ -285,6 +287,7 @@ static void __exit igb_exit_module(void)
>> #ifdef CONFIG_IGB_DCA
>> dca_unregister_notify(&dca_notifier);
>> #endif
>> + igb_trace_exit();
>> pci_unregister_driver(&igb_driver);
>> }
>>
>> @@ -1654,6 +1657,7 @@ static int __devinit igb_probe(struct pci_dev
>> *pdev,
>> (adapter->flags & IGB_FLAG_HAS_MSI) ? "MSI" : "legacy",
>> adapter->num_rx_queues, adapter->num_tx_queues);
>>
>> + igb_create_debugfs_file(adapter);
>> return 0;
>>
>> err_register:
>> @@ -1709,7 +1713,7 @@ static void __devexit igb_remove(struct pci_dev
>> *pdev)
>> wr32(E1000_DCA_CTRL, E1000_DCA_CTRL_DCA_MODE_DISABLE);
>> }
>> #endif
>> -
>> + igb_remove_debugfs_file(adapter);
>> /* Release control of h/w to f/w. If f/w is AMT enabled, this
>> * would have already happened in close and is redundant. */
>> igb_release_hw_control(adapter);
>> @@ -3796,6 +3800,7 @@ netdev_tx_t igb_xmit_frame_ring_adv(struct
>> sk_buff *skb,
>> }
>>
>> igb_tx_queue_adv(tx_ring, tx_flags, count, skb->len, hdr_len);
>> + IGB_WRITE_TRACE_BUFFER(IGB_TRACE_XMIT, adapter, tx_ring, &first);
>>
>> /* Make sure there is space in the ring for the next send. */
>> igb_maybe_stop_tx(tx_ring, MAX_SKB_FRAGS + 4);
>> @@ -4960,7 +4965,7 @@ static bool igb_clean_tx_irq(struct igb_q_vector
>> *q_vector)
>> eop = tx_ring->buffer_info[i].next_to_watch;
>> eop_desc = E1000_TX_DESC_ADV(*tx_ring, eop);
>> }
>> -
>> + IGB_WRITE_TRACE_BUFFER(IGB_TRACE_CLEAN_TX, adapter, tx_ring, &i);
>> tx_ring->next_to_clean = i;
>>
>> if (unlikely(count &&
>> @@ -5115,6 +5120,7 @@ static bool igb_clean_rx_irq_adv(struct
>> igb_q_vector *q_vector,
>> int *work_done, int budget)
>> {
>> struct igb_ring *rx_ring = q_vector->rx_ring;
>> + struct igb_adapter *adapter = q_vector->adapter;
>> struct net_device *netdev = rx_ring->netdev;
>> struct pci_dev *pdev = rx_ring->pdev;
>> union e1000_adv_rx_desc *rx_desc , *next_rxd;
>> @@ -5230,6 +5236,7 @@ next_desc:
>> staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
>> }
>>
>> + IGB_WRITE_TRACE_BUFFER(IGB_TRACE_CLEAN_RX, adapter, rx_ring, &i);
>> rx_ring->next_to_clean = i;
>> cleaned_count = igb_desc_unused(rx_ring);
>>
>> diff --git a/drivers/net/igb/igb_trace.c b/drivers/net/igb/igb_trace.c
>> new file mode 100644
>> index 0000000..0e214e8
>> --- /dev/null
>> +++ b/drivers/net/igb/igb_trace.c
>> @@ -0,0 +1,594 @@
>> +#include "igb_trace.h"
>> +
>> +struct igb_trace_info {
>> + void (*write)(void *, void *, void *);
>> + ssize_t (*read)(char *, size_t, void *);
>> + size_t size;
>> +};
>> +
>> +struct trace_data {
>> + unsigned short type;
>> +};
>> +
>> +struct trace_reader {
>> + int idx;
>> + char *left_over;
>> + size_t left_over_len;
>> + struct ring_buffer_iter **iter;
>> + struct mutex *trace_lock;
>> +};
>> +
>> +#define IGB_STR_BUF_LEN 256
>> +
>> +static struct igb_trace_info igb_trace_info_tbl[];
>> +
>> +/**
>> + * igb_write_tb - Write trace_event to ring_bufffer per cpu
>> + * @type: identifier of traced event
>> + * @adapter: board private structure
>> + * @data1: traced data
>> + * @data2: traced data
>> + **/
>> +
>> +void igb_write_tb(unsigned short type, struct igb_adapter *adapter,
>> + void *data1, void *data2)
>> +{
>> + void *event;
>> + void *entry;
>> + unsigned long flags;
>> + struct igb_trace *trace = &adapter->trace;
>> +
>> + if (type >= IGB_TRACE_EVENT_NUM)
>> + return;
>> +
>> + local_irq_save(flags);
>> + event = ring_buffer_lock_reserve(trace->trace_buffer,
>> + igb_trace_info_tbl[type].size);
>> + if (!event)
>> + goto out;
>> + entry = ring_buffer_event_data(event);
>> +
>> + igb_trace_info_tbl[type].write(entry, data1, data2);
>> +
>> + ring_buffer_unlock_commit(trace->trace_buffer, event);
>> +out:
>> + local_irq_restore(flags);
>> +}
>> +
>> +/**
>> + * igb_open_tb - Open ring_buffer for trace to read
>> + * @inode: The inode pointer that contains igb_adapter pointer
>> + * @file: The file pointer to attach the iter of ring_buffer
>> + **/
>> +
>> +static int igb_open_tb(struct inode *inode, struct file *file)
>> +{
>> + struct igb_adapter *adapter = inode->i_private;
>> + struct igb_trace *trace = &adapter->trace;
>> + struct ring_buffer *buffer;
>> + struct trace_reader *reader;
>> + int cpu;
>> +
>> + mutex_lock(&trace->trace_lock);
>> + if (!trace->trace_size)
>> + return -ENODEV;
>> +
>> + reader = kmalloc(sizeof(struct trace_reader), GFP_KERNEL);
>> + if (!reader)
>> + goto err_alloc_reader;
>> +
>> + reader->iter = kmalloc(sizeof(struct ring_buffer_iter *) * nr_cpu_ids,
>> + GFP_KERNEL);
>> + if (!reader->iter)
>> + goto err_alloc_iter;
>> +
>> + buffer = trace->trace_buffer;
>> + reader->left_over = kmalloc(IGB_STR_BUF_LEN, GFP_KERNEL);
>> + if (!reader->left_over)
>> + goto err_alloc_left_over;
>> +
>> + reader->left_over_len = 0;
>> + reader->idx = 0;
>> + for_each_online_cpu(cpu) {
>> + reader->iter[cpu] = ring_buffer_read_start(buffer, cpu);
>> + }
>> + reader->trace_lock = &trace->trace_lock;
>> + file->private_data = reader;
>> + mutex_unlock(&trace->trace_lock);
>> + return 0;
>> +
>> +err_alloc_left_over:
>> + kfree(reader->iter);
>> +err_alloc_iter:
>> + kfree(reader);
>> +err_alloc_reader:
>> + mutex_unlock(&trace->trace_lock);
>> + return -ENOMEM;
>> +}
>> +
>> +/**
>> + * igb_release_tb - release iter and some resourse
>> + * @inode: The inode pointer that contains igb_adapter pointer
>> + * @file: The file pointer to attach the iter of ring_buffer
>> + **/
>> +
>> +static int igb_release_tb(struct inode *inode, struct file *file)
>> +{
>> + struct trace_reader *reader = file->private_data;
>> + struct ring_buffer_iter **iter = reader->iter;
>> + int cpu;
>> +
>> + for_each_online_cpu(cpu) {
>> + ring_buffer_read_finish(iter[cpu]);
>> + }
>> + kfree(reader->left_over);
>> + kfree(iter);
>> + kfree(reader);
>> + return 0;
>> +}
>> +
>> +static inline unsigned long long ns2usecs(cycle_t nsec)
>> +{
>> + nsec += 500;
>> + do_div(nsec, 1000);
>> + return nsec;
>> +}
>> +
>> +static int trace_print_format(char *buf, struct trace_data *entry,
>> + int cpu , u64 ts)
>> +{
>> + int strlen = 0;
>> + unsigned long long t;
>> + unsigned long usecs_rem, secs;
>> +
>> + t = ns2usecs(ts);
>> + usecs_rem = do_div(t, USEC_PER_SEC);
>> + secs = (unsigned long)t;
>> + strlen += snprintf(buf, IGB_STR_BUF_LEN, "[%3d] %5lu.%06lu: ",
>> + cpu, secs, usecs_rem);
>> + if (entry->type < IGB_TRACE_EVENT_NUM)
>> + strlen += igb_trace_info_tbl[entry->type].read(buf + strlen,
>> + IGB_STR_BUF_LEN - strlen, entry);
>> + else
>> + strlen += snprintf(buf + strlen, IGB_STR_BUF_LEN - strlen,
>> + "type %u is not defined", entry->type);
>> + strlen += snprintf(buf + strlen, IGB_STR_BUF_LEN - strlen, "\n");
>> + return strlen;
>> +}
>> +
>> +static loff_t _igb_lseek_tb(struct trace_reader *reader, loff_t pos)
>> +{
>> + struct ring_buffer_iter **iter = reader->iter;
>> + struct ring_buffer_event *event;
>> + struct trace_data *entry;
>> + char str[IGB_STR_BUF_LEN];
>> + int cpu, next_cpu;
>> + u64 ts, next_ts;
>> + int exceed;
>> + int strlen;
>> +
>> + reader->idx = 0;
>> + for_each_online_cpu(cpu) {
>> + ring_buffer_iter_reset(iter[cpu]);
>> + }
>> + while (1) {
>> + next_ts = 0;
>> + next_cpu = -1;
>> + for_each_online_cpu(cpu) {
>> + if (!iter[cpu])
>> + continue;
>> + event = ring_buffer_iter_peek(iter[cpu], &ts);
>> + if (!event)
>> + continue;
>> + if (!next_ts || ts < next_ts) {
>> + next_ts = ts;
>> + next_cpu = cpu;
>> + }
>> + }
>> + if (next_cpu < 0)
>> + return -EINVAL;
>> + event = ring_buffer_read(iter[next_cpu], &ts);
>> + entry = ring_buffer_event_data(event);
>> + strlen = trace_print_format(str, entry, cpu, ts);
>> +
>> + if (reader->idx + strlen >= pos)
>> + break;
>> + reader->idx += strlen;
>> + }
>> + exceed = reader->idx + strlen - pos;
>> + if (exceed) {
>> + int from = strlen - exceed;
>> + memcpy(reader->left_over, str + from, exceed);
>> + }
>> + reader->left_over_len = exceed;
>> + reader->idx = pos;
>> + return pos;
>> +}
>> +
>> +/**
>> + * igb_lseek_tb - seek a ring_buffer
>> + * @file: The file pointer to attach the iter of ring_buffer
>> + * @offset: The offset to seek
>> + * @origin: absolute(0) or relative(1)
>> + **/
>> +
>> +static loff_t igb_lseek_tb(struct file *file, loff_t offset, int origin)
>> +{
>> + struct trace_reader *reader = file->private_data;
>> + loff_t ret = -EINVAL;
>> +
>> + mutex_lock(reader->trace_lock);
>> + switch (origin) {
>> + case 1:
>> + offset += file->f_pos;
>> + case 0:
>> + if (offset < 0)
>> + break;
>> + ret = _igb_lseek_tb(reader, offset);
>> + }
>> + if (ret > 0)
>> + file->f_pos = ret;
>> + mutex_unlock(reader->trace_lock);
>> + return ret;
>> +}
>> +
>> +/**
>> + * igb_read_tb - read a ring_buffer and transform print format
>> + * @file: The file pointer to attach the iter of ring_buffer
>> + * @buf: The buffer to copy to
>> + * @nbytes: The maximum number of bytes to read
>> + * @ppos: The position to read from
>> + **/
>> +
>> +static ssize_t igb_read_tb(struct file *file, char __user *buf,
>> + size_t nbytes, loff_t *ppos)
>> +{
>> + struct trace_reader *reader = file->private_data;
>> + struct ring_buffer_iter **iter = reader->iter;
>> + struct trace_data *entry;
>> + struct ring_buffer_event *event;
>> + loff_t pos = *ppos;
>> + u64 ts, next_ts = 0;
>> + int cpu, next_cpu = -1;
>> + char str[IGB_STR_BUF_LEN];
>> + unsigned int strlen = 0;
>> + size_t copy;
>> + int ret;
>> +
>> + mutex_lock(reader->trace_lock);
>> + if (pos != reader->idx)
>> + _igb_lseek_tb(reader, pos);
>> + if (reader->left_over_len) {
>> + copy = min(reader->left_over_len, nbytes);
>> + ret = copy_to_user(buf, reader->left_over,
>> + reader->left_over_len);
>> + copy -= ret;
>> + reader->left_over_len = ret;
>> + reader->idx += copy;
>> + *ppos += copy;
>> + mutex_unlock(reader->trace_lock);
>> + return reader->left_over_len - ret;
>> + }
>> + for_each_online_cpu(cpu) {
>> + if (!iter[cpu])
>> + continue;
>> + event = ring_buffer_iter_peek(iter[cpu], &ts);
>> + if (!event)
>> + continue;
>> + if (!next_ts || ts < next_ts) {
>> + next_ts = ts;
>> + next_cpu = cpu;
>> + }
>> + }
>> + if (next_cpu < 0) {
>> + mutex_unlock(reader->trace_lock);
>> + return 0;
>> + }
>> + event = ring_buffer_read(iter[next_cpu], &ts);
>> + entry = ring_buffer_event_data(event);
>> +
>> + strlen = trace_print_format(str, entry, next_cpu, ts);
>> + copy = min(strlen, nbytes);
>> + ret = copy_to_user(buf, str, strlen);
>> + copy -= ret;
>> + reader->left_over_len = ret;
>> + if (ret) {
>> + memcpy(reader->left_over, str + copy, ret);
>> + reader->left_over_len = ret;
>> + }
>> + *ppos = pos + copy;
>> + reader->idx = *ppos;
>> + mutex_unlock(reader->trace_lock);
>> + return copy;
>> +}
>> +
>> +static const struct file_operations igb_trace_file_ops = {
>> + .owner = THIS_MODULE,
>> + .open = igb_open_tb,
>> + .llseek = igb_lseek_tb,
>> + .read = igb_read_tb,
>> + .release = igb_release_tb,
>> +};
>> +
>> +/**
>> + * igb_open_trace_size - connect the pinter
>> + * @inode: The inode pointer that contains igb_adapter pointer
>> + * @file: The file pointer to attach the igb_adapter pointer
>> + **/
>> +
>> +static int igb_open_trace_size(struct inode *inode, struct file *file)
>> +{
>> + file->private_data = inode->i_private;
>> + return 0;
>> +}
>> +
>> +/**
>> + * igb_read_tb - print the size of ring_buffer byte unit to buf
>> + * if trace is disable, print 0
>> + * @file: The file pointer that contains an igb_adapter pointer
>> + * @buf: The buffer to copy to
>> + * @nbytes: The maximum number of bytes to read
>> + * @ppos: The position to read from
>> + **/
>> +
>> +static ssize_t igb_read_trace_size(struct file *file, char __user *ubuf,
>> + size_t nbytes, loff_t *ppos)
>> +{
>> + struct igb_adapter *adapter = file->private_data;
>> + struct igb_trace *trace = &adapter->trace;
>> + unsigned long size = trace->trace_size;
>> + char buf[16];
>> + int r;
>> +
>> + r = sprintf(buf, "%lu\n", size);
>> +
>> + return simple_read_from_buffer(ubuf, nbytes, ppos, buf, r);
>> +}
>> +
>> +/**
>> + * igb_trace_buffer_enable - enable trace and set ring_buffer size
>> + * @adapter: board private structure
>> + * @size: size of ring_buffer per cpu
>> + **/
>> +
>> +static int igb_trace_buffer_enable(struct igb_adapter *adapter,
>> ssize_t size)
>> +{
>> + struct igb_trace *trace = &adapter->trace;
>> + struct pci_dev *pdev = adapter->pdev;
>> +
>> + trace->trace_buffer = ring_buffer_alloc(size, RB_FL_OVERWRITE);
>> + if (!trace->trace_buffer) {
>> + dev_err(&pdev->dev, "Cannot alloc trace_buffer\n");
>> + return -EINVAL;
>> + }
>> + trace->trace_size = size;
>> + return 0;
>> +}
>> +
>> +/**
>> + * igb_trace_buffer_disable - disable trace
>> + * @adapter: board private structure
>> + **/
>> +
>> +static void igb_trace_buffer_disable(struct igb_adapter *adapter)
>> +{
>> + struct igb_trace *trace = &adapter->trace;
>> +
>> + ring_buffer_free(trace->trace_buffer);
>> + trace->trace_size = 0;
>> +}
>> +
>> +/**
>> + * igb_write_trace_size - write a ring_buffer size per cpu
>> + * if 0, disable trace
>> + * @file: Ther file pointer thar contains an igb_adapter pointer
>> + * @buf: The buffer to read and write for trace_size
>> + * @nbytes: size of buffe to read
>> + * @ppos: the position to read
>> + **/
>> +
>> +static ssize_t igb_write_trace_size(struct file *file, const char
>> __user *ubuf,
>> + size_t nbytes, loff_t *ppos)
>> +{
>> + struct igb_adapter *adapter = file->private_data;
>> + struct igb_trace *trace = &adapter->trace;
>> + unsigned long cur = trace->trace_size;
>> + int ret;
>> + unsigned long new;
>> + char buf[64];
>> +
>> + if (nbytes >= sizeof(buf))
>> + return -EINVAL;
>> +
>> + if (copy_from_user(&buf, ubuf, nbytes))
>> + return -EFAULT;
>> + buf[nbytes] = 0;
>> + ret = strict_strtoul(buf, 10, &new);
>> + if (ret < 0)
>> + return ret;
>> +
>> + mutex_lock(&trace->trace_lock);
>> + if (!cur && new) {
>> + igb_trace_buffer_enable(adapter, new);
>> + } else if (cur && !new) {
>> + igb_trace_buffer_disable(adapter);
>> + } else if (cur != new) {
>> + igb_trace_buffer_disable(adapter);
>> + igb_trace_buffer_enable(adapter, new);
>> + }
>> + mutex_unlock(&trace->trace_lock);
>> + return nbytes;
>> +}
>> +
>> +static const struct file_operations igb_trace_size_ops = {
>> + .owner = THIS_MODULE,
>> + .open = igb_open_trace_size,
>> + .read = igb_read_trace_size,
>> + .write = igb_write_trace_size,
>> +};
>> +
>> +static struct dentry *igb_trace_root;
>> +
>> +void igb_trace_init()
>> +{
>> + igb_trace_root = debugfs_create_dir("igb", NULL);
>> + if (!igb_trace_root) {
>> + printk(KERN_ERR "Cannot create debugfs\n");
>> + return;
>> + }
>> +}
>> +
>> +void igb_trace_exit(void)
>> +{
>> + if (igb_trace_root)
>> + debugfs_remove_recursive(igb_trace_root);
>> +}
>> +
>> +void igb_create_debugfs_file(struct igb_adapter *adapter)
>> +{
>> + struct net_device *netdev = adapter->netdev;
>> + struct igb_trace *trace = &adapter->trace;
>> + struct pci_dev *pdev = adapter->pdev;
>> +
>> + if (!igb_trace_root)
>> + return;
>> + trace->if_dir =
>> + debugfs_create_dir(netdev->name, igb_trace_root);
>> + if (!trace->if_dir) {
>> + dev_err(&pdev->dev, "Cannot create if_dir %s\n",
>> + netdev->name);
>> + goto err_alloc_dir;
>> + }
>> + trace->trace_file =
>> + debugfs_create_file("trace", S_IFREG|S_IRUGO|S_IWUSR,
>> + trace->if_dir,
>> + adapter, &igb_trace_file_ops);
>> + if (!trace->trace_file) {
>> + dev_err(&pdev->dev, "Cannot create debugfs for trace %s\n",
>> + netdev->name);
>> + goto err_alloc_trace;
>> + }
>> + trace->trace_size_file =
>> + debugfs_create_file("trace_size", S_IFREG|S_IRUGO|S_IWUSR,
>> + trace->if_dir,
>> + adapter, &igb_trace_size_ops);
>> + if (!trace->trace_file) {
>> + dev_err(&pdev->dev, "Cannot create debugfs for trace_size %s\n",
>> + netdev->name);
>> + goto err_alloc_trace_size;
>> + }
>> + mutex_init(&trace->trace_lock);
>> + return;
>> +
>> +err_alloc_trace_size:
>> + debugfs_remove(trace->trace_file);
>> +err_alloc_trace:
>> + debugfs_remove(trace->if_dir);
>> +err_alloc_dir:
>> + return;
>> +}
>> +
>> +void igb_remove_debugfs_file(struct igb_adapter *adapter)
>> +{
>> + struct igb_trace *trace = &adapter->trace;
>> +
>> + if (trace->trace_size_file)
>> + debugfs_remove(trace->trace_size_file);
>> + if (trace->trace_file)
>> + debugfs_remove(trace->trace_file);
>> + if (trace->if_dir)
>> + debugfs_remove(trace->if_dir);
>> +}
>> +
>> +/* function and struct for tracing xmit */
>> +struct trace_data_xmit {
>> + unsigned short type;
>> + u8 queue_index;
>> + u16 ntu;
>> + unsigned int first;
>> +};
>> +
>> +static void igb_write_tb_xmit(void *entry, void *data1, void *data2)
>> +{
>> + struct trace_data_xmit *td = entry;
>> + struct igb_ring *tx_ring = (struct igb_ring *)data1;
>> + unsigned int first = *(unsigned int *)data2;
>> +
>> + td->type = IGB_TRACE_XMIT;
>> + td->queue_index = tx_ring->queue_index;
>> + td->ntu = tx_ring->next_to_use;
>> + td->first = first;
>> +}
>> +
>> +static ssize_t igb_read_tb_xmit(char *str, size_t size, void *entry)
>> +{
>> + struct trace_data_xmit *t_data = entry;
>> +
>> + return snprintf(str, size, "xmit qidx=%u ntu=%u->%u",
>> + t_data->queue_index, t_data->first, t_data->ntu);
>> +}
>> +
>> +/* function and struct for tracing clean_tx */
>> +struct trace_data_clean_tx {
>> + unsigned short type;
>> + u8 queue_index;
>> + u16 ntc;
>> + unsigned int i;
>> +};
>> +
>> +static void igb_write_tb_clean_tx(void *entry, void *data1, void *data2)
>> +{
>> + struct trace_data_clean_tx *td = entry;
>> + struct igb_ring *tx_ring = (struct igb_ring *)data1;
>> + unsigned int i = *(unsigned int *)data2;
>> +
>> + td->type = IGB_TRACE_CLEAN_TX;
>> + td->queue_index = tx_ring->queue_index;
>> + td->ntc = tx_ring->next_to_clean;
>> + td->i = i;
>> +}
>> +
>> +static ssize_t igb_read_tb_clean_tx(char *str, size_t size, void *entry)
>> +{
>> + struct trace_data_clean_tx *t_data = entry;
>> +
>> + return snprintf(str, size, "clean_tx qidx=%u ntc=%u->%u",
>> + t_data->queue_index, t_data->ntc, t_data->i);
>> +}
>> +
>> +/* function and struct for tracing clean_rx */
>> +struct trace_data_clean_rx {
>> + unsigned short type;
>> + u8 queue_index;
>> + u16 ntc;
>> + unsigned int i;
>> +};
>> +
>> +static void igb_write_tb_clean_rx(void *entry, void *data1, void *data2)
>> +{
>> + struct trace_data_clean_rx *td = entry;
>> + struct igb_ring *rx_ring = (struct igb_ring *)data1;
>> + unsigned int i = *(unsigned int *)data2;
>> +
>> + td->type = IGB_TRACE_CLEAN_RX;
>> + td->queue_index = rx_ring->queue_index;
>> + td->ntc = rx_ring->next_to_clean;
>> + td->i = i;
>> +}
>> +
>> +static ssize_t igb_read_tb_clean_rx(char *str, size_t size, void *entry)
>> +{
>> + struct trace_data_clean_rx *t_data = entry;
>> +
>> + return snprintf(str, size, "clean_rx qidx=%u ntc=%u->%u",
>> + t_data->queue_index, t_data->ntc, t_data->i);
>> +}
>> +
>> +static struct igb_trace_info igb_trace_info_tbl[] = {
>> + {igb_write_tb_xmit, igb_read_tb_xmit,
>> + sizeof(struct trace_data_xmit)},
>> + {igb_write_tb_clean_tx, igb_read_tb_clean_tx,
>> + sizeof(struct trace_data_clean_tx)},
>> + {igb_write_tb_clean_rx, igb_read_tb_clean_rx,
>> + sizeof(struct trace_data_clean_rx)},
>> +};
>> diff --git a/drivers/net/igb/igb_trace.h b/drivers/net/igb/igb_trace.h
>> new file mode 100644
>> index 0000000..4e6a85b
>> --- /dev/null
>> +++ b/drivers/net/igb/igb_trace.h
>> @@ -0,0 +1,29 @@
>> +#ifndef _IGB_TRACE_H_
>> +#define _IGB_TRACE_H_
>> +
>> +#include <linux/module.h>
>> +#include <linux/ring_buffer.h>
>> +#include <linux/netdevice.h>
>> +#include <linux/pci.h>
>> +#include <linux/debugfs.h>
>> +#include "igb.h"
>> +
>> +#define IGB_TRACE_XMIT 0x00
>> +#define IGB_TRACE_CLEAN_TX 0x01
>> +#define IGB_TRACE_CLEAN_RX 0x02
>> +#define IGB_TRACE_EVENT_NUM 0x03
>> +
>> +extern void igb_trace_init(void);
>> +extern void igb_trace_exit(void);
>> +extern void igb_create_debugfs_file(struct igb_adapter *adapter);
>> +extern void igb_remove_debugfs_file(struct igb_adapter *adapter);
>> +extern void igb_write_tb(unsigned short type, struct igb_adapter
>> *adapter,
>> + void *data1, void *data2);
>> +
>> +#define IGB_WRITE_TRACE_BUFFER(type, adapter, data1, data2) \
>> + do { \
>> + if (adapter->trace.trace_size) \
>> + igb_write_tb(type, adapter, data1, data2); \
>> + } while (0)
>> +
>> +#endif /* _IGB_TRACE_H_ */
>>
>
>
>
^ permalink raw reply
* Re: [RFC PATCH net-next 1/5]IPv6:netfilter: defrag:Introduce net namespace
From: Shan Wei @ 2010-02-24 8:26 UTC (permalink / raw)
To: Alexey Dobriyan; +Cc: netdev
In-Reply-To: <b6fcc0a1002232348y6ff84ca8wf3bdf21de45fffbd@mail.gmail.com>
Alexey Dobriyan wrote, at 02/24/2010 03:48 PM:
>> - .procname = "nf_conntrack_frag6_timeout",
>> - .data = &nf_init_frags.timeout,
>> - .maxlen = sizeof(unsigned int),
>> - .mode = 0644,
>> - .proc_handler = proc_dointvec_jiffies,
>
> Why are you removing sysctls?
Because, after introduced net namespace, we can use net->ipv6.frags to
manage IPv6 conntrack fragment queue instead of nf_init_frags.
And sysctls of ip6frag_low_thresh, ip6frag_time and ip6frag_high_thresh
also can control IPv6 conntrack fragment queue.
So, private member of nf_init_frags becomes redundant, and remove these sysctls.
--
Best Regards
-----
Shan Wei
^ permalink raw reply
* Re: [RFC PATCH net-next 1/5]IPv6:netfilter: defrag:Introduce net namespace
From: Alexey Dobriyan @ 2010-02-24 7:48 UTC (permalink / raw)
To: shanwei; +Cc: netdev
> - .procname = "nf_conntrack_frag6_timeout",
> - .data = &nf_init_frags.timeout,
> - .maxlen = sizeof(unsigned int),
> - .mode = 0644,
> - .proc_handler = proc_dointvec_jiffies,
Why are you removing sysctls?
^ permalink raw reply
* Re: [PATCH 3/3] vhost: fix get_user_pages_fast error handling
From: David Miller @ 2010-02-24 7:41 UTC (permalink / raw)
To: mst
Cc: gleb, rusty, kvm, virtualization, netdev, linux-kernel, markmc,
herbert.xu, quintela, dlaor, avi
In-Reply-To: <20100224073424.GC27806@redhat.com>
From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Wed, 24 Feb 2010 09:34:25 +0200
> Implicitly, I guess. He said "if there's an issue Michael Tsirkin is the
> best person to resolve it", this was wrt merging his virtio&lguest tree.
> He didn't mention vhost, I wrote all of vhost though, there shouldn't be
> an issue with that.
That's good enough for me.
Feel free to setup a tree for me to pull from.
^ permalink raw reply
* Re: [PATCH 3/3] vhost: fix get_user_pages_fast error handling
From: Michael S. Tsirkin @ 2010-02-24 7:34 UTC (permalink / raw)
To: David Miller
Cc: markmc, kvm, quintela, netdev, linux-kernel, virtualization, avi,
herbert.xu
In-Reply-To: <20100223.230428.71578656.davem@davemloft.net>
On Tue, Feb 23, 2010 at 11:04:28PM -0800, David Miller wrote:
> From: "Michael S. Tsirkin" <mst@redhat.com>
> Date: Wed, 24 Feb 2010 07:37:37 +0200
>
> > Dave, so while Rusty's on vacation, what's the best way to get vhost
> > infrastructure fixes in? Are you ok with getting pull requests and
> > merging them into net-next? That should keep the clutter in your inbox
> > to the minimum.
> >
> > Of course network changes would still go the usual way.
>
> Well, who is providing oversight of vhost work while he's
> gone?
My plan was to get peer review of the patches before merging.
So far Juan Quintela and Gleb Natapov gave feedback.
> Has he, implicitly or explicitly, appointed a maintainer
> while he's away?
Implicitly, I guess. He said "if there's an issue Michael Tsirkin is the
best person to resolve it", this was wrt merging his virtio&lguest tree.
He didn't mention vhost, I wrote all of vhost though, there shouldn't be
an issue with that.
--
MST
^ permalink raw reply
* Re: [PATCH 3/3] vhost: fix get_user_pages_fast error handling
From: David Miller @ 2010-02-24 7:04 UTC (permalink / raw)
To: mst
Cc: gleb, rusty, kvm, virtualization, netdev, linux-kernel, markmc,
herbert.xu, quintela, dlaor, avi
In-Reply-To: <20100224053737.GB27806@redhat.com>
From: "Michael S. Tsirkin" <mst@redhat.com>
Date: Wed, 24 Feb 2010 07:37:37 +0200
> Dave, so while Rusty's on vacation, what's the best way to get vhost
> infrastructure fixes in? Are you ok with getting pull requests and
> merging them into net-next? That should keep the clutter in your inbox
> to the minimum.
>
> Of course network changes would still go the usual way.
Well, who is providing oversight of vhost work while he's
gone? Has he, implicitly or explicitly, appointed a maintainer
while he's away?
^ permalink raw reply
* [RFC PATCH net-next 5/5]IPv6:netfilter: Add IPSTATS_MIB_REASMFAILS MIB counter value when evicting fragment queue
From: Shan Wei @ 2010-02-24 6:08 UTC (permalink / raw)
To: Patrick McHardy, David Miller, Yasuyuki KOZAKAI
Cc: netdev@vger.kernel.org, netfilter-devel, Shan Wei
This patch adds MIB counter value about IPSTATS_MIB_REASMFAILS
if mem member of netns_frags exceeds high thresh, just like IPv4/v6 stack.
Signed-off-by: Shan Wei <shanwei@cn.fujitsu.com>
---
net/ipv6/netfilter/nf_conntrack_reasm.c | 10 +++++++---
1 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 32c5bbd..136b0de 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -113,9 +113,13 @@ static __inline__ void fq_kill(struct nf_ct_frag6_queue *fq)
inet_frag_kill(&fq->q, &nf_frags);
}
-static void nf_ct_frag6_evictor(struct net *net)
+static void nf_ct_frag6_evictor(struct net *net, struct inet6_dev *idev)
{
- inet_frag_evictor(&net->ipv6.frags, &nf_frags);
+ int evicted;
+
+ evicted = inet_frag_evictor(&net->ipv6.frags, &nf_frags);
+ if (evicted)
+ IP6_ADD_STATS_BH(net, idev, IPSTATS_MIB_REASMFAILS, evicted);
}
static void nf_ct_frag6_expire(unsigned long data)
@@ -632,7 +636,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user)
}
if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh)
- nf_ct_frag6_evictor(net);
+ nf_ct_frag6_evictor(net, idev);
fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr);
if (fq == NULL) {
--
1.6.3.3
^ permalink raw reply related
* [RFC PATCH net-next 4/5]IPv6:netfilter: Record MIB counter after a fragment reached
From: Shan Wei @ 2010-02-24 6:08 UTC (permalink / raw)
To: Patrick McHardy, David Miller, Yasuyuki KOZAKAI
Cc: netdev@vger.kernel.org, netfilter-devel, Shan Wei
This patch records MIB counter about fragments reassembly
after a fragment reached.
Note:
For the lack of memory, if fails to clone skb, pull skb or create fragment queue,
then not to forward skb to IPv6 stack, and drop it, just like IPv4.
Signed-off-by: Shan Wei <shanwei@cn.fujitsu.com>
---
net/ipv6/netfilter/nf_conntrack_reasm.c | 27 +++++++++++++++++++++------
1 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 9f50c13..32c5bbd 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -593,27 +593,31 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user)
u8 prevhdr;
struct sk_buff *ret_skb = NULL;
struct net *net = dev ? dev_net(dev) : dev_net(skb_dst(skb)->dev);
+ struct inet6_dev *idev;
+ idev = dev ? in6_dev_get(dev) : ip6_dst_idev(skb_dst(skb));
/* Jumbo payload inhibits frag. header */
if (ipv6_hdr(skb)->payload_len == 0) {
pr_debug("payload len = 0\n");
- return skb;
+ goto out_nofrag;
}
if (find_prev_fhdr(skb, &prevhdr, &nhoff, &fhoff) < 0)
- return skb;
+ goto out_nofrag;
+
+ IP6_INC_STATS(net, idev, IPSTATS_MIB_REASMREQDS);
clone = skb_clone(skb, GFP_ATOMIC);
if (clone == NULL) {
pr_debug("Can't clone skb\n");
- return skb;
+ goto out_drop_skb;
}
NFCT_FRAG6_CB(clone)->orig = skb;
if (!pskb_may_pull(clone, fhoff + sizeof(*fhdr))) {
pr_debug("message is too short.\n");
- goto ret_orig;
+ goto out_drop_skb;
}
skb_set_transport_header(clone, fhoff);
@@ -623,6 +627,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user)
if (!(fhdr->frag_off & htons(0xFFF9))) {
pr_debug("Invalid fragment offset\n");
/* It is not a fragmented frame */
+ IP6_INC_STATS(net, idev, IPSTATS_MIB_REASMOKS);
goto ret_orig;
}
@@ -632,7 +637,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user)
fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr);
if (fq == NULL) {
pr_debug("Can't find and can't create new queue\n");
- goto ret_orig;
+ goto out_drop_skb;
}
spin_lock(&fq->q.lock);
@@ -651,13 +656,23 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user)
pr_debug("Can't reassemble fragmented packets\n");
}
spin_unlock(&fq->q.lock);
-
+ if (dev && idev)
+ in6_dev_put(idev);
fq_put(fq);
return ret_skb;
ret_orig:
kfree_skb(clone);
+out_nofrag:
+ if (dev && idev)
+ in6_dev_put(idev);
return skb;
+out_drop_skb:
+ IP6_INC_STATS(net, idev, IPSTATS_MIB_REASMFAILS);
+ kfree_skb(clone);
+ kfree_skb(skb);
+ skb = NULL;
+ goto out_nofrag;
}
void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,
--
1.6.3.3
^ permalink raw reply related
* [RFC PATCH net-next 3/5]IPv6:netfilter: Record MIB counter when reassembling all fragments
From: Shan Wei @ 2010-02-24 6:08 UTC (permalink / raw)
To: David Miller, Patrick McHardy, Yasuyuki KOZAKAI
Cc: netdev@vger.kernel.org, netfilter-devel, Shan Wei
According to RFC4293, this patch records MIB counter of IPSTATS_MIB_REASMFAILS,
IPSTATS_MIB_REASMOKS, when reassembling fragments after all fragments reached.
Signed-off-by: Shan Wei <shanwei@cn.fujitsu.com>
---
net/ipv6/netfilter/nf_conntrack_reasm.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 4a1b5bd..9f50c13 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -398,6 +398,7 @@ static struct sk_buff *
nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
{
struct sk_buff *fp, *op, *head = fq->q.fragments;
+ struct net *net = container_of(fq->q.net, struct net, ipv6.frags);
int payload_len;
fq_kill(fq);
@@ -499,6 +500,9 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
NFCT_FRAG6_CB(fp)->orig = NULL;
}
+ rcu_read_lock();
+ IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
+ rcu_read_unlock();
return head;
out_oversize:
@@ -509,6 +513,9 @@ out_oom:
if (net_ratelimit())
printk(KERN_DEBUG "nf_ct_frag6_reasm: no memory for reassembly\n");
out_fail:
+ rcu_read_lock();
+ IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
+ rcu_read_unlock();
return NULL;
}
--
1.6.3.3
^ permalink raw reply related
* [RFC PATCH net-next 2/5]IPv6:netfilter: Send an ICMPv6 "Fragment Reassembly Timeout" message when enabling connection track
From: Shan Wei @ 2010-02-24 6:08 UTC (permalink / raw)
To: Yasuyuki KOZAKAI, Patrick McHardy, David Miller
Cc: netfilter-devel, netdev@vger.kernel.org, Shan Wei
An end host with IPv6 connection track enable should send an
ICMP "Fragment Reassembly Timeout" message when defraging timeout
according to the section 4.5 in RFC2460.
This patch supports it and adds counter value of Ip6ReasmTimeout and Ip6ReasmFails.
Quote Begin:
Section 4.5 in RFC2460.
If insufficient fragments are received to complete reassembly of a
packet within 60 seconds of the reception of the first-arriving
fragment of that packet, reassembly of that packet must be
abandoned and all the fragments that have been received for that
packet must be discarded. If the first fragment (i.e., the one
with a Fragment Offset of zero) has been received, an ICMP Time
Exceeded -- Fragment Reassembly Time Exceeded message should be
sent to the source of that fragment.
Quote End.
Signed-off-by: Shan Wei <shanwei@cn.fujitsu.com>
---
include/linux/skbuff.h | 5 +++
net/ipv6/netfilter/nf_conntrack_reasm.c | 48 ++++++++++++++++++++++++++++++-
net/ipv6/route.c | 1 +
3 files changed, 53 insertions(+), 1 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index ba0f8e3..e0b72e4 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -431,6 +431,11 @@ static inline struct rtable *skb_rtable(const struct sk_buff *skb)
return (struct rtable *)skb_dst(skb);
}
+static inline struct rt6_info *skb_r6table(const struct sk_buff *skb)
+{
+ return (struct rt6_info *)skb_dst(skb);
+}
+
extern void kfree_skb(struct sk_buff *skb);
extern void consume_skb(struct sk_buff *skb);
extern void __kfree_skb(struct sk_buff *skb);
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index b53083f..4a1b5bd 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -27,10 +27,12 @@
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <linux/random.h>
+#include <linux/ipv6_route.h>
#include <net/sock.h>
#include <net/snmp.h>
#include <net/inet_frag.h>
+#include <net/ip6_route.h>
#include <net/ipv6.h>
#include <net/protocol.h>
@@ -64,6 +66,7 @@ struct nf_ct_frag6_queue
struct in6_addr saddr;
struct in6_addr daddr;
+ int iif;
unsigned int csum;
__u16 nhoffset;
};
@@ -118,6 +121,8 @@ static void nf_ct_frag6_evictor(struct net *net)
static void nf_ct_frag6_expire(unsigned long data)
{
struct nf_ct_frag6_queue *fq;
+ struct net_device *dev = NULL;
+ struct net *net;
fq = container_of((struct inet_frag_queue *)data,
struct nf_ct_frag6_queue, q);
@@ -128,7 +133,44 @@ static void nf_ct_frag6_expire(unsigned long data)
goto out;
fq_kill(fq);
+ net = container_of(fq->q.net, struct net, ipv6.frags);
+ rcu_read_lock();
+ dev = dev_get_by_index_rcu(net, fq->iif);
+ if (!dev)
+ goto out_rcu_unlock;
+
+ IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT);
+ IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
+
+ /* Don't send error if the first segment did not arrive. */
+ if (!(fq->q.last_in & INET_FRAG_FIRST_IN) || !fq->q.fragments)
+ goto out_rcu_unlock;
+
+ /*
+ * Only search router table for the head fragment,
+ * when defraging timeout at PRE_ROUTING HOOK.
+ */
+ if (fq->user == IP6_DEFRAG_CONNTRACK_IN) {
+ struct sk_buff *head = fq->q.fragments;
+
+ head->dev = dev;
+ ip6_route_input(head);
+ if (!skb_dst(head))
+ goto out_rcu_unlock;
+
+ /*
+ * Only an end host needs to send an ICMP "Fragment Reassembly
+ * Timeout" message, per section 4.5 of RFC2460.
+ */
+ if (!(skb_r6table(head)->rt6i_flags & RTF_LOCAL))
+ goto out_rcu_unlock;
+ /* Send an ICMP "Fragment Reassembly Timeout" message. */
+ icmpv6_send(head, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0);
+ }
+
+out_rcu_unlock:
+ rcu_read_unlock();
out:
spin_unlock(&fq->q.lock);
fq_put(fq);
@@ -318,7 +360,11 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
else
fq->q.fragments = skb;
- skb->dev = NULL;
+ if (skb->dev) {
+ fq->iif = skb->dev->ifindex;
+ skb->dev = NULL;
+ }
+
fq->q.stamp = skb->tstamp;
fq->q.meat += skb->len;
atomic_add(skb->truesize, &fq->q.net->mem);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 88c0a5c..ef4bdd9 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -802,6 +802,7 @@ void ip6_route_input(struct sk_buff *skb)
skb_dst_set(skb, fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input));
}
+EXPORT_SYMBOL(ip6_route_input);
static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table,
struct flowi *fl, int flags)
--
1.6.3.3
^ permalink raw reply related
* [RFC PATCH net-next 1/5]IPv6:netfilter: defrag:Introduce net namespace to conntrack and share netns_frags with IPv6 stack
From: Shan Wei @ 2010-02-24 6:07 UTC (permalink / raw)
To: Patrick McHardy, David Miller, Yasuyuki KOZAKAI
Cc: netdev@vger.kernel.org, netfilter-devel, Shan Wei
Introduce net namespace to conntrack and share netns_frags with IPv6 stack.
Signed-off-by: Shan Wei <shanwei@cn.fujitsu.com>
---
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 7 +-
net/ipv6/netfilter/nf_conntrack_reasm.c | 79 +++++++-----------------
2 files changed, 25 insertions(+), 61 deletions(-)
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 996c3f4..f153b2c 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -221,7 +221,10 @@ static unsigned int ipv6_defrag(unsigned int hooknum,
if (skb->nfct && !nf_ct_is_template((struct nf_conn *)skb->nfct))
return NF_ACCEPT;
+ local_bh_disable();
reasm = nf_ct_frag6_gather(skb, nf_ct6_defrag_user(hooknum, skb));
+ local_bh_enable();
+
/* queued */
if (reasm == NULL)
return NF_STOLEN;
@@ -387,10 +390,6 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = {
.nlattr_to_tuple = ipv6_nlattr_to_tuple,
.nla_policy = ipv6_nla_policy,
#endif
-#ifdef CONFIG_SYSCTL
- .ctl_table_path = nf_net_netfilter_sysctl_path,
- .ctl_table = nf_ct_ipv6_sysctl_table,
-#endif
.me = THIS_MODULE,
};
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index ad1fcda..b53083f 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -69,34 +69,6 @@ struct nf_ct_frag6_queue
};
static struct inet_frags nf_frags;
-static struct netns_frags nf_init_frags;
-
-#ifdef CONFIG_SYSCTL
-struct ctl_table nf_ct_ipv6_sysctl_table[] = {
- {
- .procname = "nf_conntrack_frag6_timeout",
- .data = &nf_init_frags.timeout,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
- },
- {
- .procname = "nf_conntrack_frag6_low_thresh",
- .data = &nf_init_frags.low_thresh,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- {
- .procname = "nf_conntrack_frag6_high_thresh",
- .data = &nf_init_frags.high_thresh,
- .maxlen = sizeof(unsigned int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
- },
- { }
-};
-#endif
static unsigned int nf_hashfn(struct inet_frag_queue *q)
{
@@ -113,11 +85,12 @@ static void nf_skb_free(struct sk_buff *skb)
}
/* Memory Tracking Functions. */
-static inline void frag_kfree_skb(struct sk_buff *skb, unsigned int *work)
+static inline void
+frag_kfree_skb(struct netns_frags *nf, struct sk_buff *skb, unsigned int *work)
{
if (work)
*work -= skb->truesize;
- atomic_sub(skb->truesize, &nf_init_frags.mem);
+ atomic_sub(skb->truesize, &nf->mem);
nf_skb_free(skb);
kfree_skb(skb);
}
@@ -137,11 +110,9 @@ static __inline__ void fq_kill(struct nf_ct_frag6_queue *fq)
inet_frag_kill(&fq->q, &nf_frags);
}
-static void nf_ct_frag6_evictor(void)
+static void nf_ct_frag6_evictor(struct net *net)
{
- local_bh_disable();
- inet_frag_evictor(&nf_init_frags, &nf_frags);
- local_bh_enable();
+ inet_frag_evictor(&net->ipv6.frags, &nf_frags);
}
static void nf_ct_frag6_expire(unsigned long data)
@@ -166,7 +137,8 @@ out:
/* Creation primitives. */
static __inline__ struct nf_ct_frag6_queue *
-fq_find(__be32 id, u32 user, struct in6_addr *src, struct in6_addr *dst)
+fq_find(struct net *net, __be32 id, u32 user, struct in6_addr *src,
+ struct in6_addr *dst)
{
struct inet_frag_queue *q;
struct ip6_create_arg arg;
@@ -177,11 +149,10 @@ fq_find(__be32 id, u32 user, struct in6_addr *src, struct in6_addr *dst)
arg.src = src;
arg.dst = dst;
- read_lock_bh(&nf_frags.lock);
+ read_lock(&nf_frags.lock);
hash = inet6_hash_frag(id, src, dst, nf_frags.rnd);
- q = inet_frag_find(&nf_init_frags, &nf_frags, &arg, hash);
- local_bh_enable();
+ q = inet_frag_find(&net->ipv6.frags, &nf_frags, &arg, hash);
if (q == NULL)
goto oom;
@@ -334,7 +305,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
fq->q.fragments = next;
fq->q.meat -= free_it->len;
- frag_kfree_skb(free_it, NULL);
+ frag_kfree_skb(fq->q.net, free_it, NULL);
}
}
@@ -350,7 +321,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
skb->dev = NULL;
fq->q.stamp = skb->tstamp;
fq->q.meat += skb->len;
- atomic_add(skb->truesize, &nf_init_frags.mem);
+ atomic_add(skb->truesize, &fq->q.net->mem);
/* The first fragment.
* nhoffset is obtained from the first fragment, of course.
@@ -360,7 +331,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
fq->q.last_in |= INET_FRAG_FIRST_IN;
}
write_lock(&nf_frags.lock);
- list_move_tail(&fq->q.lru_list, &nf_init_frags.lru_list);
+ list_move_tail(&fq->q.lru_list, &fq->q.net->lru_list);
write_unlock(&nf_frags.lock);
return 0;
@@ -427,7 +398,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
clone->ip_summed = head->ip_summed;
NFCT_FRAG6_CB(clone)->orig = NULL;
- atomic_add(clone->truesize, &nf_init_frags.mem);
+ atomic_add(clone->truesize, &fq->q.net->mem);
}
/* We have to remove fragment header from datagram and to relocate
@@ -441,7 +412,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
skb_shinfo(head)->frag_list = head->next;
skb_reset_transport_header(head);
skb_push(head, head->data - skb_network_header(head));
- atomic_sub(head->truesize, &nf_init_frags.mem);
+ atomic_sub(head->truesize, &fq->q.net->mem);
for (fp=head->next; fp; fp = fp->next) {
head->data_len += fp->len;
@@ -451,7 +422,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
else if (head->ip_summed == CHECKSUM_COMPLETE)
head->csum = csum_add(head->csum, fp->csum);
head->truesize += fp->truesize;
- atomic_sub(fp->truesize, &nf_init_frags.mem);
+ atomic_sub(fp->truesize, &fq->q.net->mem);
}
head->next = NULL;
@@ -568,6 +539,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user)
int fhoff, nhoff;
u8 prevhdr;
struct sk_buff *ret_skb = NULL;
+ struct net *net = dev ? dev_net(dev) : dev_net(skb_dst(skb)->dev);
/* Jumbo payload inhibits frag. header */
if (ipv6_hdr(skb)->payload_len == 0) {
@@ -601,19 +573,19 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user)
goto ret_orig;
}
- if (atomic_read(&nf_init_frags.mem) > nf_init_frags.high_thresh)
- nf_ct_frag6_evictor();
+ if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh)
+ nf_ct_frag6_evictor(net);
- fq = fq_find(fhdr->identification, user, &hdr->saddr, &hdr->daddr);
+ fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr);
if (fq == NULL) {
pr_debug("Can't find and can't create new queue\n");
goto ret_orig;
}
- spin_lock_bh(&fq->q.lock);
+ spin_lock(&fq->q.lock);
if (nf_ct_frag6_queue(fq, clone, fhdr, nhoff) < 0) {
- spin_unlock_bh(&fq->q.lock);
+ spin_unlock(&fq->q.lock);
pr_debug("Can't insert skb to queue\n");
fq_put(fq);
goto ret_orig;
@@ -625,7 +597,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user)
if (ret_skb == NULL)
pr_debug("Can't reassemble fragmented packets\n");
}
- spin_unlock_bh(&fq->q.lock);
+ spin_unlock(&fq->q.lock);
fq_put(fq);
return ret_skb;
@@ -666,10 +638,6 @@ int nf_ct_frag6_init(void)
nf_frags.match = ip6_frag_match;
nf_frags.frag_expire = nf_ct_frag6_expire;
nf_frags.secret_interval = 10 * 60 * HZ;
- nf_init_frags.timeout = IPV6_FRAG_TIMEOUT;
- nf_init_frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
- nf_init_frags.low_thresh = IPV6_FRAG_LOW_THRESH;
- inet_frags_init_net(&nf_init_frags);
inet_frags_init(&nf_frags);
return 0;
@@ -678,7 +646,4 @@ int nf_ct_frag6_init(void)
void nf_ct_frag6_cleanup(void)
{
inet_frags_fini(&nf_frags);
-
- nf_init_frags.low_thresh = 0;
- nf_ct_frag6_evictor();
}
--
1.6.3.3
^ permalink raw reply related
* [RFC PATCH net-next 0/5]IPv6:netfilter: defragment
From: Shan Wei @ 2010-02-24 6:07 UTC (permalink / raw)
To: Patrick McHardy, David Miller, Yasuyuki KOZAKAI
Cc: netdev@vger.kernel.org, netfilter-devel
This patch-set solves the problem that an end host with IPv6 connection track enable
can't send an ICMP "Fragment Reassembly Timeout" message when defaging timeout.
And supports MIB counter about fragments reassembly e.g. Ip6ReasmTimeout, Ip6ReasmReqds,
Ip6ReasmOKs, Ip6ReasmFails.
patch-1: Introduce net namespace to conntrack and share netns_frags with IPv6 stack.
But, IPv6 conntrack and IPv6 stack still keep separate fragment queue.
Like IPv4, proc parameters of ip6frag_low_thresh, ip6frag_time and ip6frag_high_thresh
manage numbers and memory thresh size of both IPv6 conntrack fragment queue and
IPv6 stack fragment queue.
patch-2: Send an ICMP "Fragment Reassembly Timeout" message and record MIB counter
when defraging timeout.
patch-3,4,5: According to RFC4293, record MIB counter about fragments reassembly.
This patch-set has been tested using IPv6 Ready Logo Phase-2 tool under host and router type.
---
Shan Wei <shanwei@cn.fujitsu.com> (5):
IPv6:netfilter: defrag:Introduce net namespace to conntrack and share netns_frags with IPv6 stack
IPv6:netfilter: Send an ICMPv6 "Fragment Reassembly Timeout" message when enabling connection track
IPv6:netfilter: Record MIB counter when reassembling all fragments
IPv6:netfilter: Record MIB counter after a fragment reached
IPv6:netfilter: Add IPSTATS_MIB_REASMFAILS MIB counter value when evicting fragment queue
include/linux/skbuff.h | 5 +
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 7 +-
net/ipv6/netfilter/nf_conntrack_reasm.c | 165 +++++++++++++++---------
net/ipv6/route.c | 1 +
4 files changed, 110 insertions(+), 68 deletions(-)
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 3/3] vhost: fix get_user_pages_fast error handling
From: Michael S. Tsirkin @ 2010-02-24 5:37 UTC (permalink / raw)
To: David Miller
Cc: gleb, rusty, kvm, virtualization, netdev, linux-kernel, markmc,
herbert.xu, quintela, dlaor, avi
In-Reply-To: <20100223.144235.08984181.davem@davemloft.net>
On Tue, Feb 23, 2010 at 02:42:35PM -0800, David Miller wrote:
>
> Just for the record I'm generally not interested in vhost
> patches.
>
> If it's a specific network one that will be merged via
> the networking tree, yes please CC: me.
>
> But if it's a bunch of changes to vhost.c and other pieces
> of infrastructure, feel free to leave me out of it. It just
> clutters my already overflowing inbox.
>
> Thanks.
Dave, so while Rusty's on vacation, what's the best way to get vhost
infrastructure fixes in? Are you ok with getting pull requests and
merging them into net-next? That should keep the clutter in your inbox
to the minimum.
Of course network changes would still go the usual way.
--
MST
^ permalink raw reply
* Re: [net-next PATCH v5 2/3] sysctl: add proc_do_large_bitmap
From: Cong Wang @ 2010-02-24 5:34 UTC (permalink / raw)
To: Octavian Purdila
Cc: David Miller, Linux Kernel Network Developers,
Linux Kernel Developers, Eric W. Biederman
In-Reply-To: <4B84B7F0.7090709@redhat.com>
Cong Wang wrote:
>> diff --git a/kernel/sysctl.c b/kernel/sysctl.c
>> index 5259727..d8ea839 100644
>> --- a/kernel/sysctl.c
>> +++ b/kernel/sysctl.c
>> @@ -2635,6 +2635,140 @@ static int proc_do_cad_pid(struct ctl_table
>> *table, int write,
>
>
> The above line is wrong, it should be a part of previous line.
>
>
Sorry, ignore this, it should be my thunderbird's fault,
it truncated the line. I will fix it...
^ permalink raw reply
* Re: [net-next PATCH v5 2/3] sysctl: add proc_do_large_bitmap
From: Cong Wang @ 2010-02-24 5:24 UTC (permalink / raw)
To: Octavian Purdila
Cc: David Miller, Linux Kernel Network Developers,
Linux Kernel Developers, Eric W. Biederman
In-Reply-To: <201002221829.13987.opurdila@ixiacom.com>
Octavian Purdila wrote:
>
> Here is a new version of this patch which fixes both the comma and invalid
> value issues, please give it a try.
>
Sorry, it is even worse. :(
> [net-next PATCH v5 2/3] sysctl: add proc_do_large_bitmap
>
> The new function can be used to read/write large bitmaps via /proc. A
> comma separated range format is used for compact output and input
> (e.g. 1,3-4,10-10).
>
Writing "50000-50100" gets EINVAL, it should be success.
Writing "50000,50100" fails too.
Please, at least, do some basic testing.
Also some comments below.
> Writing into the file will first reset the bitmap then update it
> based on the given input.
>
> Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
> Cc: WANG Cong <amwang@redhat.com>
> Cc: Eric W. Biederman <ebiederm@xmission.com>
Please resend the whole patchset, and update the doc in patch 3/3.
> ---
> include/linux/sysctl.h | 2 +
> kernel/sysctl.c | 134
> ++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 136 insertions(+), 0 deletions(-)
>
> diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
> index f66014c..7bb5cb6 100644
> --- a/include/linux/sysctl.h
> +++ b/include/linux/sysctl.h
> @@ -980,6 +980,8 @@ extern int proc_doulongvec_minmax(struct ctl_table *, int,
> void __user *, size_t *, loff_t *);
> extern int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int,
> void __user *, size_t *, loff_t *);
> +extern int proc_do_large_bitmap(struct ctl_table *, int,
> + void __user *, size_t *, loff_t *);
>
> /*
> * Register a set of sysctl names by calling register_sysctl_table
> diff --git a/kernel/sysctl.c b/kernel/sysctl.c
> index 5259727..d8ea839 100644
> --- a/kernel/sysctl.c
> +++ b/kernel/sysctl.c
> @@ -2635,6 +2635,140 @@ static int proc_do_cad_pid(struct ctl_table *table,
> int write,
The above line is wrong, it should be a part of previous line.
> return 0;
> }
>
> +/**
> + * proc_do_large_bitmap - read/write from/to a large bitmap
> + * @table: the sysctl table
> + * @write: %TRUE if this is a write to the sysctl file
> + * @buffer: the user buffer
> + * @lenp: the size of the user buffer
> + * @ppos: file position
> + *
> + * The bitmap is stored at table->data and the bitmap length (in bits)
> + * in table->maxlen.
> + *
> + * We use a range comma separated format (e.g. 1,3-4,10-10) so that
> + * large bitmaps may be represented in a compact manner. Writing into
> + * the file will clear the bitmap then update it with the given input.
> + *
> + * Returns 0 on success.
> + */
> +int proc_do_large_bitmap(struct ctl_table *table, int write,
> + void __user *_buffer, size_t *lenp, loff_t *ppos)
> +{
> + bool first = 1;
> + unsigned long *bitmap = (unsigned long *) table->data;
> + unsigned long bitmap_len = table->maxlen;
> + int left = *lenp, err = 0;
'left' should be size_t.
> + char __user *buffer = (char __user *) _buffer;
> + char tr_a[] = { '-', ',', 0 }, tr_b[] = { ',', 0 }, c;
> +
> +
> + if (!bitmap_len || !left || (*ppos && !write)) {
> + *lenp = 0;
> + return 0;
> + }
> +
> + if (write) {
> + err = proc_skip_wspace(&buffer, &left);
> + while (!err && left) {
> + unsigned long val_a, val_b;
> + bool neg;
> +
> + err = proc_get_ulong(&buffer, &left, tr_a,
> + &val_a, &neg, &c);
> + if (err)
> + break;
> +
> + if (val_a >= bitmap_len || neg) {
> + err = -EINVAL;
> + break;
> + }
> +
> + val_b = val_a;
> + if (left && c == '-') {
> + /* skip the - */
> + buffer++; left--;
> +
> + err = proc_get_ulong(&buffer, &left, tr_b,
> + &val_b, &neg, &c);
> + if (err)
> + break;
> +
> + if (val_b >= bitmap_len || neg ||
> + val_a > val_b) {
> + err = -EINVAL;
> + break;
> + }
> + }
> +
> + if (left) {
> + err = proc_skip_wspace(&buffer, &left);
> + if (err)
> + break;
> + if (left) {
> + if (get_user(c, buffer)) {
> + err = -EFAULT;
> + break;
> + }
> + if (c != ',') {
> + err = -EINVAL;
> + break;
> + }
> + /* skip the , */
> + buffer++; left--;
> + }
> + }
> +
> + if (first)
> + bitmap_clear(bitmap, 0, bitmap_len);
> +
> + while (val_a <= val_b)
> + set_bit(val_a++, bitmap);
> +
> + first = 0;
> + }
> + if (!err)
> + err = proc_skip_wspace(&buffer, &left);
> + } else {
> + unsigned long bit_a, bit_b = 0;
> +
> + while (left) {
> + bit_a = find_next_bit(bitmap, bitmap_len, bit_b);
> + if (bit_a >= bitmap_len)
> + break;
> + bit_b = find_next_zero_bit(bitmap, bitmap_len,
> + bit_a + 1) - 1;
> +
> + err = proc_put_ulong(&buffer, &left, bit_a, 0, first,
> + ',');
> + if (err)
> + break;
> + if (bit_a != bit_b) {
> + err = proc_put_char(&buffer, &left, '-');
> + if (err)
> + break;
> + err = proc_put_ulong(&buffer, &left, bit_b, 0,
> + 1, 0);
> + if (err)
> + break;
> + }
> +
> + first = 0; bit_b++;
> + }
> + if (!err)
> + err = proc_put_char(&buffer, &left, '\n');
> + }
> +
> + if (first) {
> + if (err)
> + return err;
> + bitmap_clear(bitmap, 0, bitmap_len);
> + }
> + *lenp -= left;
> + *ppos += *lenp;
> + return 0;
> +}
> +
> #else /* CONFIG_PROC_FS */
>
> int proc_dostring(struct ctl_table *table, int write,
^ permalink raw reply
* linux-next: manual merge of the trivial tree with the net tree
From: Stephen Rothwell @ 2010-02-24 5:21 UTC (permalink / raw)
To: Jiri Kosina
Cc: linux-next, linux-kernel, Adam Buchbinder, Joe Perches,
David Miller, netdev
Hi Jiri,
Today's linux-next merge of the trivial tree got a conflict in
drivers/net/typhoon.c between commit
0bc88e4af07621bc4b84477374745d01a470e85d ("drivers/net/typhoon.c: Use (pr|
netdev)_<level> macro helpers") from the net tree and commit
a089377f29d3af0f62f3bdc6db0c5042513fc3f3 ("Fix misspelling of "truly" in
a label") from the trivial tree.
Just context changes. I fixed it up (see below) and can carry the fix as
necessary.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
diff --cc drivers/net/typhoon.c
index 38c2161,d1a8068..0000000
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@@ -2098,8 -2111,9 +2098,8 @@@ typhoon_tx_timeout(struct net_device *d
struct typhoon *tp = netdev_priv(dev);
if(typhoon_reset(tp->ioaddr, WaitNoSleep) < 0) {
- printk(KERN_WARNING "%s: could not reset in tx timeout\n",
- dev->name);
+ netdev_warn(dev, "could not reset in tx timeout\n");
- goto truely_dead;
+ goto truly_dead;
}
/* If we ever start using the Hi ring, it will need cleaning too */
@@@ -2107,8 -2121,9 +2107,8 @@@
typhoon_free_rx_rings(tp);
if(typhoon_start_runtime(tp) < 0) {
- printk(KERN_ERR "%s: could not start runtime in tx timeout\n",
- dev->name);
+ netdev_err(dev, "could not start runtime in tx timeout\n");
- goto truely_dead;
+ goto truly_dead;
}
netif_wake_queue(dev);
^ 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