ipv4: provide addr and netconf dump consistency info
authorNicolas Dichtel <nicolas.dichtel@6wind.com>
Fri, 22 Mar 2013 06:28:42 +0000 (06:28 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sun, 24 Mar 2013 21:16:29 +0000 (17:16 -0400)
This patch takes benefit of dev_addr_genid and dev_base_seq to check if a change
occurs during a netlink dump. If a change is detected, the flag NLM_F_DUMP_INTR
is set in the first message after the dump was interrupted.

Note that seq and prev_seq must be reset between each family in rtnl_dump_all()
because they are specific to each family.

Reported-by: Junwei Zhang <junwei.zhang@6wind.com>
Reported-by: Hongjun Li <hongjun.li@6wind.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/rtnetlink.c
net/ipv4/devinet.c

index 751f1244b6489e73d4493e7e76a4f4ad13aa4e59..aeb81316a7042438e5ef3b20c798eedf8746365f 100644 (file)
@@ -1929,8 +1929,11 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
                if (rtnl_msg_handlers[idx] == NULL ||
                    rtnl_msg_handlers[idx][type].dumpit == NULL)
                        continue;
-               if (idx > s_idx)
+               if (idx > s_idx) {
                        memset(&cb->args[0], 0, sizeof(cb->args));
+                       cb->prev_seq = 0;
+                       cb->seq = 0;
+               }
                if (rtnl_msg_handlers[idx][type].dumpit(skb, cb))
                        break;
        }
index 20a9f9274f3feb3d13e361346dae0bf4bfd20dc4..5d985e36753526f4b9cfb37cde3be352556a4b0c 100644 (file)
@@ -1499,6 +1499,8 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
                idx = 0;
                head = &net->dev_index_head[h];
                rcu_read_lock();
+               cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
+                         net->dev_base_seq;
                hlist_for_each_entry_rcu(dev, head, index_hlist) {
                        if (idx < s_idx)
                                goto cont;
@@ -1519,6 +1521,7 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
                                        rcu_read_unlock();
                                        goto done;
                                }
+                               nl_dump_check_consistent(cb, nlmsg_hdr(skb));
                        }
 cont:
                        idx++;
@@ -1807,6 +1810,8 @@ static int inet_netconf_dump_devconf(struct sk_buff *skb,
                idx = 0;
                head = &net->dev_index_head[h];
                rcu_read_lock();
+               cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^
+                         net->dev_base_seq;
                hlist_for_each_entry_rcu(dev, head, index_hlist) {
                        if (idx < s_idx)
                                goto cont;
@@ -1824,6 +1829,7 @@ static int inet_netconf_dump_devconf(struct sk_buff *skb,
                                rcu_read_unlock();
                                goto done;
                        }
+                       nl_dump_check_consistent(cb, nlmsg_hdr(skb));
 cont:
                        idx++;
                }