udp: no longer use SLAB_DESTROY_BY_RCU
Tom Herbert would like not touching UDP socket refcnt for encapsulated traffic. For this to happen, we need to use normal RCU rules, with a grace period before freeing a socket. UDP sockets are not short lived in the high usage case, so the added cost of call_rcu() should not be a concern. This actually removes a lot of complexity in UDP stack. Multicast receives no longer need to hold a bucket spinlock. Note that ip early demux still needs to take a reference on the socket. Same remark for functions used by xt_socket and xt_PROXY netfilter modules, but this might be changed later. Performance for a single UDP socket receiving flood traffic from many RX queues/cpus. Simple udp_rx using simple recvfrom() loop : 438 kpps instead of 374 kpps : 17 % increase of the peak rate. v2: Addressed Willem de Bruijn feedback in multicast handling - keep early demux break in __udp4_lib_demux_lookup() Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Tom Herbert <tom@herbertland.com> Cc: Willem de Bruijn <willemb@google.com> Tested-by: Tom Herbert <tom@herbertland.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
a4298e4522
commit
ca065d0cf8
@@ -36,10 +36,11 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
|
||||
const struct inet_diag_req_v2 *req)
|
||||
{
|
||||
int err = -EINVAL;
|
||||
struct sock *sk;
|
||||
struct sock *sk = NULL;
|
||||
struct sk_buff *rep;
|
||||
struct net *net = sock_net(in_skb->sk);
|
||||
|
||||
rcu_read_lock();
|
||||
if (req->sdiag_family == AF_INET)
|
||||
sk = __udp4_lib_lookup(net,
|
||||
req->id.idiag_src[0], req->id.idiag_sport,
|
||||
@@ -54,9 +55,9 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
|
||||
req->id.idiag_dport,
|
||||
req->id.idiag_if, tbl, NULL);
|
||||
#endif
|
||||
else
|
||||
goto out_nosk;
|
||||
|
||||
if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
|
||||
sk = NULL;
|
||||
rcu_read_unlock();
|
||||
err = -ENOENT;
|
||||
if (!sk)
|
||||
goto out_nosk;
|
||||
@@ -96,24 +97,23 @@ static void udp_dump(struct udp_table *table, struct sk_buff *skb,
|
||||
struct netlink_callback *cb,
|
||||
const struct inet_diag_req_v2 *r, struct nlattr *bc)
|
||||
{
|
||||
int num, s_num, slot, s_slot;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
int num, s_num, slot, s_slot;
|
||||
|
||||
s_slot = cb->args[0];
|
||||
num = s_num = cb->args[1];
|
||||
|
||||
for (slot = s_slot; slot <= table->mask; s_num = 0, slot++) {
|
||||
struct sock *sk;
|
||||
struct hlist_nulls_node *node;
|
||||
struct udp_hslot *hslot = &table->hash[slot];
|
||||
struct sock *sk;
|
||||
|
||||
num = 0;
|
||||
|
||||
if (hlist_nulls_empty(&hslot->head))
|
||||
if (hlist_empty(&hslot->head))
|
||||
continue;
|
||||
|
||||
spin_lock_bh(&hslot->lock);
|
||||
sk_nulls_for_each(sk, node, &hslot->head) {
|
||||
sk_for_each(sk, &hslot->head) {
|
||||
struct inet_sock *inet = inet_sk(sk);
|
||||
|
||||
if (!net_eq(sock_net(sk), net))
|
||||
|
Reference in New Issue
Block a user