summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Graf <tgraf@infradead.org>2011-06-20 23:11:20 -0400
committerDavid S. Miller <davem@davemloft.net>2011-07-01 18:39:53 -0400
commit4e985adaa504c1c1a05c8e013777ea0791a17b4d (patch)
treed2eedf47256577ebfc67f0356c9b348590b560d3
parente77aeb71f04ed236fffe5f347e208c8b0e92d48a (diff)
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>
-rw-r--r--include/net/net_namespace.h1
-rw-r--r--net/core/dev.c10
-rw-r--r--net/core/net_namespace.c1
-rw-r--r--net/core/rtnetlink.c4
4 files changed, 16 insertions, 0 deletions
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index aef430d779bd..1ab1aec209ac 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -65,6 +65,7 @@ struct net {
65 struct list_head dev_base_head; 65 struct list_head dev_base_head;
66 struct hlist_head *dev_name_head; 66 struct hlist_head *dev_name_head;
67 struct hlist_head *dev_index_head; 67 struct hlist_head *dev_index_head;
68 unsigned int dev_base_seq; /* protected by rtnl_mutex */
68 69
69 /* core fib_rules */ 70 /* core fib_rules */
70 struct list_head rules_ops; 71 struct list_head rules_ops;
diff --git a/net/core/dev.c b/net/core/dev.c
index 6b6ef14b42f2..4577e6711ec3 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -199,6 +199,11 @@ static struct list_head ptype_all __read_mostly; /* Taps */
199DEFINE_RWLOCK(dev_base_lock); 199DEFINE_RWLOCK(dev_base_lock);
200EXPORT_SYMBOL(dev_base_lock); 200EXPORT_SYMBOL(dev_base_lock);
201 201
202static inline void dev_base_seq_inc(struct net *net)
203{
204 while (++net->dev_base_seq == 0);
205}
206
202static inline struct hlist_head *dev_name_hash(struct net *net, const char *name) 207static inline struct hlist_head *dev_name_hash(struct net *net, const char *name)
203{ 208{
204 unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ)); 209 unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ));
@@ -237,6 +242,9 @@ static int list_netdevice(struct net_device *dev)
237 hlist_add_head_rcu(&dev->index_hlist, 242 hlist_add_head_rcu(&dev->index_hlist,
238 dev_index_hash(net, dev->ifindex)); 243 dev_index_hash(net, dev->ifindex));
239 write_unlock_bh(&dev_base_lock); 244 write_unlock_bh(&dev_base_lock);
245
246 dev_base_seq_inc(net);
247
240 return 0; 248 return 0;
241} 249}
242 250
@@ -253,6 +261,8 @@ static void unlist_netdevice(struct net_device *dev)
253 hlist_del_rcu(&dev->name_hlist); 261 hlist_del_rcu(&dev->name_hlist);
254 hlist_del_rcu(&dev->index_hlist); 262 hlist_del_rcu(&dev->index_hlist);
255 write_unlock_bh(&dev_base_lock); 263 write_unlock_bh(&dev_base_lock);
264
265 dev_base_seq_inc(dev_net(dev));
256} 266}
257 267
258/* 268/*
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index ea489db1bc23..5bbdbf0d3664 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -129,6 +129,7 @@ static __net_init int setup_net(struct net *net)
129 129
130 atomic_set(&net->count, 1); 130 atomic_set(&net->count, 1);
131 atomic_set(&net->passive, 1); 131 atomic_set(&net->passive, 1);
132 net->dev_base_seq = 1;
132 133
133#ifdef NETNS_REFCNT_DEBUG 134#ifdef NETNS_REFCNT_DEBUG
134 atomic_set(&net->use_count, 0); 135 atomic_set(&net->use_count, 0);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index a798fc6f2aa1..99d9e953fe39 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1032,6 +1032,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
1032 s_idx = cb->args[1]; 1032 s_idx = cb->args[1];
1033 1033
1034 rcu_read_lock(); 1034 rcu_read_lock();
1035 cb->seq = net->dev_base_seq;
1036
1035 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { 1037 for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1036 idx = 0; 1038 idx = 0;
1037 head = &net->dev_index_head[h]; 1039 head = &net->dev_index_head[h];
@@ -1043,6 +1045,8 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
1043 cb->nlh->nlmsg_seq, 0, 1045 cb->nlh->nlmsg_seq, 0,
1044 NLM_F_MULTI) <= 0) 1046 NLM_F_MULTI) <= 0)
1045 goto out; 1047 goto out;
1048
1049 nl_dump_check_consistent(cb, nlmsg_hdr(skb));
1046cont: 1050cont:
1047 idx++; 1051 idx++;
1048 } 1052 }