* [PATCH 2.6.21.5-rt17] IPV6: estalished connections are not shown with "cat /proc/net/tcp6"
@ 2007-06-22 21:36 Masayuki Nakagawa
2007-06-23 7:13 ` Thomas Gleixner
2007-06-23 12:25 ` Steven Rostedt
0 siblings, 2 replies; 7+ messages in thread
From: Masayuki Nakagawa @ 2007-06-22 21:36 UTC (permalink / raw)
To: mingo; +Cc: linux-rt-users, dwalker
I found an issue regarding networking in the real-time patch (patch-2.6.21.5-rt17).
The issue happens only with the kernel, which the real-time patch was applied.
However, the latest stable main kernel (2.6.21.5) doesn't have the same issue.
Therefore, please don't transfer this report to netdev.
The detail of issue is below.
I ran my test program, which is a very simple IPv6 client-server program.
These programs establish a TCP/IPv6 connection between two hosts, and then sleep,
like following diagram.
And then, the problem appears with "cat /proc/net/tcp6".
serverA serverB
| SYN |
+--------------->+
| SYN/ACK |
+<---------------+
| ACK |
+--------------->+
| |
sleep... sleep...
| |
When I "cat /proc/net/tcp6" on serverA while establishing connection between serverA and B,
the established connections are not shown.
If you need my test program, please let me know. I can provide it to you.
However, in case of the main-line kernel, the established connections will be
shown appropriately with "cat /proc/net/tcp6". It's different because the
real-time patch has implemented a new socket lookup mechanism for a high-latency.
So, real-time patch has a different mechanism from main-line kernel.
The real-time patch, which implemented a new socket lookup mechanism is using
bitmap(ebitmask). When establishing TCP connection, it sets a flag bit into
the bitmap like followings.
[ebitmask in struct inet_hashinfo]
Before connecting
0000000000000000000000000000000000000000000000000000000000000000
After connecting
0000001000000000000000000000000000000000000000000000000000000000
^
And when reading "/proc/net/tcp and tcp6", the kernel searches the currently active
TCP connections with reference to the bitmap.
However, the kernel can't search the active TCP/IPv6 connection in established state.
It is because the kernel doesn't set a flag bit when establishing TCP/IPv6 connection.
In case of TCP/IPv4, __inet_hash() sets the flag bit properly with __inet_hash_setbit().
But, in case of TCP/IPv6, the setting the flag bit is missing in __inet6_hash().
[include/net/inet_hashtables.h]
static inline void __inet_hash(struct inet_hashinfo *hashinfo,
struct sock *sk, const int listen_possible)
{
struct hlist_head *list;
rwlock_t *lock;
unsigned long *bitmask = NULL;
unsigned int index = 0;
BUG_TRAP(sk_unhashed(sk));
if (listen_possible && sk->sk_state == TCP_LISTEN) {
list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
lock = &hashinfo->lhash_lock;
inet_listen_wlock(hashinfo);
} else {
struct inet_ehash_bucket *head;
sk->sk_hash = inet_sk_ehashfn(sk);
index = inet_ehash_index(hashinfo, sk->sk_hash);
head = inet_ehash_bucket(hashinfo, sk->sk_hash);
list = &head->chain;
lock = &head->lock;
bitmask = hashinfo->ebitmask;
write_lock(lock);
}
__sk_add_node(sk, list);
__inet_hash_setbit(bitmask, index);
sock_prot_inc_use(sk->sk_prot);
write_unlock(lock);
if (listen_possible && sk->sk_state == TCP_LISTEN)
wake_up(&hashinfo->lhash_wait);
}
[net/ipv6/inet6_hashtables.c]
void __inet6_hash(struct inet_hashinfo *hashinfo,
struct sock *sk)
{
struct hlist_head *list;
rwlock_t *lock;
printk("__inet6_hash hit\n");
BUG_TRAP(sk_unhashed(sk));
if (sk->sk_state == TCP_LISTEN) {
list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
lock = &hashinfo->lhash_lock;
inet_listen_wlock(hashinfo);
} else {
unsigned int hash;
sk->sk_hash = hash = inet6_sk_ehashfn(sk);
hash &= (hashinfo->ehash_size - 1);
list = &hashinfo->ehash[hash].chain;
lock = &hashinfo->ehash[hash].lock;
write_lock(lock);
}
__sk_add_node(sk, list);
sock_prot_inc_use(sk->sk_prot);
write_unlock(lock);
}
So, I suggest a following change.
The change is to set the flag bit appropriately in __inet6_hash().
Signed-off-by: Masayuki Nakagawa <nakagawa.msy@ncos.nec.co.jp>
Index: linus-kernel.git/net/ipv6/inet6_hashtables.c
===================================================================
--- linus-kernel.git.orig/net/ipv6/inet6_hashtables.c
+++ linus-kernel.git/net/ipv6/inet6_hashtables.c
@@ -27,6 +27,8 @@ void __inet6_hash(struct inet_hashinfo *
{
struct hlist_head *list;
rwlock_t *lock;
+ unsigned long *bitmask = NULL;
+ unsigned int index = 0;
BUG_TRAP(sk_unhashed(sk));
@@ -35,15 +37,16 @@ void __inet6_hash(struct inet_hashinfo *
lock = &hashinfo->lhash_lock;
inet_listen_wlock(hashinfo);
} else {
- unsigned int hash;
- sk->sk_hash = hash = inet6_sk_ehashfn(sk);
- hash &= (hashinfo->ehash_size - 1);
- list = &hashinfo->ehash[hash].chain;
- lock = &hashinfo->ehash[hash].lock;
+ sk->sk_hash = inet6_sk_ehashfn(sk);
+ index = inet_ehash_index(hashinfo, sk->sk_hash);
+ list = &hashinfo->ehash[index].chain;
+ lock = &hashinfo->ehash[index].lock;
+ bitmask = hashinfo->ebitmask;
write_lock(lock);
}
__sk_add_node(sk, list);
+ __inet_hash_setbit(bitmask, index);
sock_prot_inc_use(sk->sk_prot);
write_unlock(lock);
}
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2.6.21.5-rt17] IPV6: estalished connections are not shown with "cat /proc/net/tcp6"
2007-06-22 21:36 [PATCH 2.6.21.5-rt17] IPV6: estalished connections are not shown with "cat /proc/net/tcp6" Masayuki Nakagawa
@ 2007-06-23 7:13 ` Thomas Gleixner
2007-06-23 12:25 ` Steven Rostedt
1 sibling, 0 replies; 7+ messages in thread
From: Thomas Gleixner @ 2007-06-23 7:13 UTC (permalink / raw)
To: Masayuki Nakagawa; +Cc: mingo, linux-rt-users, dwalker, Steven Rostedt
On Fri, 2007-06-22 at 14:36 -0700, Masayuki Nakagawa wrote:
> So, I suggest a following change.
> The change is to set the flag bit appropriately in __inet6_hash().
>
> Signed-off-by: Masayuki Nakagawa <nakagawa.msy@ncos.nec.co.jp>
Thanks, applied.
tglx
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2.6.21.5-rt17] IPV6: estalished connections are not shown with "cat /proc/net/tcp6"
2007-06-22 21:36 [PATCH 2.6.21.5-rt17] IPV6: estalished connections are not shown with "cat /proc/net/tcp6" Masayuki Nakagawa
2007-06-23 7:13 ` Thomas Gleixner
@ 2007-06-23 12:25 ` Steven Rostedt
2007-07-09 16:53 ` Daniel Walker
1 sibling, 1 reply; 7+ messages in thread
From: Steven Rostedt @ 2007-06-23 12:25 UTC (permalink / raw)
To: Masayuki Nakagawa
Cc: mingo, linux-rt-users, dwalker, Thomas Gleixner, Lee Revell
Wow, a blast from the past :-)
I'm the original author of the hash code, and since I don't use ipv6
(yet) I must have missed it in my testing.
On Fri, 2007-06-22 at 14:36 -0700, Masayuki Nakagawa wrote:
> I found an issue regarding networking in the real-time patch (patch-2.6.21.5-rt17).
> The issue happens only with the kernel, which the real-time patch was applied.
> However, the latest stable main kernel (2.6.21.5) doesn't have the same issue.
> Therefore, please don't transfer this report to netdev.
>
> The detail of issue is below.
> I ran my test program, which is a very simple IPv6 client-server program.
> These programs establish a TCP/IPv6 connection between two hosts, and then sleep,
> like following diagram.
> And then, the problem appears with "cat /proc/net/tcp6".
>
> serverA serverB
> | SYN |
> +--------------->+
> | SYN/ACK |
> +<---------------+
> | ACK |
> +--------------->+
> | |
> sleep... sleep...
> | |
>
> When I "cat /proc/net/tcp6" on serverA while establishing connection between serverA and B,
> the established connections are not shown.
> If you need my test program, please let me know. I can provide it to you.
>
> However, in case of the main-line kernel, the established connections will be
> shown appropriately with "cat /proc/net/tcp6". It's different because the
> real-time patch has implemented a new socket lookup mechanism for a high-latency.
> So, real-time patch has a different mechanism from main-line kernel.
>
> The real-time patch, which implemented a new socket lookup mechanism is using
> bitmap(ebitmask). When establishing TCP connection, it sets a flag bit into
> the bitmap like followings.
>
> [ebitmask in struct inet_hashinfo]
> Before connecting
> 0000000000000000000000000000000000000000000000000000000000000000
> After connecting
> 0000001000000000000000000000000000000000000000000000000000000000
> ^
>
> And when reading "/proc/net/tcp and tcp6", the kernel searches the currently active
> TCP connections with reference to the bitmap.
>
> However, the kernel can't search the active TCP/IPv6 connection in established state.
> It is because the kernel doesn't set a flag bit when establishing TCP/IPv6 connection.
> In case of TCP/IPv4, __inet_hash() sets the flag bit properly with __inet_hash_setbit().
> But, in case of TCP/IPv6, the setting the flag bit is missing in __inet6_hash().
>
> [include/net/inet_hashtables.h]
> static inline void __inet_hash(struct inet_hashinfo *hashinfo,
> struct sock *sk, const int listen_possible)
> {
> struct hlist_head *list;
> rwlock_t *lock;
> unsigned long *bitmask = NULL;
> unsigned int index = 0;
>
> BUG_TRAP(sk_unhashed(sk));
> if (listen_possible && sk->sk_state == TCP_LISTEN) {
> list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
> lock = &hashinfo->lhash_lock;
> inet_listen_wlock(hashinfo);
> } else {
> struct inet_ehash_bucket *head;
> sk->sk_hash = inet_sk_ehashfn(sk);
> index = inet_ehash_index(hashinfo, sk->sk_hash);
> head = inet_ehash_bucket(hashinfo, sk->sk_hash);
> list = &head->chain;
> lock = &head->lock;
> bitmask = hashinfo->ebitmask;
> write_lock(lock);
> }
> __sk_add_node(sk, list);
> __inet_hash_setbit(bitmask, index);
> sock_prot_inc_use(sk->sk_prot);
> write_unlock(lock);
> if (listen_possible && sk->sk_state == TCP_LISTEN)
> wake_up(&hashinfo->lhash_wait);
> }
>
> [net/ipv6/inet6_hashtables.c]
> void __inet6_hash(struct inet_hashinfo *hashinfo,
> struct sock *sk)
> {
> struct hlist_head *list;
> rwlock_t *lock;
>
> printk("__inet6_hash hit\n");
>
> BUG_TRAP(sk_unhashed(sk));
>
> if (sk->sk_state == TCP_LISTEN) {
> list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
> lock = &hashinfo->lhash_lock;
> inet_listen_wlock(hashinfo);
> } else {
> unsigned int hash;
> sk->sk_hash = hash = inet6_sk_ehashfn(sk);
> hash &= (hashinfo->ehash_size - 1);
> list = &hashinfo->ehash[hash].chain;
> lock = &hashinfo->ehash[hash].lock;
> write_lock(lock);
> }
>
> __sk_add_node(sk, list);
> sock_prot_inc_use(sk->sk_prot);
> write_unlock(lock);
> }
>
> So, I suggest a following change.
> The change is to set the flag bit appropriately in __inet6_hash().
>
> Signed-off-by: Masayuki Nakagawa <nakagawa.msy@ncos.nec.co.jp>
>
Very nice investigation and solution.
>
> Index: linus-kernel.git/net/ipv6/inet6_hashtables.c
> ===================================================================
> --- linus-kernel.git.orig/net/ipv6/inet6_hashtables.c
> +++ linus-kernel.git/net/ipv6/inet6_hashtables.c
> @@ -27,6 +27,8 @@ void __inet6_hash(struct inet_hashinfo *
> {
> struct hlist_head *list;
> rwlock_t *lock;
> + unsigned long *bitmask = NULL;
> + unsigned int index = 0;
>
> BUG_TRAP(sk_unhashed(sk));
>
> @@ -35,15 +37,16 @@ void __inet6_hash(struct inet_hashinfo *
> lock = &hashinfo->lhash_lock;
> inet_listen_wlock(hashinfo);
> } else {
> - unsigned int hash;
> - sk->sk_hash = hash = inet6_sk_ehashfn(sk);
> - hash &= (hashinfo->ehash_size - 1);
> - list = &hashinfo->ehash[hash].chain;
> - lock = &hashinfo->ehash[hash].lock;
> + sk->sk_hash = inet6_sk_ehashfn(sk);
> + index = inet_ehash_index(hashinfo, sk->sk_hash);
> + list = &hashinfo->ehash[index].chain;
> + lock = &hashinfo->ehash[index].lock;
> + bitmask = hashinfo->ebitmask;
> write_lock(lock);
> }
>
> __sk_add_node(sk, list);
> + __inet_hash_setbit(bitmask, index);
> sock_prot_inc_use(sk->sk_prot);
> write_unlock(lock);
> }
I spent a few minutes looking at your changes and I don't see anything
wrong with it.
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Looking at the original patch, here's the reason for the bitmask:
--- linux-2.6.21.orig/net/ipv4/tcp_ipv4.c 2007-06-17 17:19:02.000000000 +0200
+++ linux-2.6.21/net/ipv4/tcp_ipv4.c 2007-06-17 17:20:27.000000000 +0200
@@ -2033,7 +2033,12 @@ static void *established_get_first(struc
struct tcp_iter_state* st = seq->private;
void *rc = NULL;
- for (st->bucket = 0; st->bucket < tcp_hashinfo.ehash_size; ++st->bucket) {
The above is a linear search through out a very large array, where most
of the items are NULL. I believe it was Lee that noticed this creating
a large latency. This was back in 2.6.14. I'll check to see if this
still is a source of latency with the latest kernels.
-- Steve
+ for (st->bucket = find_first_bit(tcp_hashinfo.ebitmask,
+ tcp_hashinfo.ehash_size);
+ st->bucket < tcp_hashinfo.ehash_size;
+ st->bucket = find_next_bit(tcp_hashinfo.ebitmask,
+ tcp_hashinfo.ehash_size,
+ st->bucket+1)) {
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2.6.21.5-rt17] IPV6: estalished connections are not shown with "cat /proc/net/tcp6"
2007-06-23 12:25 ` Steven Rostedt
@ 2007-07-09 16:53 ` Daniel Walker
0 siblings, 0 replies; 7+ messages in thread
From: Daniel Walker @ 2007-07-09 16:53 UTC (permalink / raw)
To: Steven Rostedt
Cc: Masayuki Nakagawa, mingo, linux-rt-users, Thomas Gleixner,
Lee Revell
On Sat, 2007-06-23 at 08:25 -0400, Steven Rostedt wrote:
> --- linux-2.6.21.orig/net/ipv4/tcp_ipv4.c 2007-06-17 17:19:02.000000000 +0200
> +++ linux-2.6.21/net/ipv4/tcp_ipv4.c 2007-06-17 17:20:27.000000000 +0200
> @@ -2033,7 +2033,12 @@ static void *established_get_first(struc
> struct tcp_iter_state* st = seq->private;
> void *rc = NULL;
>
> - for (st->bucket = 0; st->bucket < tcp_hashinfo.ehash_size; ++st->bucket) {
>
> The above is a linear search through out a very large array, where most
> of the items are NULL. I believe it was Lee that noticed this creating
> a large latency. This was back in 2.6.14. I'll check to see if this
> still is a source of latency with the latest kernels.
It looks fairly generic, is it a latency that could be fix the same way
up stream?
Daniel
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2.6.21.5-rt17] IPV6: estalished connections are not shown with "cat /proc/net/tcp6"
[not found] <46D4CED2.4060302@ncos.nec.co.jp>
@ 2007-08-29 4:56 ` David Miller
2007-08-29 12:36 ` Steven Rostedt
2007-08-29 12:31 ` Steven Rostedt
1 sibling, 1 reply; 7+ messages in thread
From: David Miller @ 2007-08-29 4:56 UTC (permalink / raw)
To: nakagawa.msy; +Cc: rostedt, dwalker, mingo, linux-rt-users, tglx, rlrevell
From: Masayuki Nakagawa <nakagawa.msy@ncos.nec.co.jp>
Date: Tue, 28 Aug 2007 18:41:38 -0700
> +static inline void __inet_hash_setbit(unsigned long *bitmask,
> + unsigned int index)
> +{
> + if (bitmask)
> + set_bit(index, bitmask);
> +}
> +
> +static inline void __inet_hash_clearbit(unsigned long *bitmask,
> + unsigned int index)
> +{
> + if (bitmask)
> + clear_bit(index, bitmask);
> +}
> +
A new atomic operation every single socket hashing insert or delete
operation is way too much amount of overhead for what should be a
trivial problem.
Please fix this in another way that does not add new locks or atomics
to the socket creation and destruction fast paths, thank you.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2.6.21.5-rt17] IPV6: estalished connections are not shown with "cat /proc/net/tcp6"
[not found] <46D4CED2.4060302@ncos.nec.co.jp>
2007-08-29 4:56 ` David Miller
@ 2007-08-29 12:31 ` Steven Rostedt
1 sibling, 0 replies; 7+ messages in thread
From: Steven Rostedt @ 2007-08-29 12:31 UTC (permalink / raw)
To: Masayuki Nakagawa; +Cc: dwalker, mingo, linux-rt-users, tglx, rlrevell
--
On Tue, 28 Aug 2007, Masayuki Nakagawa wrote:
> > On Sat, 2007-06-23 at 08:25 -0400, Steven Rostedt wrote:
> >
> >> --- linux-2.6.21.orig/net/ipv4/tcp_ipv4.c 2007-06-17 17:19:02.000000000 +0200
> >> +++ linux-2.6.21/net/ipv4/tcp_ipv4.c 2007-06-17 17:20:27.000000000 +0200
> >> @@ -2033,7 +2033,12 @@ static void *established_get_first(struc
> >> struct tcp_iter_state* st = seq->private;
> >> void *rc = NULL;
> >>
> >> - for (st->bucket = 0; st->bucket < tcp_hashinfo.ehash_size; ++st->bucket) {
> >>
> >> The above is a linear search through out a very large array, where most
> >> of the items are NULL. I believe it was Lee that noticed this creating
> >> a large latency. This was back in 2.6.14. I'll check to see if this
> >> still is a source of latency with the latest kernels.
> >
> > It looks fairly generic, is it a latency that could be fix the same way
> > up stream?
> >
> > Daniel
> >
> Hi Steven,
>
> I believe that we should push the following patch to upstream(netdev).
> (This is a patch which extracted a part of the hash code from real-time patch.)
> How do you think?
>
Hi Masayuki,
I really need to investigate if this is even still needed. This code was
originally added when a bh lock was held for the entire for loop. I see
that it is done per entry now. I'll take a look to see if there's a
better way to do this.
Thanks for bringing this back to the fore front.
-- Steve
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2.6.21.5-rt17] IPV6: estalished connections are not shown with "cat /proc/net/tcp6"
2007-08-29 4:56 ` David Miller
@ 2007-08-29 12:36 ` Steven Rostedt
0 siblings, 0 replies; 7+ messages in thread
From: Steven Rostedt @ 2007-08-29 12:36 UTC (permalink / raw)
To: David Miller; +Cc: nakagawa.msy, dwalker, mingo, linux-rt-users, tglx, rlrevell
--
When I'm asked what language is my mother tongue,
I simply answer "C".
On Tue, 28 Aug 2007, David Miller wrote:
> From: Masayuki Nakagawa <nakagawa.msy@ncos.nec.co.jp>
> Date: Tue, 28 Aug 2007 18:41:38 -0700
>
> > +static inline void __inet_hash_setbit(unsigned long *bitmask,
> > + unsigned int index)
> > +{
> > + if (bitmask)
> > + set_bit(index, bitmask);
> > +}
> > +
> > +static inline void __inet_hash_clearbit(unsigned long *bitmask,
> > + unsigned int index)
> > +{
> > + if (bitmask)
> > + clear_bit(index, bitmask);
> > +}
> > +
>
> A new atomic operation every single socket hashing insert or delete
> operation is way too much amount of overhead for what should be a
> trivial problem.
Indeed it is.
>
> Please fix this in another way that does not add new locks or atomics
> to the socket creation and destruction fast paths, thank you.
>
This was originally written back when there was a bh lock around the
entire loop (IIRC). It caused quite a bit of latency problems back then.
I'll have to take a look to see if it is even still a problem.
If it is, then we'll need to find another fix for it. Unfortunately, it's
not that trivial (if it is still a problem). Since we need a way to look a
a large number of buckets without looping through checking each one.
Lee, I think you were the one to notice this source of latency back when
it was first discovered. If I write a patch to back this out of the -rt
kernel, could you see if it is still an issue?
Thanks,
-- Steve
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2007-08-29 12:37 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-06-22 21:36 [PATCH 2.6.21.5-rt17] IPV6: estalished connections are not shown with "cat /proc/net/tcp6" Masayuki Nakagawa
2007-06-23 7:13 ` Thomas Gleixner
2007-06-23 12:25 ` Steven Rostedt
2007-07-09 16:53 ` Daniel Walker
[not found] <46D4CED2.4060302@ncos.nec.co.jp>
2007-08-29 4:56 ` David Miller
2007-08-29 12:36 ` Steven Rostedt
2007-08-29 12:31 ` Steven Rostedt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).