forked from mirrors/linux
		
	rtnetlink: use xarray iterator to implement rtnl_dump_ifinfo()
Adopt net->dev_by_index as I did in commit 0e0939c0ad
("net-procfs: use xarray iterator to implement /proc/net/dev")
This makes sure an existing device is always visible in the dump,
regardless of concurrent insertions/deletions.
v2: added suggestions from Jakub Kicinski and Ido Schimmel,
    thanks for the help !
Link: https://lore.kernel.org/all/20240209142441.6c56435b@kernel.org/
Link: https://lore.kernel.org/all/ZckR-XOsULLI9EHc@shredder/
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://lore.kernel.org/r/20240211214404.1882191-3-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
			
			
This commit is contained in:
		
							parent
							
								
									f383ced24d
								
							
						
					
					
						commit
						3e41af9076
					
				
					 1 changed files with 21 additions and 39 deletions
				
			
		|  | @ -2188,25 +2188,22 @@ static int rtnl_valid_dump_ifinfo_req(const struct nlmsghdr *nlh, | ||||||
| 
 | 
 | ||||||
| static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | ||||||
| { | { | ||||||
|  | 	const struct rtnl_link_ops *kind_ops = NULL; | ||||||
| 	struct netlink_ext_ack *extack = cb->extack; | 	struct netlink_ext_ack *extack = cb->extack; | ||||||
| 	const struct nlmsghdr *nlh = cb->nlh; | 	const struct nlmsghdr *nlh = cb->nlh; | ||||||
| 	struct net *net = sock_net(skb->sk); | 	struct net *net = sock_net(skb->sk); | ||||||
| 	struct net *tgt_net = net; |  | ||||||
| 	int h, s_h; |  | ||||||
| 	int idx = 0, s_idx; |  | ||||||
| 	struct net_device *dev; |  | ||||||
| 	struct hlist_head *head; |  | ||||||
| 	struct nlattr *tb[IFLA_MAX+1]; |  | ||||||
| 	u32 ext_filter_mask = 0; |  | ||||||
| 	const struct rtnl_link_ops *kind_ops = NULL; |  | ||||||
| 	unsigned int flags = NLM_F_MULTI; | 	unsigned int flags = NLM_F_MULTI; | ||||||
|  | 	struct nlattr *tb[IFLA_MAX+1]; | ||||||
|  | 	struct { | ||||||
|  | 		unsigned long ifindex; | ||||||
|  | 	} *ctx = (void *)cb->ctx; | ||||||
|  | 	struct net *tgt_net = net; | ||||||
|  | 	u32 ext_filter_mask = 0; | ||||||
|  | 	struct net_device *dev; | ||||||
| 	int master_idx = 0; | 	int master_idx = 0; | ||||||
| 	int netnsid = -1; | 	int netnsid = -1; | ||||||
| 	int err, i; | 	int err, i; | ||||||
| 
 | 
 | ||||||
| 	s_h = cb->args[0]; |  | ||||||
| 	s_idx = cb->args[1]; |  | ||||||
| 
 |  | ||||||
| 	err = rtnl_valid_dump_ifinfo_req(nlh, cb->strict_check, tb, extack); | 	err = rtnl_valid_dump_ifinfo_req(nlh, cb->strict_check, tb, extack); | ||||||
| 	if (err < 0) { | 	if (err < 0) { | ||||||
| 		if (cb->strict_check) | 		if (cb->strict_check) | ||||||
|  | @ -2250,36 +2247,21 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) | ||||||
| 		flags |= NLM_F_DUMP_FILTERED; | 		flags |= NLM_F_DUMP_FILTERED; | ||||||
| 
 | 
 | ||||||
| walk_entries: | walk_entries: | ||||||
| 	for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { | 	err = 0; | ||||||
| 		idx = 0; | 	for_each_netdev_dump(tgt_net, dev, ctx->ifindex) { | ||||||
| 		head = &tgt_net->dev_index_head[h]; | 		if (link_dump_filtered(dev, master_idx, kind_ops)) | ||||||
| 		hlist_for_each_entry(dev, head, index_hlist) { | 			continue; | ||||||
| 			if (link_dump_filtered(dev, master_idx, kind_ops)) | 		err = rtnl_fill_ifinfo(skb, dev, net, RTM_NEWLINK, | ||||||
| 				goto cont; | 				       NETLINK_CB(cb->skb).portid, | ||||||
| 			if (idx < s_idx) | 				       nlh->nlmsg_seq, 0, flags, | ||||||
| 				goto cont; | 				       ext_filter_mask, 0, NULL, 0, | ||||||
| 			err = rtnl_fill_ifinfo(skb, dev, net, | 				       netnsid, GFP_KERNEL); | ||||||
| 					       RTM_NEWLINK, | 		if (err < 0) { | ||||||
| 					       NETLINK_CB(cb->skb).portid, | 			if (likely(skb->len)) | ||||||
| 					       nlh->nlmsg_seq, 0, flags, | 				err = skb->len; | ||||||
| 					       ext_filter_mask, 0, NULL, 0, | 			break; | ||||||
| 					       netnsid, GFP_KERNEL); |  | ||||||
| 
 |  | ||||||
| 			if (err < 0) { |  | ||||||
| 				if (likely(skb->len)) |  | ||||||
| 					goto out; |  | ||||||
| 
 |  | ||||||
| 				goto out_err; |  | ||||||
| 			} |  | ||||||
| cont: |  | ||||||
| 			idx++; |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| out: |  | ||||||
| 	err = skb->len; |  | ||||||
| out_err: |  | ||||||
| 	cb->args[1] = idx; |  | ||||||
| 	cb->args[0] = h; |  | ||||||
| 	cb->seq = tgt_net->dev_base_seq; | 	cb->seq = tgt_net->dev_base_seq; | ||||||
| 	nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | 	nl_dump_check_consistent(cb, nlmsg_hdr(skb)); | ||||||
| 	if (netnsid >= 0) | 	if (netnsid >= 0) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Eric Dumazet
						Eric Dumazet