Skip to content

Commit 4ce5dc9

Browse files
edumazetdavem330
authored andcommitted
inet: switch inet_dump_fib() to RCU protection
No longer hold RTNL while calling inet_dump_fib(). Also change return value for a completed dump: Returning 0 instead of skb->len allows NLMSG_DONE to be appended to the skb. User space does not have to call us again to get a standalone NLMSG_DONE marker. Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Donald Hunter <donald.hunter@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 0ac3fa0 commit 4ce5dc9

File tree

2 files changed

+20
-21
lines changed

2 files changed

+20
-21
lines changed

net/ipv4/fib_frontend.c

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -990,20 +990,21 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
990990
struct fib_dump_filter filter = {
991991
.dump_routes = true,
992992
.dump_exceptions = true,
993-
.rtnl_held = true,
993+
.rtnl_held = false,
994994
};
995995
const struct nlmsghdr *nlh = cb->nlh;
996996
struct net *net = sock_net(skb->sk);
997997
unsigned int h, s_h;
998998
unsigned int e = 0, s_e;
999999
struct fib_table *tb;
10001000
struct hlist_head *head;
1001-
int dumped = 0, err;
1001+
int dumped = 0, err = 0;
10021002

1003+
rcu_read_lock();
10031004
if (cb->strict_check) {
10041005
err = ip_valid_fib_dump_req(net, nlh, &filter, cb);
10051006
if (err < 0)
1006-
return err;
1007+
goto unlock;
10071008
} else if (nlmsg_len(nlh) >= sizeof(struct rtmsg)) {
10081009
struct rtmsg *rtm = nlmsg_data(nlh);
10091010

@@ -1012,29 +1013,28 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
10121013

10131014
/* ipv4 does not use prefix flag */
10141015
if (filter.flags & RTM_F_PREFIX)
1015-
return skb->len;
1016+
goto unlock;
10161017

10171018
if (filter.table_id) {
10181019
tb = fib_get_table(net, filter.table_id);
10191020
if (!tb) {
10201021
if (rtnl_msg_family(cb->nlh) != PF_INET)
1021-
return skb->len;
1022+
goto unlock;
10221023

10231024
NL_SET_ERR_MSG(cb->extack, "ipv4: FIB table does not exist");
1024-
return -ENOENT;
1025+
err = -ENOENT;
1026+
goto unlock;
10251027
}
1026-
1027-
rcu_read_lock();
10281028
err = fib_table_dump(tb, skb, cb, &filter);
1029-
rcu_read_unlock();
1030-
return skb->len ? : err;
1029+
if (err < 0 && skb->len)
1030+
err = skb->len;
1031+
goto unlock;
10311032
}
10321033

10331034
s_h = cb->args[0];
10341035
s_e = cb->args[1];
10351036

1036-
rcu_read_lock();
1037-
1037+
err = 0;
10381038
for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) {
10391039
e = 0;
10401040
head = &net->ipv4.fib_table_hash[h];
@@ -1047,23 +1047,21 @@ static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
10471047
err = fib_table_dump(tb, skb, cb, &filter);
10481048
if (err < 0) {
10491049
if (likely(skb->len))
1050-
goto out;
1051-
1052-
goto out_err;
1050+
err = skb->len;
1051+
goto out;
10531052
}
10541053
dumped = 1;
10551054
next:
10561055
e++;
10571056
}
10581057
}
10591058
out:
1060-
err = skb->len;
1061-
out_err:
1062-
rcu_read_unlock();
10631059

10641060
cb->args[1] = e;
10651061
cb->args[0] = h;
10661062

1063+
unlock:
1064+
rcu_read_unlock();
10671065
return err;
10681066
}
10691067

@@ -1666,5 +1664,6 @@ void __init ip_fib_init(void)
16661664

16671665
rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, 0);
16681666
rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, 0);
1669-
rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, 0);
1667+
rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib,
1668+
RTNL_FLAG_DUMP_UNLOCKED);
16701669
}

net/ipv4/fib_trie.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2368,7 +2368,7 @@ int fib_table_dump(struct fib_table *tb, struct sk_buff *skb,
23682368
* and key == 0 means the dump has wrapped around and we are done.
23692369
*/
23702370
if (count && !key)
2371-
return skb->len;
2371+
return 0;
23722372

23732373
while ((l = leaf_walk_rcu(&tp, key)) != NULL) {
23742374
int err;
@@ -2394,7 +2394,7 @@ int fib_table_dump(struct fib_table *tb, struct sk_buff *skb,
23942394
cb->args[3] = key;
23952395
cb->args[2] = count;
23962396

2397-
return skb->len;
2397+
return 0;
23982398
}
23992399

24002400
void __init fib_trie_init(void)

0 commit comments

Comments
 (0)