Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtnl: provide link dump consistency info

This patch adds a change sequence counter to each net namespace
which is bumped whenever a netdevice is added or removed from
the list. If such a change occurred while a link dump took place,
the dump will have the NLM_F_DUMP_INTR flag set in the first
message which has been interrupted and in all subsequent messages
of the same dump.

Note that links may still be modified or renamed while a dump is
taking place but we can guarantee for userspace to receive a
complete list of links and not miss any.

Testing:
I have added 500 VLAN netdevices to make sure the dump is split
over multiple messages. Then while continuously dumping links in
one process I also continuously deleted and re-added a dummy
netdevice in another process. Multiple dumps per seconds have
had the NLM_F_DUMP_INTR flag set.

I guess we can wait for Johannes patch to hit net-next via the
wireless tree. I just wanted to give this some testing right away.

Signed-off-by: Thomas Graf <tgraf@infradead.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Thomas Graf and committed by
David S. Miller
4e985ada e77aeb71

+16
+1
include/net/net_namespace.h
··· 65 65 struct list_head dev_base_head; 66 66 struct hlist_head *dev_name_head; 67 67 struct hlist_head *dev_index_head; 68 + unsigned int dev_base_seq; /* protected by rtnl_mutex */ 68 69 69 70 /* core fib_rules */ 70 71 struct list_head rules_ops;
+10
net/core/dev.c
··· 199 199 DEFINE_RWLOCK(dev_base_lock); 200 200 EXPORT_SYMBOL(dev_base_lock); 201 201 202 + static inline void dev_base_seq_inc(struct net *net) 203 + { 204 + while (++net->dev_base_seq == 0); 205 + } 206 + 202 207 static inline struct hlist_head *dev_name_hash(struct net *net, const char *name) 203 208 { 204 209 unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ)); ··· 242 237 hlist_add_head_rcu(&dev->index_hlist, 243 238 dev_index_hash(net, dev->ifindex)); 244 239 write_unlock_bh(&dev_base_lock); 240 + 241 + dev_base_seq_inc(net); 242 + 245 243 return 0; 246 244 } 247 245 ··· 261 253 hlist_del_rcu(&dev->name_hlist); 262 254 hlist_del_rcu(&dev->index_hlist); 263 255 write_unlock_bh(&dev_base_lock); 256 + 257 + dev_base_seq_inc(dev_net(dev)); 264 258 } 265 259 266 260 /*
+1
net/core/net_namespace.c
··· 129 129 130 130 atomic_set(&net->count, 1); 131 131 atomic_set(&net->passive, 1); 132 + net->dev_base_seq = 1; 132 133 133 134 #ifdef NETNS_REFCNT_DEBUG 134 135 atomic_set(&net->use_count, 0);
+4
net/core/rtnetlink.c
··· 1032 1032 s_idx = cb->args[1]; 1033 1033 1034 1034 rcu_read_lock(); 1035 + cb->seq = net->dev_base_seq; 1036 + 1035 1037 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { 1036 1038 idx = 0; 1037 1039 head = &net->dev_index_head[h]; ··· 1045 1043 cb->nlh->nlmsg_seq, 0, 1046 1044 NLM_F_MULTI) <= 0) 1047 1045 goto out; 1046 + 1047 + nl_dump_check_consistent(cb, nlmsg_hdr(skb)); 1048 1048 cont: 1049 1049 idx++; 1050 1050 }