packets: Always register packet sk in the same order
authorMaxime Chevallier <maxime.chevallier@bootlin.com>
Sat, 16 Mar 2019 13:41:30 +0000 (14:41 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 19 Mar 2019 00:58:39 +0000 (17:58 -0700)
When using fanouts with AF_PACKET, the demux functions such as
fanout_demux_cpu will return an index in the fanout socket array, which
corresponds to the selected socket.

The ordering of this array depends on the order the sockets were added
to a given fanout group, so for FANOUT_CPU this means sockets are bound
to cpus in the order they are configured, which is OK.

However, when stopping then restarting the interface these sockets are
bound to, the sockets are reassigned to the fanout group in the reverse
order, due to the fact that they were inserted at the head of the
interface's AF_PACKET socket list.

This means that traffic that was directed to the first socket in the
fanout group is now directed to the last one after an interface restart.

In the case of FANOUT_CPU, traffic from CPU0 will be directed to the
socket that used to receive traffic from the last CPU after an interface
restart.

This commit introduces a helper to add a socket at the tail of a list,
then uses it to register AF_PACKET sockets.

Note that this changes the order in which sockets are listed in /proc and
with sock_diag.

Fixes: dc99f600698d ("packet: Add fanout support")
Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/sock.h
net/packet/af_packet.c

index 328cb7cb7b0bb93f1eb3ec2708c43b29b56efb15..8de5ee258b93a50b2fdcde796bae3a5b53ce4d6a 100644 (file)
@@ -710,6 +710,12 @@ static inline void sk_add_node_rcu(struct sock *sk, struct hlist_head *list)
                hlist_add_head_rcu(&sk->sk_node, list);
 }
 
+static inline void sk_add_node_tail_rcu(struct sock *sk, struct hlist_head *list)
+{
+       sock_hold(sk);
+       hlist_add_tail_rcu(&sk->sk_node, list);
+}
+
 static inline void __sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list)
 {
        hlist_nulls_add_head_rcu(&sk->sk_nulls_node, list);
index 8376bc1c1508170aa333f8feaa8a154908e0eb3c..8754d7c93b84b2d6e873a2340f3203c8a92d3bdd 100644 (file)
@@ -3243,7 +3243,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
        }
 
        mutex_lock(&net->packet.sklist_lock);
-       sk_add_node_rcu(sk, &net->packet.sklist);
+       sk_add_node_tail_rcu(sk, &net->packet.sklist);
        mutex_unlock(&net->packet.sklist_lock);
 
        preempt_disable();