* Re: [PATCH net v2] net: tcp: move sk_rx_dst_set call after tcp_create_openreq_child()
From: David Miller @ 2012-08-20 10:04 UTC (permalink / raw)
To: eric.dumazet; +Cc: ncardwell, netdev, edumazet
In-Reply-To: <1345383675.5158.202.camel@edumazet-glaptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Sun, 19 Aug 2012 15:41:15 +0200
> On Sun, 2012-08-19 at 09:30 -0400, Neal Cardwell wrote:
>> This commit removes the sk_rx_dst_set calls from
>> tcp_create_openreq_child(), because at that point the icsk_af_ops
>> field of ipv6_mapped TCP sockets has not been set to its proper final
>> value.
>>
>> Instead, to make sure we get the right sk_rx_dst_set variant
>> appropriate for the address family of the new connection, we have
>> tcp_v{4,6}_syn_recv_sock() directly call the appropriate function
>> shortly after the call to tcp_create_openreq_child() returns.
>>
>> This also moves inet6_sk_rx_dst_set() to avoid a forward declaration
>> with the new approach.
>>
>> Signed-off-by: Neal Cardwell <ncardwell@google.com>
>> Reported-by: Artem Savkov <artem.savkov@gmail.com>
>> Cc: Eric Dumazet <edumazet@google.com>
>> ---
>> net/ipv4/tcp_ipv4.c | 1 +
>> net/ipv4/tcp_minisocks.c | 2 --
>> net/ipv6/tcp_ipv6.c | 25 +++++++++++++------------
>> 3 files changed, 14 insertions(+), 14 deletions(-)
>
> Thanks Neal !
>
> Acked-by: Eric Dumazet <edumazet@google.com>
Applied, thanks everyone.
^ permalink raw reply
* Re: [RFC PATCH 0/5] net: socket bind to file descriptor introduced
From: Stanislav Kinsbursky @ 2012-08-20 10:18 UTC (permalink / raw)
To: Eric W. Biederman
Cc: tglx@linutronix.de, mingo@redhat.com, davem@davemloft.net,
hpa@zytor.com, thierry.reding@avionic-design.de,
bfields@redhat.com, eric.dumazet@gmail.com, Pavel Emelianov,
neilb@suse.de, netdev@vger.kernel.org, x86@kernel.org,
linux-kernel@vger.kernel.org, paul.gortmaker@windriver.com,
viro@zeniv.linux.org.uk, gorcunov@openvz.org,
akpm@linux-foundation.org, tim.c.chen@linux.intel.com,
devel@openvz.org
In-Reply-To: <87y5lf7d37.fsf@xmission.com>
16.08.2012 07:03, Eric W. Biederman пишет:
> Stanislav Kinsbursky <skinsbursky@parallels.com> writes:
>
>> This patch set introduces new socket operation and new system call:
>> sys_fbind(), which allows to bind socket to opened file.
>> File to bind to can be created by sys_mknod(S_IFSOCK) and opened by
>> open(O_PATH).
>>
>> This system call is especially required for UNIX sockets, which has name
>> lenght limitation.
>>
>> The following series implements...
>
> Hmm. I just realized this patchset is even sillier than I thought.
>
> Stanislav is the problem you are ultimately trying to solve nfs clients
> in a container connecting to the wrong user space rpciod?
>
Hi, Eric.
The problem you mentioned was the reason why I started to think about this.
But currently I believe, that limitations in unix sockets connect or bind should
be removed, because it will be useful it least for CRIU project.
> Aka net/sunrpc/xprtsock.c:xs_setup_local only taking an absolute path
> and then creating a delayed work item to actually open the unix domain
> socket?
>
> The straight correct and straight forward thing to do appears to be:
> - Capture the root from current->fs in xs_setup_local.
> - In xs_local_finish_connect change current->fs.root to the captured
> version of root before kernel_connect, and restore current->fs.root
> after kernel_connect.
>
> It might not be a bad idea to implement open on unix domain sockets in
> a filesystem as create(AF_LOCAL)+connect() which would allow you to
> replace __sock_create + kernel_connect with a simple file_open_root.
>
I like the idea of introducing new family (AF_LOCAL_AT for example) and new
sockaddr for connecting or binding from specified root. The only thing I'm
worrying is passing file descriptor to unix bind or connect routine. Because
this approach doesn't provide easy way to use such family and sockaddr in kernel
(like in NFS example).
> But I think the simple scheme of:
> struct path old_root;
> old_root = current->fs.root;
> kernel_connect(...);
> current->fs.root = old_root;
>
> Is more than sufficient and will remove the need for anything
> except a purely local change to get nfs clients to connect from
> containers.
>
That was my first idea. And probably it would be worth to change all fs_struct
to support sockets with relative path.
What do you think about it?
> Eric
>
--
Best regards,
Stanislav Kinsbursky
^ permalink raw reply
* [PATCH] tcp: fix possible socket refcount problem
From: Eric Dumazet @ 2012-08-20 10:22 UTC (permalink / raw)
To: Fengguang Wu; +Cc: David Miller, networking
In-Reply-To: <1345380682.5158.201.camel@edumazet-glaptop>
From: Eric Dumazet <edumazet@google.com>
Commit 6f458dfb40 (tcp: improve latencies of timer triggered events)
added bug leading to following trace :
[ 2866.131281] IPv4: Attempt to release TCP socket in state 1 ffff880019ec0000
[ 2866.131726]
[ 2866.132188] =========================
[ 2866.132281] [ BUG: held lock freed! ]
[ 2866.132281] 3.6.0-rc1+ #622 Not tainted
[ 2866.132281] -------------------------
[ 2866.132281] kworker/0:1/652 is freeing memory ffff880019ec0000-ffff880019ec0a1f, with a lock still held there!
[ 2866.132281] (sk_lock-AF_INET-RPC){+.+...}, at: [<ffffffff81903619>] tcp_sendmsg+0x29/0xcc6
[ 2866.132281] 4 locks held by kworker/0:1/652:
[ 2866.132281] #0: (rpciod){.+.+.+}, at: [<ffffffff81083567>] process_one_work+0x1de/0x47f
[ 2866.132281] #1: ((&task->u.tk_work)){+.+.+.}, at: [<ffffffff81083567>] process_one_work+0x1de/0x47f
[ 2866.132281] #2: (sk_lock-AF_INET-RPC){+.+...}, at: [<ffffffff81903619>] tcp_sendmsg+0x29/0xcc6
[ 2866.132281] #3: (&icsk->icsk_retransmit_timer){+.-...}, at: [<ffffffff81078017>] run_timer_softirq+0x1ad/0x35f
[ 2866.132281]
[ 2866.132281] stack backtrace:
[ 2866.132281] Pid: 652, comm: kworker/0:1 Not tainted 3.6.0-rc1+ #622
[ 2866.132281] Call Trace:
[ 2866.132281] <IRQ> [<ffffffff810bc527>] debug_check_no_locks_freed+0x112/0x159
[ 2866.132281] [<ffffffff818a0839>] ? __sk_free+0xfd/0x114
[ 2866.132281] [<ffffffff811549fa>] kmem_cache_free+0x6b/0x13a
[ 2866.132281] [<ffffffff818a0839>] __sk_free+0xfd/0x114
[ 2866.132281] [<ffffffff818a08c0>] sk_free+0x1c/0x1e
[ 2866.132281] [<ffffffff81911e1c>] tcp_write_timer+0x51/0x56
[ 2866.132281] [<ffffffff81078082>] run_timer_softirq+0x218/0x35f
[ 2866.132281] [<ffffffff81078017>] ? run_timer_softirq+0x1ad/0x35f
[ 2866.132281] [<ffffffff810f5831>] ? rb_commit+0x58/0x85
[ 2866.132281] [<ffffffff81911dcb>] ? tcp_write_timer_handler+0x148/0x148
[ 2866.132281] [<ffffffff81070bd6>] __do_softirq+0xcb/0x1f9
[ 2866.132281] [<ffffffff81a0a00c>] ? _raw_spin_unlock+0x29/0x2e
[ 2866.132281] [<ffffffff81a1227c>] call_softirq+0x1c/0x30
[ 2866.132281] [<ffffffff81039f38>] do_softirq+0x4a/0xa6
[ 2866.132281] [<ffffffff81070f2b>] irq_exit+0x51/0xad
[ 2866.132281] [<ffffffff81a129cd>] do_IRQ+0x9d/0xb4
[ 2866.132281] [<ffffffff81a0a3ef>] common_interrupt+0x6f/0x6f
[ 2866.132281] <EOI> [<ffffffff8109d006>] ? sched_clock_cpu+0x58/0xd1
[ 2866.132281] [<ffffffff81a0a172>] ? _raw_spin_unlock_irqrestore+0x4c/0x56
[ 2866.132281] [<ffffffff81078692>] mod_timer+0x178/0x1a9
[ 2866.132281] [<ffffffff818a00aa>] sk_reset_timer+0x19/0x26
[ 2866.132281] [<ffffffff8190b2cc>] tcp_rearm_rto+0x99/0xa4
[ 2866.132281] [<ffffffff8190dfba>] tcp_event_new_data_sent+0x6e/0x70
[ 2866.132281] [<ffffffff8190f7ea>] tcp_write_xmit+0x7de/0x8e4
[ 2866.132281] [<ffffffff818a565d>] ? __alloc_skb+0xa0/0x1a1
[ 2866.132281] [<ffffffff8190f952>] __tcp_push_pending_frames+0x2e/0x8a
[ 2866.132281] [<ffffffff81904122>] tcp_sendmsg+0xb32/0xcc6
[ 2866.132281] [<ffffffff819229c2>] inet_sendmsg+0xaa/0xd5
[ 2866.132281] [<ffffffff81922918>] ? inet_autobind+0x5f/0x5f
[ 2866.132281] [<ffffffff810ee7f1>] ? trace_clock_local+0x9/0xb
[ 2866.132281] [<ffffffff8189adab>] sock_sendmsg+0xa3/0xc4
[ 2866.132281] [<ffffffff810f5de6>] ? rb_reserve_next_event+0x26f/0x2d5
[ 2866.132281] [<ffffffff8103e6a9>] ? native_sched_clock+0x29/0x6f
[ 2866.132281] [<ffffffff8103e6f8>] ? sched_clock+0x9/0xd
[ 2866.132281] [<ffffffff810ee7f1>] ? trace_clock_local+0x9/0xb
[ 2866.132281] [<ffffffff8189ae03>] kernel_sendmsg+0x37/0x43
[ 2866.132281] [<ffffffff8199ce49>] xs_send_kvec+0x77/0x80
[ 2866.132281] [<ffffffff8199cec1>] xs_sendpages+0x6f/0x1a0
[ 2866.132281] [<ffffffff8107826d>] ? try_to_del_timer_sync+0x55/0x61
[ 2866.132281] [<ffffffff8199d0d2>] xs_tcp_send_request+0x55/0xf1
[ 2866.132281] [<ffffffff8199bb90>] xprt_transmit+0x89/0x1db
[ 2866.132281] [<ffffffff81999bcd>] ? call_connect+0x3c/0x3c
[ 2866.132281] [<ffffffff81999d92>] call_transmit+0x1c5/0x20e
[ 2866.132281] [<ffffffff819a0d55>] __rpc_execute+0x6f/0x225
[ 2866.132281] [<ffffffff81999bcd>] ? call_connect+0x3c/0x3c
[ 2866.132281] [<ffffffff819a0f33>] rpc_async_schedule+0x28/0x34
[ 2866.132281] [<ffffffff810835d6>] process_one_work+0x24d/0x47f
[ 2866.132281] [<ffffffff81083567>] ? process_one_work+0x1de/0x47f
[ 2866.132281] [<ffffffff819a0f0b>] ? __rpc_execute+0x225/0x225
[ 2866.132281] [<ffffffff81083a6d>] worker_thread+0x236/0x317
[ 2866.132281] [<ffffffff81083837>] ? process_scheduled_works+0x2f/0x2f
[ 2866.132281] [<ffffffff8108b7b8>] kthread+0x9a/0xa2
[ 2866.132281] [<ffffffff81a12184>] kernel_thread_helper+0x4/0x10
[ 2866.132281] [<ffffffff81a0a4b0>] ? retint_restore_args+0x13/0x13
[ 2866.132281] [<ffffffff8108b71e>] ? __init_kthread_worker+0x5a/0x5a
[ 2866.132281] [<ffffffff81a12180>] ? gs_change+0x13/0x13
[ 2866.308506] IPv4: Attempt to release TCP socket in state 1 ffff880019ec0000
[ 2866.309689] =============================================================================
[ 2866.310254] BUG TCP (Not tainted): Object already free
[ 2866.310254] -----------------------------------------------------------------------------
[ 2866.310254]
The bug comes from the fact that timer set in sk_reset_timer() can run
before we actually do the sock_hold(). socket refcount reaches zero and
we free the socket too soon.
timer handler is not allowed to reduce socket refcnt if socket is owned
by the user, or we need to change sk_reset_timer() implementation.
We should take a reference on the socket in case TCP_DELACK_TIMER_DEFERRED
or TCP_DELACK_TIMER_DEFERRED bit are set in tsq_flags
Also fix a typo in tcp_delack_timer(), where TCP_WRITE_TIMER_DEFERRED
was used instead of TCP_DELACK_TIMER_DEFERRED.
For consistency, use same socket refcount change for TCP_MTU_REDUCED_DEFERRED,
even if not fired from a timer.
Reported-by: Fengguang Wu <fengguang.wu@intel.com>
Tested-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
net/ipv4/tcp_ipv4.c | 8 +++++---
net/ipv4/tcp_output.c | 14 +++++++++-----
net/ipv4/tcp_timer.c | 6 ++++--
3 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 7678237..6278a11 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -417,10 +417,12 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */
tp->mtu_info = info;
- if (!sock_owned_by_user(sk))
+ if (!sock_owned_by_user(sk)) {
tcp_v4_mtu_reduced(sk);
- else
- set_bit(TCP_MTU_REDUCED_DEFERRED, &tp->tsq_flags);
+ } else {
+ if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, &tp->tsq_flags))
+ sock_hold(sk);
+ }
goto out;
}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 20dfd89..d046326 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -910,14 +910,18 @@ void tcp_release_cb(struct sock *sk)
if (flags & (1UL << TCP_TSQ_DEFERRED))
tcp_tsq_handler(sk);
- if (flags & (1UL << TCP_WRITE_TIMER_DEFERRED))
+ if (flags & (1UL << TCP_WRITE_TIMER_DEFERRED)) {
tcp_write_timer_handler(sk);
-
- if (flags & (1UL << TCP_DELACK_TIMER_DEFERRED))
+ __sock_put(sk);
+ }
+ if (flags & (1UL << TCP_DELACK_TIMER_DEFERRED)) {
tcp_delack_timer_handler(sk);
-
- if (flags & (1UL << TCP_MTU_REDUCED_DEFERRED))
+ __sock_put(sk);
+ }
+ if (flags & (1UL << TCP_MTU_REDUCED_DEFERRED)) {
sk->sk_prot->mtu_reduced(sk);
+ __sock_put(sk);
+ }
}
EXPORT_SYMBOL(tcp_release_cb);
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 6df36ad..b774a03 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -252,7 +252,8 @@ static void tcp_delack_timer(unsigned long data)
inet_csk(sk)->icsk_ack.blocked = 1;
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED);
/* deleguate our work to tcp_release_cb() */
- set_bit(TCP_WRITE_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags);
+ if (!test_and_set_bit(TCP_DELACK_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags))
+ sock_hold(sk);
}
bh_unlock_sock(sk);
sock_put(sk);
@@ -481,7 +482,8 @@ static void tcp_write_timer(unsigned long data)
tcp_write_timer_handler(sk);
} else {
/* deleguate our work to tcp_release_cb() */
- set_bit(TCP_WRITE_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags);
+ if (!test_and_set_bit(TCP_WRITE_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags))
+ sock_hold(sk);
}
bh_unlock_sock(sk);
sock_put(sk);
^ permalink raw reply related
* Re: [PATCH 11/11] netlink: add documentation for memory mapped I/O
From: Jan Engelhardt @ 2012-08-20 10:32 UTC (permalink / raw)
To: Patrick McHardy; +Cc: Florian.Westphal, netdev, netfilter-devel
In-Reply-To: <1345443532-3707-12-git-send-email-kaber@trash.net>
On Monday 2012-08-20 08:18, Patrick McHardy wrote:
>+
>+RX and TX rings
>+----------------
>+
>+Each ring contains a number of continous memory blocks, containing frames of
>+fixed size dependant on the parameters used for ring setup.
dependent
>+The blocks are only visible to the kernel, from the point of view of user-space
>+the ring just contains the frames in a continous memory zone.
...to the kernel; from the user-space point of view, the ring...
continuous (multiple occurrences)
>+Ring frames
>+------------
>+
>+Each frames contain a frame header, consisting of a synchronization word and some
Each frame contains a frame header,
>+The possible values in the status word are:
>+
>+- NL_MMAP_STATUS_UNUSED:
>+ RX ring: frame belongs to the kernel and contains no message
The frame (mult)
>+ for user-space. Approriate action is to invoke poll()
>+ to wait for new messages.
The appropriate (mult)
>+ if (hdr->nm_status == NL_MMAP_STATUS_VALID)
>+ /* Regular memory mapped frame */
>+ nlh = (void *hdr) + NL_MMAP_HDRLEN;
(void *)hdr + NL_MMAP_HDRLEN
^ permalink raw reply
* Re: [PATCH 05/18] netfilter: nf_nat: add protoff argument to packet mangling functions
From: Patrick McHardy @ 2012-08-20 10:37 UTC (permalink / raw)
To: Jan Engelhardt; +Cc: netfilter-devel, netdev
In-Reply-To: <alpine.LNX.2.01.1208201000580.6101@frira.zrqbmnf.qr>
On Mon, 20 Aug 2012, Jan Engelhardt wrote:
>
> On Monday 2012-08-20 05:39, Patrick McHardy wrote:
>> index 0bb5a69..4b59a15 100644
>> --- a/include/linux/netfilter/nf_conntrack_amanda.h
>> +++ b/include/linux/netfilter/nf_conntrack_amanda.h
>> @@ -4,6 +4,7 @@
>>
>> extern unsigned int (*nf_nat_amanda_hook)(struct sk_buff *skb,
>> enum ip_conntrack_info ctinfo,
>> + unsigned int protoff,
>> unsigned int matchoff,
>> unsigned int matchlen,
>> struct nf_conntrack_expect *exp);
>
> What about using a structure to collect all the accumulating parameters,
> like we do for xtables match functions?
Yes, we could do that for the common parameters.
^ permalink raw reply
* Re: [PATCH 01/18] ipv4: fix path MTU discovery with connection tracking
From: Patrick McHardy @ 2012-08-20 10:59 UTC (permalink / raw)
To: Jan Engelhardt; +Cc: netfilter-devel, netdev
In-Reply-To: <alpine.LNX.2.01.1208201002270.6101@frira.zrqbmnf.qr>
On Mon, 20 Aug 2012, Jan Engelhardt wrote:
> On Monday 2012-08-20 05:39, Patrick McHardy wrote:
>
>> IPv4 conntrack defragments incoming packet at the PRE_ROUTING hook and
>> (in case of forwarded packets) refragments them at POST_ROUTING
>> independant of the IP_DF flag.
>
> "independent". (also in 06/18)
Fixed, thanks.
^ permalink raw reply
* Re: [PATCH v1 3/5] cgroup: Protect access to task_cls_classid() when built as module
From: Neil Horman @ 2012-08-20 11:08 UTC (permalink / raw)
To: Li Zefan
Cc: Daniel Wagner, netdev-u79uwXL29TY76Z2rM5mHXA,
cgroups-u79uwXL29TY76Z2rM5mHXA, Daniel Wagner, David S. Miller,
Gao feng, Jamal Hadi Salim, John Fastabend, Tejun Heo
In-Reply-To: <50318BF9.2080803-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
On Mon, Aug 20, 2012 at 08:59:37AM +0800, Li Zefan wrote:
> 于 2012/8/18 2:28, Neil Horman 写道:
> > On Fri, Aug 17, 2012 at 04:58:12PM +0200, Daniel Wagner wrote:
> >> From: Daniel Wagner <daniel.wagner-98C5kh4wR6ohFhg+JK9F0w@public.gmane.org>
> >>
> >> The module version of task_cls_classid() checks if net_cls_sbusys_id
> >> is valid to indentify when it is okay to access the controller.
> >>
> >> Instead relying on the subusys_id to be set, make it explicit
> >> with a jump label.
> >>
> >> Signed-off-by: Daniel Wagner <daniel.wagner-98C5kh4wR6ohFhg+JK9F0w@public.gmane.org>
> >> Cc: "David S. Miller" <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
> >> Cc: Gao feng <gaofeng-BthXqXjhjHXQFUHtdCDX3A@public.gmane.org>
> >> Cc: Jamal Hadi Salim <jhs-jkUAjuhPggJWk0Htik3J/w@public.gmane.org>
> >> Cc: John Fastabend <john.r.fastabend-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> >> Cc: Li Zefan <lizefan-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
> >> Cc: Neil Horman <nhorman-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
> >> Cc: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> >> Cc: netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> >> Cc: cgroups-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> >> ---
> >> include/net/cls_cgroup.h | 5 ++++-
> >> net/core/sock.c | 5 +++++
> >> net/sched/cls_cgroup.c | 9 +++++++++
> >> 3 files changed, 18 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h
> >> index 401672c..bbbd957 100644
> >> --- a/include/net/cls_cgroup.h
> >> +++ b/include/net/cls_cgroup.h
> >> @@ -16,6 +16,7 @@
> >> #include <linux/cgroup.h>
> >> #include <linux/hardirq.h>
> >> #include <linux/rcupdate.h>
> >> +#include <linux/jump_label.h>
> >>
> >> #ifdef CONFIG_CGROUPS
> >> struct cgroup_cls_state
> >> @@ -44,6 +45,8 @@ static inline u32 task_cls_classid(struct task_struct *p)
> >> }
> >>
> >> #elif IS_MODULE(CONFIG_NET_CLS_CGROUP)
> >> +extern struct static_key cgroup_cls_enabled;
> >> +#define clscg_enabled static_key_false(&cgroup_cls_enabled)
> >>
> >> extern int net_cls_subsys_id;
> >>
> >> @@ -52,7 +55,7 @@ static inline u32 task_cls_classid(struct task_struct *p)
> >> int id;
> >> u32 classid = 0;
> >>
> >> - if (in_interrupt())
> >> + if (!clscg_enabled || in_interrupt())
> >> return 0;
> >>
> >> rcu_read_lock();
> >> diff --git a/net/core/sock.c b/net/core/sock.c
> >> index 8f67ced..8106e77 100644
> >> --- a/net/core/sock.c
> >> +++ b/net/core/sock.c
> >> @@ -327,6 +327,11 @@ int __sk_backlog_rcv(struct sock *sk, struct sk_buff *skb)
> >> EXPORT_SYMBOL(__sk_backlog_rcv);
> >>
> >> #if defined(CONFIG_CGROUPS)
> >> +#if IS_MODULE(CONFIG_NET_CLS_CGROUP)
> >> +struct static_key cgroup_cls_enabled = STATIC_KEY_INIT_FALSE;
> >> +EXPORT_SYMBOL_GPL(cgroup_cls_enabled);
> >> +#endif
> >> +
> >> #if !defined(CONFIG_NET_CLS_CGROUP)
> >> int net_cls_subsys_id = -1;
> >> EXPORT_SYMBOL_GPL(net_cls_subsys_id);
> >> diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c
> >> index 7743ea8..0635894 100644
> >> --- a/net/sched/cls_cgroup.c
> >> +++ b/net/sched/cls_cgroup.c
> >> @@ -44,12 +44,21 @@ static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp)
> >>
> >> if (cgrp->parent)
> >> cs->classid = cgrp_cls_state(cgrp->parent)->classid;
> >> +#if IS_MODULE(CONFIG_NET_CLS_CGROUP)
> >> + else if (!clscg_enabled)
> >> + static_key_slow_inc(&cgroup_cls_enabled);
> > This is racy I think. The read of the static key is atomic with other reads,
> > but the entire conditional is not atomic. If two cpus were creating cgroups in
> > parallel, it would be possible for both to read the static key as being zero
> > (the second cpu would read the key before the first cpu could increment it).
>
> static_key_slow_inc() is called only when we're creating the root cgroup, and that's
> module loading.
>
> so it's safe.
>
What makes you say that? It appears to me that we call ss->create (and
potential ss->destroy, depending on failure conditions) from cgroup_create,
which in turn is called from cgroup_mkdir, which is called for every cgroup
instance created, not just the root cgroup.
Neil
^ permalink raw reply
* Re: [PATCH v1 3/5] cgroup: Protect access to task_cls_classid() when built as module
From: Daniel Wagner @ 2012-08-20 11:29 UTC (permalink / raw)
To: Neil Horman
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, cgroups-u79uwXL29TY76Z2rM5mHXA,
Daniel Wagner, David S. Miller, Gao feng, Jamal Hadi Salim,
John Fastabend, Li Zefan, Tejun Heo
In-Reply-To: <20120817182855.GA11607-B26myB8xz7F8NnZeBjwnZQMhkBWG/bsMQH7oEaQurus@public.gmane.org>
On Fri, Aug 17, 2012 at 02:28:55PM -0400, Neil Horman wrote:
> On Fri, Aug 17, 2012 at 04:58:12PM +0200, Daniel Wagner wrote:
> > From: Daniel Wagner <daniel.wagner-98C5kh4wR6ohFhg+JK9F0w@public.gmane.org>
> >
> > The module version of task_cls_classid() checks if net_cls_sbusys_id
> > is valid to indentify when it is okay to access the controller.
> >
> > Instead relying on the subusys_id to be set, make it explicit
> > with a jump label.
> >
> > Signed-off-by: Daniel Wagner <daniel.wagner-98C5kh4wR6ohFhg+JK9F0w@public.gmane.org>
> > Cc: "David S. Miller" <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
> > Cc: Gao feng <gaofeng-BthXqXjhjHXQFUHtdCDX3A@public.gmane.org>
> > Cc: Jamal Hadi Salim <jhs-jkUAjuhPggJWk0Htik3J/w@public.gmane.org>
> > Cc: John Fastabend <john.r.fastabend-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
> > Cc: Li Zefan <lizefan-hv44wF8Li93QT0dZR+AlfA@public.gmane.org>
> > Cc: Neil Horman <nhorman-2XuSBdqkA4R54TAoqtyWWQ@public.gmane.org>
> > Cc: Tejun Heo <tj-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> > Cc: netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> > Cc: cgroups-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> > ---
> > include/net/cls_cgroup.h | 5 ++++-
> > net/core/sock.c | 5 +++++
> > net/sched/cls_cgroup.c | 9 +++++++++
> > 3 files changed, 18 insertions(+), 1 deletion(-)
> >
> > diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h
> > index 401672c..bbbd957 100644
> > --- a/include/net/cls_cgroup.h
> > +++ b/include/net/cls_cgroup.h
> > @@ -16,6 +16,7 @@
> > #include <linux/cgroup.h>
> > #include <linux/hardirq.h>
> > #include <linux/rcupdate.h>
> > +#include <linux/jump_label.h>
> >
> > #ifdef CONFIG_CGROUPS
> > struct cgroup_cls_state
> > @@ -44,6 +45,8 @@ static inline u32 task_cls_classid(struct task_struct *p)
> > }
> >
> > #elif IS_MODULE(CONFIG_NET_CLS_CGROUP)
> > +extern struct static_key cgroup_cls_enabled;
> > +#define clscg_enabled static_key_false(&cgroup_cls_enabled)
> >
> > extern int net_cls_subsys_id;
> >
> > @@ -52,7 +55,7 @@ static inline u32 task_cls_classid(struct task_struct *p)
> > int id;
> > u32 classid = 0;
> >
> > - if (in_interrupt())
> > + if (!clscg_enabled || in_interrupt())
> > return 0;
> >
> > rcu_read_lock();
> > diff --git a/net/core/sock.c b/net/core/sock.c
> > index 8f67ced..8106e77 100644
> > --- a/net/core/sock.c
> > +++ b/net/core/sock.c
> > @@ -327,6 +327,11 @@ int __sk_backlog_rcv(struct sock *sk, struct sk_buff *skb)
> > EXPORT_SYMBOL(__sk_backlog_rcv);
> >
> > #if defined(CONFIG_CGROUPS)
> > +#if IS_MODULE(CONFIG_NET_CLS_CGROUP)
> > +struct static_key cgroup_cls_enabled = STATIC_KEY_INIT_FALSE;
> > +EXPORT_SYMBOL_GPL(cgroup_cls_enabled);
> > +#endif
> > +
> > #if !defined(CONFIG_NET_CLS_CGROUP)
> > int net_cls_subsys_id = -1;
> > EXPORT_SYMBOL_GPL(net_cls_subsys_id);
> > diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c
> > index 7743ea8..0635894 100644
> > --- a/net/sched/cls_cgroup.c
> > +++ b/net/sched/cls_cgroup.c
> > @@ -44,12 +44,21 @@ static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp)
> >
> > if (cgrp->parent)
> > cs->classid = cgrp_cls_state(cgrp->parent)->classid;
> > +#if IS_MODULE(CONFIG_NET_CLS_CGROUP)
> > + else if (!clscg_enabled)
> > + static_key_slow_inc(&cgroup_cls_enabled);
> This is racy I think. The read of the static key is atomic with other reads,
> but the entire conditional is not atomic. If two cpus were creating cgroups in
> parallel, it would be possible for both to read the static key as being zero
> (the second cpu would read the key before the first cpu could increment it).
D'oh, That is racy.
> > +#endif
> >
> > return &cs->css;
> > }
> >
> > static void cgrp_destroy(struct cgroup *cgrp)
> > {
> > +#if IS_MODULE(CONFIG_NET_CLS_CGROUP)
> > + if (!cgrp->parent && clscg_enabled)
> > + static_key_slow_dec(&cgroup_cls_enabled);
> Ditto here with the race above. I think what you want is one of:
>
> 1) Use static_key_slow_[inc|dec] unconditionally
While the static_key_slow_inc() case will work, I am not so sure about
the static_key_slow_dec(), e.g. we could still access inside
task_cls_classid() a destroyed container.
> 2) Keep a separate internal counter to track the number of cgroup instances
> so that you only inc the static key on the first create and dec it on the last
> delete.
If I got you right, than this would not be different then direclty using
static_key_slow_[inc|dec].
> I would think (1) would be sufficent. It looks like static_key_slow_inc uses
> atomic_inc_not_zero to just do an inc anyway in the event that multiple inc
> events are made.
Would something like this work?
static inline u32 task_cls_classid(struct task_struct *p)
{
u32 classid;
struct cgroup_cls_state *css;
if (!clscg_enabled || in_interrupt())
return 0;
rcu_read_lock();
css = container_of(task_subsys_state(p, net_cls_subsys_id),
struct cgroup_cls_state, css);
if (!css)
classid = css->classid;
else
classid = 0;
rcu_read_unlock();
return classid;
}
Daniel
^ permalink raw reply
* Re: [PATCH v1 3/5] cgroup: Protect access to task_cls_classid() when built as module
From: Glauber Costa @ 2012-08-20 11:33 UTC (permalink / raw)
To: Daniel Wagner
Cc: Neil Horman, netdev-u79uwXL29TY76Z2rM5mHXA,
cgroups-u79uwXL29TY76Z2rM5mHXA, Daniel Wagner, David S. Miller,
Gao feng, Jamal Hadi Salim, John Fastabend, Li Zefan, Tejun Heo
In-Reply-To: <20120820112938.GA22415-rjQKm2AMs/APuY3F5OKgMy7zKzJi9e1+kcYEyfhdaNw@public.gmane.org>
On 08/20/2012 03:29 PM, Daniel Wagner wrote:
>> This is racy I think. The read of the static key is atomic with other reads,
>> > but the entire conditional is not atomic. If two cpus were creating cgroups in
>> > parallel, it would be possible for both to read the static key as being zero
>> > (the second cpu would read the key before the first cpu could increment it).
> D'oh, That is racy.
>
Take a look at how we solve this particular problem in memcg. By using a
pair of bits meaning "ever active" and "currently active", we can avoid
problems with the static key increments.
Nothing bad can't happen by increasing the static key more than once;
the problem is that you need to somehow take note of that to make sure
you decrement the as many times you incremented when you release it.
Two other important things to keep in mind while dealing with static
branches:
* You can't increase/decrease while holding the cgroup_lock. lockdep may
trigger, because the cgroup_lock holds the cpu_hotplug lock, that the
static branches update path will also take. (due to cpusets). Doing a
logical hotplug will stress this path, and make the problem visible.
Take a look at disarm_sock_keys() (mm/memcontrol.c) to see how we solve
this particular problem.
* If you have code in more than one call site, the update among them is
not atomic. Not sure if this one applies to your case, but it can lead
you to some very unpleasant to debug problems. We use one of those two
bits I mentioned ("currently active") to make sure objects are not
marked before all sites are already patched.
Hope our previous experience with this can help you.
^ permalink raw reply
* Re: [RFC PATCH 1/1] fair.c: Add/Export find_idlest_perfer_cpu API
From: Peter Zijlstra @ 2012-08-20 12:00 UTC (permalink / raw)
To: Shirley Ma; +Cc: linux-kernel, mingo, Michael S. Tsirkin, netdev, sri, vivek
In-Reply-To: <1345232770.16533.234.camel@oc3660625478.ibm.com>
On Fri, 2012-08-17 at 12:46 -0700, Shirley Ma wrote:
> Add/Export a new API for per-cpu thread model networking device driver
> to choose a preferred idlest cpu within allowed cpumask.
>
> The receiving CPUs of a networking device are not under cgroup controls.
> Normally the receiving work will be scheduled on the cpu on which the
> interrupts are received. When such a networking device uses per-cpu
> thread model, the cpu which is chose to process the packets might not be
> part of cgroup cpusets without using such an API here.
>
> On NUMA system, by using the preferred cpumask from the same NUMA node
> would help to reduce expensive cross memory access to/from the other
> NUMA node.
>
> KVM per-cpu vhost will be the first one to use this API. Any other
> device driver which uses per-cpu thread model and has cgroup cpuset
> control will use this API later.
How often will this be called and how do you obtain the cpumasks
provided to the function?
^ permalink raw reply
* Re: [PATCH] ipv4: Use netinet->inet_opt in inet_csk_route_child_sock()
From: Christoph Paasch @ 2012-08-20 12:11 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20120820.025147.936465141809418575.davem@davemloft.net>
On Monday 20 August 2012 02:51:47 David Miller wrote:
> From: Christoph Paasch <christoph.paasch@uclouvain.be>
> Date: Fri, 17 Aug 2012 23:35:12 +0200
>
> > @@ -404,7 +404,7 @@ struct dst_entry *inet_csk_route_child_sock(struct
> > sock *sk,>
> > {
> > const struct inet_request_sock *ireq = inet_rsk(req);
> > struct inet_sock *newinet = inet_sk(newsk);
> >
> > - struct ip_options_rcu *opt = ireq->opt;
> > + struct ip_options_rcu *opt = rcu_dereference(newinet->inet_opt);
> >
> > struct net *net = sock_net(sk);
>
> We're not inside of a rcu_read_lock() protected section, so this access
> is not legitimate. If you enabled RCU lock debugging, you would have
> triggered a warning in the kernel log.
Oh, sorry... I will resubmit a v2.
Although, I enabled CONFIG_PROVE_RCU (and all other RCU-related debug I could
find) and no warning was triggered.
By the way, in dccp_v4_request_recv_sock() is the code:
newinet->inet_opt = ireq->opt;
Shouldn't this rather be an rcu_assign_pointer() ?
And in cipso_v4_sock_delattr() I believe we should also rather access 'opt'
instead of doing cipso_v4_delopt(&sk_inet->inet_opt) ?
Christoph
--
IP Networking Lab --- http://inl.info.ucl.ac.be
MultiPath TCP in the Linux Kernel --- http://mptcp.info.ucl.ac.be
Université Catholique de Louvain
--
^ permalink raw reply
* Re: [PATCH 1/2] ipv6: do not hold route table lock when send ndisc probe
From: Cong Wang @ 2012-08-20 12:15 UTC (permalink / raw)
To: Debabrata Banerjee
Cc: netdev, Banerjee, Debabrata, David S. Miller, Hideaki YOSHIFUJI,
Patrick McHardy
In-Reply-To: <CAATkVEzKuTeUbU75B6EoSfFvGVsz_eK47XNWmsP5KcCvjTDEDA@mail.gmail.com>
On Fri, 2012-08-17 at 14:54 -0400, Debabrata Banerjee wrote:
> Well it get rids of the deadlock for sure, but I am not sure it
> doesn't break something else, one would have to know all of this code
> much better to tell. You'll notice read_unlock_bh(&table->tb6_lock)
> for the first lock in ip6_pol_route() has more in the critical section
> after the rt6_select() call, especially that rather scary BACKTRACK()
> macro.
>
Yeah, I noticed that, ->tb6_lock seems to protect lookup of ->tb6_root,
not sure if 'rt' may still valid after retaking this lock... Hmm,
probably calling ndisc_send_ns() inside a work is a better approach.
I will update the patch.
Thanks!
^ permalink raw reply
* WARNING: at include/net/mac80211.h:3630 rate_control_send_low+0xc1/0x1a1
From: Arnd Hannemann @ 2012-08-20 12:51 UTC (permalink / raw)
To: linux-wireless-u79uwXL29TY76Z2rM5mHXA; +Cc: netdev
Hi,
I just observed the above kernel warning after issuing an "wpa_cli reassociate",
followed by some "iwconfig" calls to check the status.
Kernel is 3.4.7, Hardware is x86 (32bit) and ath9k
WARNING comes from inline function "rate_lowest_index":
3629 /* warn when we cannot find a rate. */
3630 WARN_ON_ONCE(1);
Full stacktrace below:
[1793205.090602] wlan0: deauthenticating from XX:XX:XX:XX:XX:XX by local choice (reason=3)
[1793205.090754] ------------[ cut here ]------------
[1793205.105295] WARNING: at include/net/mac80211.h:3630 rate_control_send_low+0xc1/0x1a1 [mac80211]()
[1793205.132424] Modules linked in: aes_generic xt_TCPMSS ipt_ULOG ipt_MASQUERADE xt_LOG xt_time xt_connlimit xt_helper xt_realm xt_NFQUEUE xt_tcpmss xt_addrtype xt_pkttype iptab
le_raw xt_TPROXY nf_tproxy_core ip6_tables nf_defrag_ipv6 xt_hashlimit xt_comment xt_length xt_connmark xt_owner xt_recent xt_iprange xt_physdev xt_policy xt_multiport iptable_na
t nf_nat xt_conntrack nf_conntrack_tftp nf_conntrack_sip nf_conntrack_proto_sctp nf_conntrack_pptp nf_conntrack_proto_gre nf_conntrack_netlink nfnetlink nf_conntrack_irc nf_connt
rack_h323 nf_conntrack_ftp nf_conntrack_ipv4 nf_defrag_ipv4 nf_conntrack ath9k ath5k ath9k_common ath9k_hw mac80211 ath ohci_hcd ehci_hcd cfg80211
[1793205.313648] Pid: 1959, comm: wpa_supplicant Not tainted 3.4.7-ela1 #1
[1793205.333502] Call Trace:
[1793205.341407] [<c1016dee>] warn_slowpath_common+0x65/0x7a
[1793205.357935] [<d094178b>] ? rate_control_send_low+0xc1/0x1a1 [mac80211]
[1793205.378312] [<c1016e12>] warn_slowpath_null+0xf/0x13
[1793205.394073] [<d094178b>] rate_control_send_low+0xc1/0x1a1 [mac80211]
[1793205.414008] [<d095af6c>] minstrel_ht_get_rate+0x25/0x295 [mac80211]
[1793205.433675] [<d09414fb>] rate_control_get_rate+0x7e/0x24d [mac80211]
[1793205.453528] [<c102e7f4>] ? T.295+0xe/0x128
[1793205.466632] [<c1167ffe>] ? rb_insert_color+0x58/0xc5
[1793205.482397] [<d09494d1>] invoke_tx_handlers+0x78f/0xfa5 [mac80211]
[1793205.501799] [<d094a648>] ieee80211_tx+0x50/0x77 [mac80211]
[1793205.519112] [<d094a971>] ieee80211_xmit+0xae/0xb6 [mac80211]
[1793205.536956] [<d094a9bf>] ieee80211_tx_skb_tid+0x46/0x50 [mac80211]
[1793205.556368] [<d094e4d4>] ieee80211_send_deauth_disassoc+0xbb/0xc1 [mac80211]
[1793205.578365] [<d094e5ff>] ieee80211_set_disassoc+0x125/0x275 [mac80211]
[1793205.598803] [<d094e8b9>] ieee80211_mgd_deauth+0x92/0x102 [mac80211]
[1793205.618455] [<d0943b87>] ieee80211_deauth+0x10/0x12 [mac80211]
[1793205.636812] [<d0878348>] __cfg80211_mlme_deauth+0x84/0x90 [cfg80211]
[1793205.656702] [<d087a9d5>] __cfg80211_disconnect+0xc3/0x125 [cfg80211]
[1793205.676594] [<d087d330>] cfg80211_mgd_wext_siwessid+0xec/0x18d [cfg80211]
[1793205.697778] [<d087c639>] cfg80211_wext_siwessid+0x31/0x3e [cfg80211]
[1793205.717648] [<c1293b8a>] ioctl_standard_call+0x1e6/0x27a
[1793205.734374] [<c1293ccf>] wext_handle_ioctl+0xb1/0x132
[1793205.750374] [<d087c608>] ? cfg80211_wext_giwessid+0x4a/0x4a [cfg80211]
[1793205.770755] [<c11df9db>] dev_ioctl+0x53f/0x57c
[1793205.784892] [<c10683f8>] ? do_sync_write+0x93/0xce
[1793205.800077] [<c11d0250>] ? kernel_sendmsg+0x37/0x37
[1793205.815514] [<c11d0428>] sock_ioctl+0x1d8/0x1e4
[1793205.829892] [<c11d0250>] ? kernel_sendmsg+0x37/0x37
[1793205.845341] [<c10733b8>] do_vfs_ioctl+0x424/0x463
[1793205.860263] [<c11d0b76>] ? sys_send+0x18/0x1a
[1793205.874146] [<c11d1ad4>] ? sys_socketcall+0xc9/0x19c
[1793205.889848] [<c1073425>] sys_ioctl+0x2e/0x48
[1793205.903477] [<c129d095>] syscall_call+0x7/0xb
[1793205.917356] [<c1290000>] ? rsi_parse+0xbf/0x331
[1793205.931752] ---[ end trace 9c8890d6ce64a00b ]---
[1793205.966909] cfg80211: Calling CRDA to update world regulatory domain
[1793205.986669] wlan0: authenticate with XX:XX:XX:XX:XX:XY
Best regards
Arnd
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH v2] ipv4: Use newinet->inet_opt in inet_csk_route_child_sock()
From: Christoph Paasch @ 2012-08-20 12:52 UTC (permalink / raw)
To: David Miller; +Cc: netdev
Since 0e734419923bd ("ipv4: Use inet_csk_route_child_sock() in DCCP and
TCP."), inet_csk_route_child_sock() is called instead of
inet_csk_route_req().
However, after creating the child-sock in tcp/dccp_v4_syn_recv_sock(),
ireq->opt is set to NULL, before calling inet_csk_route_child_sock().
Thus, inside inet_csk_route_child_sock() opt is always NULL and the
SRR-options are not respected anymore.
Packets sent by the server won't have the correct destination-IP.
This patch fixes it by accessing newinet->inet_opt instead of ireq->opt
inside inet_csk_route_child_sock().
Reported-by: Luca Boccassi <luca.boccassi@gmail.com>
Signed-off-by: Christoph Paasch <christoph.paasch@uclouvain.be>
---
v2:
* Added rcu_read_(un)lock()
* Fixed typo in the patch-subject
* Added "Reported-by"
---
net/ipv4/inet_connection_sock.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index db0cf17..7f75f21 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -404,12 +404,15 @@ struct dst_entry *inet_csk_route_child_sock(struct sock *sk,
{
const struct inet_request_sock *ireq = inet_rsk(req);
struct inet_sock *newinet = inet_sk(newsk);
- struct ip_options_rcu *opt = ireq->opt;
+ struct ip_options_rcu *opt;
struct net *net = sock_net(sk);
struct flowi4 *fl4;
struct rtable *rt;
fl4 = &newinet->cork.fl.u.ip4;
+
+ rcu_read_lock();
+ opt = rcu_dereference(newinet->inet_opt);
flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark,
RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE,
sk->sk_protocol, inet_sk_flowi_flags(sk),
@@ -421,11 +424,13 @@ struct dst_entry *inet_csk_route_child_sock(struct sock *sk,
goto no_route;
if (opt && opt->opt.is_strictroute && rt->rt_gateway)
goto route_err;
+ rcu_read_unlock();
return &rt->dst;
route_err:
ip_rt_put(rt);
no_route:
+ rcu_read_unlock();
IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES);
return NULL;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH 0/3] ipvs: IPv6 fragment handling for IPVS
From: Jesper Dangaard Brouer @ 2012-08-20 13:08 UTC (permalink / raw)
To: netdev, Patrick McHardy, Hans Schillstrom, lvs-devel,
Julian Anastasov, Simon Horman
Cc: Jesper Dangaard Brouer, Wensong Zhang, netfilter-devel
The following patchset implement IPv6 fragment handling for IPVS.
This work is based upon patches from Hans Schillstrom. I have taken
over the patchset, in close agreement with Hans, because he don't have
(gotten allocated) time to complete his work.
I have cleaned up the patchset, changed the API a bit, fixed a refcnt
bug, and rebased on top of Julians recent changes. (All with Hans'es
knowledge)
Patch01: is just unrelated trivial fixes.
Patch02: Fix faulty IPv6 extension header handling in IPVS
Patch03: Complete IPv6 fragment handling for IPVS
This patchset is based upon:
Homes ipvs-next tree:
git://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs-next.git
On top of commit 3654e61137db891f5312e6dd813b961484b5fdf3:
ipvs: add pmtu_disc option to disable IP DF for TUN packets
---
Jesper Dangaard Brouer (3):
ipvs: Complete IPv6 fragment handling for IPVS
ipvs: Fix faulty IPv6 extension header handling in IPVS
ipvs: Trivial changes, use compressed IPv6 address in output
include/net/ip_vs.h | 191 +++++++++++----
net/netfilter/ipvs/Kconfig | 7 -
net/netfilter/ipvs/ip_vs_conn.c | 15 -
net/netfilter/ipvs/ip_vs_core.c | 384 +++++++++++++++++--------------
net/netfilter/ipvs/ip_vs_dh.c | 2
net/netfilter/ipvs/ip_vs_lblc.c | 2
net/netfilter/ipvs/ip_vs_lblcr.c | 2
net/netfilter/ipvs/ip_vs_pe_sip.c | 27 ++
net/netfilter/ipvs/ip_vs_proto.c | 6
net/netfilter/ipvs/ip_vs_proto_ah_esp.c | 9 -
net/netfilter/ipvs/ip_vs_proto_sctp.c | 42 +--
net/netfilter/ipvs/ip_vs_proto_tcp.c | 40 +--
net/netfilter/ipvs/ip_vs_proto_udp.c | 41 +--
net/netfilter/ipvs/ip_vs_sched.c | 2
net/netfilter/ipvs/ip_vs_sh.c | 2
net/netfilter/ipvs/ip_vs_xmit.c | 75 +++---
net/netfilter/xt_ipvs.c | 4
17 files changed, 489 insertions(+), 362 deletions(-)
--
Best regards,
Jesper Dangaard Brouer
MSc.CS, Sr. Network Kernel Developer at Red Hat
Author of http://www.iptv-analyzer.org
LinkedIn: http://www.linkedin.com/in/brouer
^ permalink raw reply
* [PATCH 1/3] ipvs: Trivial changes, use compressed IPv6 address in output
From: Jesper Dangaard Brouer @ 2012-08-20 13:08 UTC (permalink / raw)
To: netdev, Patrick McHardy, Hans Schillstrom, lvs-devel,
Julian Anastasov, Simon Horman
Cc: Jesper Dangaard Brouer, Wensong Zhang, netfilter-devel
In-Reply-To: <20120820130732.1509.13080.stgit@dragon>
Have not converted the proc file output to compressed IPv6 addresses.
Move trivial fixes to this first patch.
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
---
include/net/ip_vs.h | 2 +-
net/netfilter/ipvs/ip_vs_proto.c | 6 +++---
net/netfilter/ipvs/ip_vs_sched.c | 2 +-
net/netfilter/ipvs/ip_vs_xmit.c | 10 +++++-----
4 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index ee75ccd..aba0bb2 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -165,7 +165,7 @@ static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len,
int len;
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6)
- len = snprintf(&buf[*idx], buf_len - *idx, "[%pI6]",
+ len = snprintf(&buf[*idx], buf_len - *idx, "[%pI6c]",
&addr->in6) + 1;
else
#endif
diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c
index 50d8218..939f7fb 100644
--- a/net/netfilter/ipvs/ip_vs_proto.c
+++ b/net/netfilter/ipvs/ip_vs_proto.c
@@ -280,17 +280,17 @@ ip_vs_tcpudp_debug_packet_v6(struct ip_vs_protocol *pp,
if (ih == NULL)
sprintf(buf, "TRUNCATED");
else if (ih->nexthdr == IPPROTO_FRAGMENT)
- sprintf(buf, "%pI6->%pI6 frag", &ih->saddr, &ih->daddr);
+ sprintf(buf, "%pI6c->%pI6c frag", &ih->saddr, &ih->daddr);
else {
__be16 _ports[2], *pptr;
pptr = skb_header_pointer(skb, offset + sizeof(struct ipv6hdr),
sizeof(_ports), _ports);
if (pptr == NULL)
- sprintf(buf, "TRUNCATED %pI6->%pI6",
+ sprintf(buf, "TRUNCATED %pI6c->%pI6c",
&ih->saddr, &ih->daddr);
else
- sprintf(buf, "%pI6:%u->%pI6:%u",
+ sprintf(buf, "%pI6c:%u->%pI6c:%u",
&ih->saddr, ntohs(pptr[0]),
&ih->daddr, ntohs(pptr[1]));
}
diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c
index 08dbdd5..d6bf20d 100644
--- a/net/netfilter/ipvs/ip_vs_sched.c
+++ b/net/netfilter/ipvs/ip_vs_sched.c
@@ -159,7 +159,7 @@ void ip_vs_scheduler_err(struct ip_vs_service *svc, const char *msg)
svc->fwmark, msg);
#ifdef CONFIG_IP_VS_IPV6
} else if (svc->af == AF_INET6) {
- IP_VS_ERR_RL("%s: %s [%pI6]:%d - %s\n",
+ IP_VS_ERR_RL("%s: %s [%pI6c]:%d - %s\n",
svc->scheduler->name,
ip_vs_proto_name(svc->protocol),
&svc->addr.in6, ntohs(svc->port), msg);
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 543a554..eef3432 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -319,7 +319,7 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,
local = __ip_vs_is_local_route6(rt);
if (!((local ? IP_VS_RT_MODE_LOCAL : IP_VS_RT_MODE_NON_LOCAL) &
rt_mode)) {
- IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI6\n",
+ IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI6c\n",
local ? "local":"non-local", daddr);
dst_release(&rt->dst);
return NULL;
@@ -327,8 +327,8 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,
if (local && !(rt_mode & IP_VS_RT_MODE_RDR) &&
!((ort = (struct rt6_info *) skb_dst(skb)) &&
__ip_vs_is_local_route6(ort))) {
- IP_VS_DBG_RL("Redirect from non-local address %pI6 to local "
- "requires NAT method, dest: %pI6\n",
+ IP_VS_DBG_RL("Redirect from non-local address %pI6c to local "
+ "requires NAT method, dest: %pI6c\n",
&ipv6_hdr(skb)->daddr, daddr);
dst_release(&rt->dst);
return NULL;
@@ -336,8 +336,8 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,
if (unlikely(!local && (!skb->dev || skb->dev->flags & IFF_LOOPBACK) &&
ipv6_addr_type(&ipv6_hdr(skb)->saddr) &
IPV6_ADDR_LOOPBACK)) {
- IP_VS_DBG_RL("Stopping traffic from loopback address %pI6 "
- "to non-local address, dest: %pI6\n",
+ IP_VS_DBG_RL("Stopping traffic from loopback address %pI6c "
+ "to non-local address, dest: %pI6c\n",
&ipv6_hdr(skb)->saddr, daddr);
dst_release(&rt->dst);
return NULL;
^ permalink raw reply related
* [PATCH 3/3] ipvs: Complete IPv6 fragment handling for IPVS
From: Jesper Dangaard Brouer @ 2012-08-20 13:08 UTC (permalink / raw)
To: netdev, Patrick McHardy, Hans Schillstrom, lvs-devel,
Julian Anastasov, Simon Horman
Cc: Jesper Dangaard Brouer, Wensong Zhang, netfilter-devel
In-Reply-To: <20120820130732.1509.13080.stgit@dragon>
IPVS now supports fragmented packets, with support from nf_conntrack_reasm.c
Based on patch from: Hans Schillstrom.
IPVS do like conntrack i.e. use the skb->nfct_reasm
(i.e. when all fragments is collected, nf_ct_frag6_output()
starts a "re-play" of all fragments into the interrupted
PREROUTING chain at prio -399 (NF_IP6_PRI_CONNTRACK_DEFRAG+1)
with nfct_reasm pointing to the assembled packet.)
Notice, module nf_defrag_ipv6 must be loaded for this to work.
IPVS adds a new hook into prerouting chain at prio
-99 (NF_IP6_PRI_NAT_DST+1) to catch fragments, and copy fw-mark
info from the first packet with an upper layer header.
Also, for IPv6, handle all ICMPv6 NONE Informational Messages (via
ICMPV6_INFOMSG_MASK). This actually only extend our handling to
type ICMPV6_PARAMPROB (Parameter Problem), and future types.
- Fixed refcnt bug since last.
Signed-off-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Hans Schillstrom <hans@schillstrom.com>
---
include/net/ip_vs.h | 16 ++++
net/netfilter/ipvs/Kconfig | 7 +-
net/netfilter/ipvs/ip_vs_conn.c | 2
net/netfilter/ipvs/ip_vs_core.c | 173 ++++++++++++++++++++++++++++-----------
net/netfilter/ipvs/ip_vs_xmit.c | 24 ++++-
5 files changed, 161 insertions(+), 61 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 8d5920f..50f377e 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -123,11 +123,27 @@ static inline struct sk_buff *skb_nfct_reasm(const struct sk_buff *skb)
{
return skb->nfct_reasm;
}
+static inline void *frag_safe_skb_hp(const struct sk_buff *skb, int offset,
+ int len, void *buffer,
+ const struct ip_vs_iphdr *ipvsh)
+{
+ if (unlikely(ipvsh->fragoffs && skb_nfct_reasm(skb)))
+ return skb_header_pointer(skb_nfct_reasm(skb), ipvsh->offs,
+ len, buffer);
+
+ return skb_header_pointer(skb, offset, len, buffer);
+}
#else
static inline struct sk_buff *skb_nfct_reasm(const struct sk_buff *skb)
{
return NULL;
}
+static inline void *frag_safe_skb_hp(const struct sk_buff *skb, int offset,
+ int len, void *buffer,
+ const struct ip_vs_iphdr *ipvsh)
+{
+ return skb_header_pointer(skb, offset, len, buffer);
+}
#endif
static inline void
diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig
index 8b2cffd..0c3b167 100644
--- a/net/netfilter/ipvs/Kconfig
+++ b/net/netfilter/ipvs/Kconfig
@@ -28,12 +28,11 @@ if IP_VS
config IP_VS_IPV6
bool "IPv6 support for IPVS"
depends on IPV6 = y || IP_VS = IPV6
+ select IP6_NF_IPTABLES
---help---
- Add IPv6 support to IPVS. This is incomplete and might be dangerous.
+ Add IPv6 support to IPVS.
- See http://www.mindbasket.com/ipvs for more information.
-
- Say N if unsure.
+ Say Y if unsure.
config IP_VS_DEBUG
bool "IP virtual server debugging"
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index a00db99..30e764a 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -313,7 +313,7 @@ ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb,
__be16 _ports[2], *pptr;
struct net *net = skb_net(skb);
- pptr = skb_header_pointer(skb, iph->len, sizeof(_ports), _ports);
+ pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports, iph);
if (pptr == NULL)
return 1;
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 32c69ed..9f2e167 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -402,7 +402,7 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
/*
* IPv6 frags, only the first hit here.
*/
- pptr = skb_header_pointer(skb, iph->len, sizeof(_ports), _ports);
+ pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports, iph);
if (pptr == NULL)
return NULL;
@@ -505,7 +505,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
int unicast;
#endif
- pptr = skb_header_pointer(skb, iph->len, sizeof(_ports), _ports);
+ pptr = frag_safe_skb_hp(skb, iph->len, sizeof(_ports), _ports, iph);
if (pptr == NULL) {
ip_vs_service_put(svc);
return NF_DROP;
@@ -651,14 +651,6 @@ static inline int ip_vs_gather_frags(struct sk_buff *skb, u_int32_t user)
return err;
}
-#ifdef CONFIG_IP_VS_IPV6
-static inline int ip_vs_gather_frags_v6(struct sk_buff *skb, u_int32_t user)
-{
- /* TODO IPv6: Find out what to do here for IPv6 */
- return 0;
-}
-#endif
-
static int ip_vs_route_me_harder(int af, struct sk_buff *skb)
{
#ifdef CONFIG_IP_VS_IPV6
@@ -729,10 +721,22 @@ void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
struct ip_vs_conn *cp, int inout)
{
struct ipv6hdr *iph = ipv6_hdr(skb);
- unsigned int icmp_offset = sizeof(struct ipv6hdr);
- struct icmp6hdr *icmph = (struct icmp6hdr *)(skb_network_header(skb) +
- icmp_offset);
- struct ipv6hdr *ciph = (struct ipv6hdr *)(icmph + 1);
+ unsigned int icmp_offset = 0;
+ unsigned int offs = 0; /* header offset*/
+ int protocol;
+ struct icmp6hdr *icmph;
+ struct ipv6hdr *ciph;
+ unsigned short fragoffs;
+
+ ipv6_find_hdr(skb, &icmp_offset, IPPROTO_ICMPV6, &fragoffs, NULL);
+ icmph = (struct icmp6hdr *)(skb_network_header(skb) + icmp_offset);
+ offs = icmp_offset + sizeof(struct icmp6hdr);
+ ciph = (struct ipv6hdr *)(skb_network_header(skb) + offs);
+
+ protocol = ipv6_find_hdr(skb, &offs, -1, &fragoffs, NULL);
+
+ if (!skb_make_writable(skb, offs + sizeof(__u32)))
+ return;
if (inout) {
iph->saddr = cp->vaddr.in6;
@@ -743,10 +747,13 @@ void ip_vs_nat_icmp_v6(struct sk_buff *skb, struct ip_vs_protocol *pp,
}
/* the TCP/UDP/SCTP port */
- if (IPPROTO_TCP == ciph->nexthdr || IPPROTO_UDP == ciph->nexthdr ||
- IPPROTO_SCTP == ciph->nexthdr) {
- __be16 *ports = (void *)ciph + sizeof(struct ipv6hdr);
+ if (!fragoffs && (IPPROTO_TCP == protocol || IPPROTO_UDP == protocol ||
+ IPPROTO_SCTP == protocol)) {
+ __be16 *ports = (void *)(skb_network_header(skb) + offs);
+ IP_VS_DBG(11, "%s() changed port %d to %d\n", __func__,
+ ntohs(inout ? ports[1] : ports[0]),
+ ntohs(inout ? cp->vport : cp->dport));
if (inout)
ports[1] = cp->vport;
else
@@ -919,12 +926,12 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related,
union nf_inet_addr snet;
*related = 1;
-
- ic = skb_header_pointer(skb, ipvsh->len, sizeof(_icmph), &_icmph);
+ ic = frag_safe_skb_hp(skb, ipvsh->len, sizeof(_icmph), &_icmph, ipvsh);
if (ic == NULL)
return NF_DROP;
- IP_VS_DBG(12, "Outgoing ICMPv6 (%d,%d) %pI6c->%pI6c\n",
+ IP_VS_DBG(12, "Outgoing ICMPv6 %s(%d,%d) %pI6c->%pI6c\n",
+ ipvsh->flags & IP6T_FH_F_FRAG ? "Fragment " : "",
ic->icmp6_type, ntohs(icmpv6_id(ic)),
&ipvsh->saddr, &ipvsh->daddr);
@@ -935,12 +942,15 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related,
* this means that some packets will manage to get a long way
* down this stack and then be rejected, but that's life.
*/
- if ((ic->icmp6_type != ICMPV6_DEST_UNREACH) &&
- (ic->icmp6_type != ICMPV6_PKT_TOOBIG) &&
- (ic->icmp6_type != ICMPV6_TIME_EXCEED)) {
+ if (ic->icmp6_type & ICMPV6_INFOMSG_MASK) {
*related = 0;
return NF_ACCEPT;
}
+ /* Fragment header that is before ICMP header tells us that:
+ * it's not an error message since they can't be fragmented.
+ */
+ if (ipvsh->flags & IP6T_FH_F_FRAG)
+ return NF_DROP;
/* Now find the contained IP header */
ipvsh->len += sizeof(_icmph);
@@ -1095,6 +1105,12 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
ip_vs_fill_iph_skb(af, skb, &iph);
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) {
+ if (!iph.fragoffs && skb_nfct_reasm(skb)) {
+ struct sk_buff *reasm = skb_nfct_reasm(skb);
+ /* Save fw mark for coming frags */
+ reasm->ipvs_property = 1;
+ reasm->mark = skb->mark;
+ }
if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
int related;
int verdict = ip_vs_out_icmp_v6(skb, &related,
@@ -1102,7 +1118,6 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
if (related)
return verdict;
- ip_vs_fill_iph_skb(af, skb, &iph);
}
} else
#endif
@@ -1112,7 +1127,6 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
if (related)
return verdict;
- ip_vs_fill_ip4hdr(skb_network_header(skb), &iph);
}
pd = ip_vs_proto_data_get(net, iph.protocol);
@@ -1145,8 +1159,8 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
pp->protocol == IPPROTO_SCTP)) {
__be16 _ports[2], *pptr;
- pptr = skb_header_pointer(skb, iph.len,
- sizeof(_ports), _ports);
+ pptr = frag_safe_skb_hp(skb, iph.len,
+ sizeof(_ports), _ports, &iph);
if (pptr == NULL)
return NF_ACCEPT; /* Not for me */
if (ip_vs_lookup_real_service(net, af, iph.protocol,
@@ -1432,20 +1446,21 @@ static int ip_vs_in_icmp_v6(struct sk_buff *skb, int *related,
unsigned int hooknum, struct ip_vs_iphdr *iph)
{
struct net *net = NULL;
+ const struct ipv6hdr _ip6h, *ip6h;
struct icmp6hdr _icmph, *ic;
struct ip_vs_iphdr ciph;
struct ip_vs_conn *cp;
struct ip_vs_protocol *pp;
struct ip_vs_proto_data *pd;
- unsigned int offset, verdict;
+ unsigned int offs_ciph, verdict;
*related = 1;
- ic = skb_header_pointer(skb, iph->len, sizeof(_icmph), &_icmph);
+ ic = frag_safe_skb_hp(skb, iph->len, sizeof(_icmph), &_icmph, iph);
if (ic == NULL)
return NF_DROP;
- IP_VS_DBG(12, "Incoming ICMPv6 (%d,%d) %pI6c->%pI6c\n",
+ IP_VS_DBG(12, "Incoming ICMPv6 %d(%d,%d) %pI6c->%pI6c\n", hooknum,
ic->icmp6_type, ntohs(icmpv6_id(ic)),
&iph->saddr, &iph->daddr);
@@ -1456,51 +1471,64 @@ static int ip_vs_in_icmp_v6(struct sk_buff *skb, int *related,
* this means that some packets will manage to get a long way
* down this stack and then be rejected, but that's life.
*/
- if ((ic->icmp6_type != ICMPV6_DEST_UNREACH) &&
- (ic->icmp6_type != ICMPV6_PKT_TOOBIG) &&
- (ic->icmp6_type != ICMPV6_TIME_EXCEED)) {
+ if (ic->icmp6_type & ICMPV6_INFOMSG_MASK) {
*related = 0;
return NF_ACCEPT;
}
+ /* Fragment header that is before ICMP header tells us that:
+ * it's not an error message since they can't be fragmented.
+ */
+ if (iph->flags & IP6T_FH_F_FRAG)
+ return NF_DROP;
/* Now find the contained IP header */
ciph.len = iph->len + sizeof(_icmph);
ciph.flags = 0;
ciph.fragoffs = 0;
+ offs_ciph = ciph.len; /* Save ip header offset */
+ ip6h = skb_header_pointer(skb, ciph.len, sizeof(_ip6h),
+ (void *)&_ip6h);
ciph.protocol = ipv6_find_hdr(skb, &ciph.len, -1, &ciph.fragoffs,
&ciph.flags);
- ciph.saddr = iph->saddr; /* con_in_get() handles reverse order */
- ciph.daddr = iph->daddr;
+ ciph.saddr.in6 = ip6h->saddr; /* con_in_get() handles reverse order */
+ ciph.daddr.in6 = ip6h->daddr;
net = skb_net(skb);
pd = ip_vs_proto_data_get(net, ciph.protocol);
- if (!pd)
- return NF_ACCEPT;
- pp = pd->pp;
- /* Is the embedded protocol header present?
- * If it's the second or later fragment we don't know what it is
+ /* Is not the embedded protocol header present?
+ * or it's the second or later fragment we don't know what it is
* i.e. just let it through.
*/
- if (ciph.fragoffs)
+ if (!pd || ciph.fragoffs)
return NF_ACCEPT;
+ pp = pd->pp;
- offset = ciph.len;
- IP_VS_DBG_PKT(11, AF_INET6, pp, skb, offset,
+ IP_VS_DBG_PKT(11, AF_INET6, pp, skb, offs_ciph,
"Checking incoming ICMPv6 for");
- /* The embedded headers contain source and dest in reverse order */
- cp = pp->conn_in_get(AF_INET6, skb, &ciph, 1);
+ /* The embedded headers contain source and dest in reverse order
+ * if not from localhost
+ */
+ cp = pp->conn_in_get(AF_INET6, skb, &ciph,
+ (hooknum == NF_INET_LOCAL_OUT) ? 0 : 1);
+
if (!cp)
return NF_ACCEPT;
+ /* VS/TUN, VS/DR and LOCALNODE just let it go */
+ if ((hooknum == NF_INET_LOCAL_OUT) &&
+ (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ)) {
+ __ip_vs_conn_put(cp);
+ return NF_ACCEPT;
+ }
/* do the statistics and put it back */
ip_vs_in_stats(cp, skb);
if (IPPROTO_TCP == ciph.protocol || IPPROTO_UDP == ciph.protocol ||
IPPROTO_SCTP == ciph.protocol)
- offset = ciph.len + (2 * sizeof(__u16));
+ offs_ciph = ciph.len;
- verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offset, hooknum, &ciph);
+ verdict = ip_vs_icmp_xmit_v6(skb, cp, pp, offs_ciph, hooknum, &ciph);
__ip_vs_conn_put(cp);
@@ -1562,6 +1590,12 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) {
+ if (!iph.fragoffs && skb_nfct_reasm(skb)) {
+ struct sk_buff *reasm = skb_nfct_reasm(skb);
+ /* Save fw mark for coming frags. */
+ reasm->ipvs_property = 1;
+ reasm->mark = skb->mark;
+ }
if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
int related;
int verdict = ip_vs_in_icmp_v6(skb, &related, hooknum,
@@ -1587,12 +1621,12 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
pp = pd->pp;
/*
* Check if the packet belongs to an existing connection entry
- * Only sched first IPv6 fragment.
*/
cp = pp->conn_in_get(af, skb, &iph, 0);
- if (unlikely(!cp) && !iph.fragoffs) {
+ if (unlikely(!cp)) {
int v;
+ /* Schedule and create new connection entry into &cp */
if (!pp->conn_schedule(af, skb, pd, &v, &cp, &iph))
return v;
}
@@ -1685,6 +1719,39 @@ ip_vs_local_request4(unsigned int hooknum, struct sk_buff *skb,
#ifdef CONFIG_IP_VS_IPV6
/*
+ * AF_INET6 fragment handling
+ * Copy info from first fragment, to the rest of them.
+ */
+static unsigned int
+ip_vs_preroute_frag6(unsigned int hooknum, struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ struct ip_vs_iphdr iphdr = { .len = 0, .flags = 0, };
+ struct sk_buff *reasm = skb_nfct_reasm(skb);
+ struct net *net;
+
+ /* Skip if not a "replay" from nf_ct_frag6_output or first fragment.
+ * ipvs_property is set when checking first fragment
+ * in ip_vs_in() and ip_vs_out().
+ */
+ if (reasm)
+ IP_VS_DBG(2, "Fragment recv prop:%d\n", reasm->ipvs_property);
+ if (!reasm || !reasm->ipvs_property)
+ return NF_ACCEPT;
+
+ net = skb_net(skb);
+ if (!net_ipvs(net)->enable)
+ return NF_ACCEPT;
+
+ /* Copy stored fw mark, saved in ip_vs_{in,out} */
+ skb->mark = reasm->mark;
+
+ return NF_ACCEPT;
+}
+
+/*
* AF_INET6 handler in NF_INET_LOCAL_IN chain
* Schedule and forward packets from remote clients
*/
@@ -1823,6 +1890,14 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
.priority = 100,
},
#ifdef CONFIG_IP_VS_IPV6
+ /* After mangle & nat fetch 2:nd fragment and following */
+ {
+ .hook = ip_vs_preroute_frag6,
+ .owner = THIS_MODULE,
+ .pf = NFPROTO_IPV6,
+ .hooknum = NF_INET_PRE_ROUTING,
+ .priority = NF_IP6_PRI_NAT_DST + 1,
+ },
/* After packet filtering, change source only for VS/NAT */
{
.hook = ip_vs_reply6,
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 925cca2..422b92f 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -497,7 +497,9 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
skb->dev = net->loopback_dev;
}
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+ /* only send ICMP too big on first fragment */
+ if (!iph->fragoffs)
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
dst_release(&rt->dst);
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
goto tx_error;
@@ -667,7 +669,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
EnterFunction(10);
/* check if it is a connection of no-client-port */
- if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) {
+ if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT && !iph->fragoffs)) {
__be16 _pt, *p;
p = skb_header_pointer(skb, iph->len, sizeof(_pt), &_pt);
if (p == NULL)
@@ -693,7 +695,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
if (ct && !nf_ct_is_untracked(ct)) {
IP_VS_DBG_RL_PKT(10, AF_INET6, pp, skb, 0,
- "ip_vs_nat_xmit_v6(): "
+ "ip_vs_nat_xmit_v6(): "\
"stopping DNAT to local address");
goto tx_error_put;
}
@@ -717,7 +719,9 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
skb->dev = net->loopback_dev;
}
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+ /* only send ICMP too big on first fragment */
+ if (!iph->fragoffs)
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
IP_VS_DBG_RL_PKT(0, AF_INET6, pp, skb, 0,
"ip_vs_nat_xmit_v6(): frag needed for");
goto tx_error_put;
@@ -952,7 +956,9 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
skb->dev = net->loopback_dev;
}
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+ /* only send ICMP too big on first fragment */
+ if (!ipvsh->fragoffs)
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
goto tx_error_put;
}
@@ -1118,7 +1124,9 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
skb->dev = net->loopback_dev;
}
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+ /* only send ICMP too big on first fragment */
+ if (!iph->fragoffs)
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
dst_release(&rt->dst);
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
goto tx_error;
@@ -1356,7 +1364,9 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
skb->dev = net->loopback_dev;
}
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+ /* only send ICMP too big on first fragment */
+ if (!iph->fragoffs)
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
IP_VS_DBG_RL("%s(): frag needed\n", __func__);
goto tx_error_put;
}
^ permalink raw reply related
* Re: [PATCH 05/19] netfilter: nf_conntrack_ipv6: improve fragmentation handling
From: Jesper Dangaard Brouer @ 2012-08-20 13:13 UTC (permalink / raw)
To: Patrick McHardy; +Cc: netfilter-devel, netdev
In-Reply-To: <Pine.GSO.4.63.1208192141570.3016@stinky-local.trash.net>
On Sun, 2012-08-19 at 21:44 +0200, Patrick McHardy wrote:
> Could you send me your patch so I get a better picture of what you're
> doing exactly?
Okay, just posted the patchset.
Specifically look at patch:
[PATCH 3/3] ipvs: Complete IPv6 fragment handling for IPVS
Where I use the hook to copy the fw mark from the reasm SKB packet to
the SKB fragments. (Perhaps, this could be done else were in the
netfilter framework).
--Jesper Brouer
^ permalink raw reply
* [PATCH net-next] af_packet: use define instead of constant
From: Daniel Borkmann @ 2012-08-20 13:34 UTC (permalink / raw)
To: davem; +Cc: netdev
Instead of using a hard-coded value for the status variable, it would make
the code more readable to use its destined define from linux/if_packet.h.
Signed-off-by: daniel.borkmann@tik.ee.ethz.ch
---
net/packet/af_packet.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 226b2cd..3ee372a 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -855,7 +855,8 @@ static void prb_fill_vlan_info(struct tpacket_kbdq_core *pkc,
ppd->hv1.tp_vlan_tci = vlan_tx_tag_get(pkc->skb);
ppd->tp_status = TP_STATUS_VLAN_VALID;
} else {
- ppd->hv1.tp_vlan_tci = ppd->tp_status = 0;
+ ppd->hv1.tp_vlan_tci = 0;
+ ppd->tp_status = TP_STATUS_AVAILABLE;
}
}
@@ -1943,7 +1944,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
int tp_len, size_max;
unsigned char *addr;
int len_sum = 0;
- int status = 0;
+ int status = TP_STATUS_AVAILABLE;
int hlen, tlen;
mutex_lock(&po->pg_vec_lock);
^ permalink raw reply related
* Re: [RFC PATCH net-next 0/9] tipc: misc updates for 3.7
From: Paul Gortmaker @ 2012-08-20 13:46 UTC (permalink / raw)
To: David Miller; +Cc: netdev, jon.maloy, ying.xue
In-Reply-To: <20120820.022743.465143033806832968.davem@davemloft.net>
On 12-08-20 05:27 AM, David Miller wrote:
> From: Paul Gortmaker <paul.gortmaker@windriver.com>
> Date: Thu, 16 Aug 2012 18:09:05 -0400
>
>> This series gets some more largely trivial things out of
>> the way. Most interesting are:
>>
>> 1) fix lockdep splat from bearer init by pushing the setup
>> off to schedule_work.
>>
>> 2) simplification of configuration by removal of a couple of
>> tuning knobs which used to have low default values.
>>
>> The remainder are largely innocuous, I think. I did wonder
>> if there was an alternate/better way to handle the splat though.
>>
>> I've done my own local testing of this series on today's net-next
>> commit 2ea214929d601 ("Merge branch 'for-davem' ... wireless-next")
>>
>> I'll wait a couple of days to allow for any possible feedback and
>> change requests, and then send a pull request after that.
>
> All applied, thanks Paul.
>
> It's less useful for you to build the GIT tree "later", at least for
> me.
>
> If the patches are good and there is no feedback asking for changes,
> I want to be able to just pull them into my tree immediately as I
> did here.
OK, I will go back to what I was doing before, i.e. putting them
on kernel.org and putting the git:// location in the 0/N summary
all in one step.
Paul.
>
> Thanks.
>
^ permalink raw reply
* [PATCH net-next] packet: Protect packet sk list with mutex
From: Pavel Emelyanov @ 2012-08-20 14:50 UTC (permalink / raw)
To: David Miller, Linux Netdev List
In patch eea68e2f (packet: Report socket mclist info via diag module) I've
introduced a "scheduling in atomic" problem in packet diag module -- the
socket list is traversed under rcu_read_lock() while performed under it sk
mclist access requires rtnl lock (i.e. -- mutex) to be taken. Similar thing
was then re-introduced by further packet diag patches (fanount mutex and
pgvec mutex for rings) :(
Apart from being terribly sorry for the above, I propose to change the
packet sk list protection from spinlock to mutex. This lock currently
protects only the sklist modifications (that already happen in sleeping
context) and nothing more.
Am I wrong again and a fine-grained atomic locking is required for
everything that is reported by packet diag instead?
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
---
diff --git a/include/net/netns/packet.h b/include/net/netns/packet.h
index cb4e894..4780b08 100644
--- a/include/net/netns/packet.h
+++ b/include/net/netns/packet.h
@@ -8,7 +8,7 @@
#include <linux/spinlock.h>
struct netns_packet {
- spinlock_t sklist_lock;
+ struct mutex sklist_lock;
struct hlist_head sklist;
};
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 226b2cd..5048672 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -2308,10 +2308,10 @@ static int packet_release(struct socket *sock)
net = sock_net(sk);
po = pkt_sk(sk);
- spin_lock_bh(&net->packet.sklist_lock);
+ mutex_lock(&net->packet.sklist_lock);
sk_del_node_init_rcu(sk);
sock_prot_inuse_add(net, sk->sk_prot, -1);
- spin_unlock_bh(&net->packet.sklist_lock);
+ mutex_unlock(&net->packet.sklist_lock);
spin_lock(&po->bind_lock);
unregister_prot_hook(sk, false);
@@ -2510,10 +2510,10 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
register_prot_hook(sk);
}
- spin_lock_bh(&net->packet.sklist_lock);
+ mutex_lock(&net->packet.sklist_lock);
sk_add_node_rcu(sk, &net->packet.sklist);
sock_prot_inuse_add(net, &packet_proto, 1);
- spin_unlock_bh(&net->packet.sklist_lock);
+ mutex_unlock(&net->packet.sklist_lock);
return 0;
out:
@@ -3766,7 +3766,7 @@ static const struct file_operations packet_seq_fops = {
static int __net_init packet_net_init(struct net *net)
{
- spin_lock_init(&net->packet.sklist_lock);
+ mutex_init(&net->packet.sklist_lock);
INIT_HLIST_HEAD(&net->packet.sklist);
if (!proc_net_fops_create(net, "packet", 0, &packet_seq_fops))
diff --git a/net/packet/diag.c b/net/packet/diag.c
index bc33fbe..39bce0d 100644
--- a/net/packet/diag.c
+++ b/net/packet/diag.c
@@ -177,8 +177,8 @@ static int packet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
net = sock_net(skb->sk);
req = nlmsg_data(cb->nlh);
- rcu_read_lock();
- sk_for_each_rcu(sk, node, &net->packet.sklist) {
+ mutex_lock(&net->packet.sklist_lock);
+ sk_for_each(sk, node, &net->packet.sklist) {
if (!net_eq(sock_net(sk), net))
continue;
if (num < s_num)
@@ -192,7 +192,7 @@ next:
num++;
}
done:
- rcu_read_unlock();
+ mutex_unlock(&net->packet.sklist_lock);
cb->args[0] = num;
return skb->len;
^ permalink raw reply related
* Fwd: TCP fragmentation broken in 3.6-rc ?
From: Sylvain Munaut @ 2012-08-20 14:56 UTC (permalink / raw)
To: netdev
In-Reply-To: <CAF6-1L6xy1rRd321ZMzrLG6xHMdO0+sdjbtznUOsMzfYyU1SEg@mail.gmail.com>
Hi,
It seems somehow something was broken in 3.6-rc.
I'm not sure exactly what though. The symptoms are:
- TCP connection get "stuck" with data in send queue when doing
"large" transfers ( like typing 'ps ax' on a ssh connection )
- Only happens on path where the PMTU is lower than the MTU of the interface
- Is not present right after boot, it only appears 10-20min after
boot or so. (and that's inside the _same_ TCP connection, it works
fine at first and then in the same ssh session, it'll get stuck)
- Definitely seems related to fragments somehow since I see a router
sending ICMP message saying fragmentation is needed.
- Exact same setup works fine with kernel 3.5.1
Cheers,
Sylvain
^ permalink raw reply
* smsc75xx & smsc95xx, setting skb->truesize correctly?
From: Jussi Kivilinna @ 2012-08-20 14:57 UTC (permalink / raw)
To: netdev; +Cc: Steve Glendinning
Hello,
Is setting skb->truesize in smsc75xx and smsc95xx correct?
In smsc75xx/smsc95xx_rx_fixup(), input skb containing multiple packets
is cloned and truesize for each clone is set to packet-size +
sizeof(struct sk_buff), but input skb has minimum allocation size of
9000 bytes (MAX_SINGLE_PACKET_SIZE) and maximum of 18944 bytes
(DEFAULT_HS_BURST_CAP_SIZE) (+ NET_IP_ALIGN). Doesn't this cause
truesize to be underestimated?
-Jussi
^ permalink raw reply
* [net-next PATCH] mdio: translation of MMD EEE registers to/from ethtool settings
From: Bruce Allan @ 2012-08-20 14:55 UTC (permalink / raw)
To: netdev; +Cc: Bruce Allan, Giuseppe Cavallaro
The helper functions which translate IEEE MDIO Manageable Device (MMD)
Energy-Efficient Ethernet (EEE) registers 3.20, 7.60 and 7.61 to and from
the comparable ethtool supported/advertised settings will be needed by
drivers other than those in PHYLIB (e.g. e1000e in a follow-on patch).
In the same fashion as similar translation functions in linux/mii.h, move
these functions from the PHYLIB core to the linux/mdio.h header file so the
code will not have to be duplicated in each driver needing MMD-to-ethtool
(and vice-versa) translations. The function and some variable names have
been renamed to be more descriptive.
Not tested on the only hardware that currently calls the related functions,
stmmac, because I don't have access to any. Has been compile tested and
the translations have been tested on a locally modified version of e1000e.
Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
---
drivers/net/phy/phy.c | 74 ++++----------------------------------------
include/linux/mdio.h | 83 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 90 insertions(+), 67 deletions(-)
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 7ca2ff9..ef9ea92 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -1035,66 +1035,6 @@ static void phy_write_mmd_indirect(struct mii_bus *bus, int prtad, int devad,
bus->write(bus, addr, MII_MMD_DATA, data);
}
-static u32 phy_eee_to_adv(u16 eee_adv)
-{
- u32 adv = 0;
-
- if (eee_adv & MDIO_EEE_100TX)
- adv |= ADVERTISED_100baseT_Full;
- if (eee_adv & MDIO_EEE_1000T)
- adv |= ADVERTISED_1000baseT_Full;
- if (eee_adv & MDIO_EEE_10GT)
- adv |= ADVERTISED_10000baseT_Full;
- if (eee_adv & MDIO_EEE_1000KX)
- adv |= ADVERTISED_1000baseKX_Full;
- if (eee_adv & MDIO_EEE_10GKX4)
- adv |= ADVERTISED_10000baseKX4_Full;
- if (eee_adv & MDIO_EEE_10GKR)
- adv |= ADVERTISED_10000baseKR_Full;
-
- return adv;
-}
-
-static u32 phy_eee_to_supported(u16 eee_caported)
-{
- u32 supported = 0;
-
- if (eee_caported & MDIO_EEE_100TX)
- supported |= SUPPORTED_100baseT_Full;
- if (eee_caported & MDIO_EEE_1000T)
- supported |= SUPPORTED_1000baseT_Full;
- if (eee_caported & MDIO_EEE_10GT)
- supported |= SUPPORTED_10000baseT_Full;
- if (eee_caported & MDIO_EEE_1000KX)
- supported |= SUPPORTED_1000baseKX_Full;
- if (eee_caported & MDIO_EEE_10GKX4)
- supported |= SUPPORTED_10000baseKX4_Full;
- if (eee_caported & MDIO_EEE_10GKR)
- supported |= SUPPORTED_10000baseKR_Full;
-
- return supported;
-}
-
-static u16 phy_adv_to_eee(u32 adv)
-{
- u16 reg = 0;
-
- if (adv & ADVERTISED_100baseT_Full)
- reg |= MDIO_EEE_100TX;
- if (adv & ADVERTISED_1000baseT_Full)
- reg |= MDIO_EEE_1000T;
- if (adv & ADVERTISED_10000baseT_Full)
- reg |= MDIO_EEE_10GT;
- if (adv & ADVERTISED_1000baseKX_Full)
- reg |= MDIO_EEE_1000KX;
- if (adv & ADVERTISED_10000baseKX4_Full)
- reg |= MDIO_EEE_10GKX4;
- if (adv & ADVERTISED_10000baseKR_Full)
- reg |= MDIO_EEE_10GKR;
-
- return reg;
-}
-
/**
* phy_init_eee - init and check the EEE feature
* @phydev: target phy_device struct
@@ -1132,7 +1072,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
if (eee_cap < 0)
return eee_cap;
- cap = phy_eee_to_supported(eee_cap);
+ cap = mmd_eee_cap_to_ethtool_sup_t(eee_cap);
if (!cap)
goto eee_exit;
@@ -1149,8 +1089,8 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
if (eee_adv < 0)
return eee_adv;
- adv = phy_eee_to_adv(eee_adv);
- lp = phy_eee_to_adv(eee_lp);
+ adv = mmd_eee_adv_to_ethtool_adv_t(eee_adv);
+ lp = mmd_eee_adv_to_ethtool_adv_t(eee_lp);
idx = phy_find_setting(phydev->speed, phydev->duplex);
if ((lp & adv & settings[idx].setting))
goto eee_exit;
@@ -1210,21 +1150,21 @@ int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data)
MDIO_MMD_PCS, phydev->addr);
if (val < 0)
return val;
- data->supported = phy_eee_to_supported(val);
+ data->supported = mmd_eee_cap_to_ethtool_sup_t(val);
/* Get advertisement EEE */
val = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_ADV,
MDIO_MMD_AN, phydev->addr);
if (val < 0)
return val;
- data->advertised = phy_eee_to_adv(val);
+ data->advertised = mmd_eee_adv_to_ethtool_adv_t(val);
/* Get LP advertisement EEE */
val = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_LPABLE,
MDIO_MMD_AN, phydev->addr);
if (val < 0)
return val;
- data->lp_advertised = phy_eee_to_adv(val);
+ data->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(val);
return 0;
}
@@ -1241,7 +1181,7 @@ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data)
{
int val;
- val = phy_adv_to_eee(data->advertised);
+ val = ethtool_adv_to_mmd_eee_adv_t(data->advertised);
phy_write_mmd_indirect(phydev->bus, MDIO_AN_EEE_ADV, MDIO_MMD_AN,
phydev->addr, val);
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index 7cccafe..6c40684 100644
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -377,5 +377,88 @@ static inline void mdio45_ethtool_gset(const struct mdio_if_info *mdio,
extern int mdio_mii_ioctl(const struct mdio_if_info *mdio,
struct mii_ioctl_data *mii_data, int cmd);
+/**
+ * mmd_eee_cap_to_ethtool_sup_t
+ * @eee_cap: value of the MMD EEE Capability register
+ *
+ * A small helper function that translates MMD EEE Capability (3.20) bits
+ * to ethtool supported settings.
+ */
+static inline u32 mmd_eee_cap_to_ethtool_sup_t(u16 eee_cap)
+{
+ u32 supported = 0;
+
+ if (eee_cap & MDIO_EEE_100TX)
+ supported |= SUPPORTED_100baseT_Full;
+ if (eee_cap & MDIO_EEE_1000T)
+ supported |= SUPPORTED_1000baseT_Full;
+ if (eee_cap & MDIO_EEE_10GT)
+ supported |= SUPPORTED_10000baseT_Full;
+ if (eee_cap & MDIO_EEE_1000KX)
+ supported |= SUPPORTED_1000baseKX_Full;
+ if (eee_cap & MDIO_EEE_10GKX4)
+ supported |= SUPPORTED_10000baseKX4_Full;
+ if (eee_cap & MDIO_EEE_10GKR)
+ supported |= SUPPORTED_10000baseKR_Full;
+
+ return supported;
+}
+
+/**
+ * mmd_eee_adv_to_ethtool_adv_t
+ * @eee_adv: value of the MMD EEE Advertisement/Link Partner Ability registers
+ *
+ * A small helper function that translates the MMD EEE Advertisment (7.60)
+ * and MMD EEE Link Partner Ability (7.61) bits to ethtool advertisement
+ * settings.
+ */
+static inline u32 mmd_eee_adv_to_ethtool_adv_t(u16 eee_adv)
+{
+ u32 adv = 0;
+
+ if (eee_adv & MDIO_EEE_100TX)
+ adv |= ADVERTISED_100baseT_Full;
+ if (eee_adv & MDIO_EEE_1000T)
+ adv |= ADVERTISED_1000baseT_Full;
+ if (eee_adv & MDIO_EEE_10GT)
+ adv |= ADVERTISED_10000baseT_Full;
+ if (eee_adv & MDIO_EEE_1000KX)
+ adv |= ADVERTISED_1000baseKX_Full;
+ if (eee_adv & MDIO_EEE_10GKX4)
+ adv |= ADVERTISED_10000baseKX4_Full;
+ if (eee_adv & MDIO_EEE_10GKR)
+ adv |= ADVERTISED_10000baseKR_Full;
+
+ return adv;
+}
+
+/**
+ * ethtool_adv_to_mmd_eee_adv_t
+ * @adv: the ethtool advertisement settings
+ *
+ * A small helper function that translates ethtool advertisement settings
+ * to EEE advertisements for the MMD EEE Advertisement (7.60) and
+ * MMD EEE Link Partner Ability (7.61) registers.
+ */
+static inline u16 ethtool_adv_to_mmd_eee_adv_t(u32 adv)
+{
+ u16 reg = 0;
+
+ if (adv & ADVERTISED_100baseT_Full)
+ reg |= MDIO_EEE_100TX;
+ if (adv & ADVERTISED_1000baseT_Full)
+ reg |= MDIO_EEE_1000T;
+ if (adv & ADVERTISED_10000baseT_Full)
+ reg |= MDIO_EEE_10GT;
+ if (adv & ADVERTISED_1000baseKX_Full)
+ reg |= MDIO_EEE_1000KX;
+ if (adv & ADVERTISED_10000baseKX4_Full)
+ reg |= MDIO_EEE_10GKX4;
+ if (adv & ADVERTISED_10000baseKR_Full)
+ reg |= MDIO_EEE_10GKR;
+
+ return reg;
+}
+
#endif /* __KERNEL__ */
#endif /* __LINUX_MDIO_H__ */
^ permalink raw reply related
* Re: [PATCH net-next] packet: Protect packet sk list with mutex
From: Eric Dumazet @ 2012-08-20 15:11 UTC (permalink / raw)
To: Pavel Emelyanov; +Cc: David Miller, Linux Netdev List
In-Reply-To: <50324EBC.9060804@parallels.com>
On Mon, 2012-08-20 at 18:50 +0400, Pavel Emelyanov wrote:
> In patch eea68e2f (packet: Report socket mclist info via diag module) I've
> introduced a "scheduling in atomic" problem in packet diag module -- the
> socket list is traversed under rcu_read_lock() while performed under it sk
> mclist access requires rtnl lock (i.e. -- mutex) to be taken. Similar thing
> was then re-introduced by further packet diag patches (fanount mutex and
> pgvec mutex for rings) :(
>
> Apart from being terribly sorry for the above, I propose to change the
> packet sk list protection from spinlock to mutex. This lock currently
> protects only the sklist modifications (that already happen in sleeping
> context) and nothing more.
>
> Am I wrong again and a fine-grained atomic locking is required for
> everything that is reported by packet diag instead?
>
> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
>
> ---
>
> diff --git a/include/net/netns/packet.h b/include/net/netns/packet.h
> index cb4e894..4780b08 100644
> --- a/include/net/netns/packet.h
> +++ b/include/net/netns/packet.h
> @@ -8,7 +8,7 @@
> #include <linux/spinlock.h>
>
> struct netns_packet {
> - spinlock_t sklist_lock;
> + struct mutex sklist_lock;
> struct hlist_head sklist;
> };
>
> diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
> index 226b2cd..5048672 100644
> --- a/net/packet/af_packet.c
> +++ b/net/packet/af_packet.c
> @@ -2308,10 +2308,10 @@ static int packet_release(struct socket *sock)
> net = sock_net(sk);
> po = pkt_sk(sk);
>
> - spin_lock_bh(&net->packet.sklist_lock);
> + mutex_lock(&net->packet.sklist_lock);
> sk_del_node_init_rcu(sk);
> sock_prot_inuse_add(net, sk->sk_prot, -1);
Last time I checked, sock_prot_inuse_add() needed BH protection.
( This could be relaxed somehow on x86 thanks to this_cpu_add() ... but
thats another point)
Could you please report the full stack trace ?
^ 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