+Johannes and wireless ML. From: Alexandre Ferrieux <alexandre.ferrieux@xxxxxxxxx> Date: Sun, 15 Sep 2024 22:49:22 +0200 > (thanks Simon, reposting with another account to avoid the offending disclaimer) > > Hi, > > Currently, netns don't really scale beyond a few thousands, for > mundane reasons (see below). But should they ? Is there, in the > design, an assumption that tens of thousands of network namespaces are > considered "unreasonable" ? > > A typical use case for such ridiculous numbers is a tester for > firewalls or carrier-grade NATs. In these, you typically want tens of > thousands of tunnels, each of which is perfectly instantiated as an > interface. And, to avoid an explosion in source routing rules, you > want them in separate namespaces. > > Now why don't they scale *today* ? For two independent, seemingly > accidental, O(N) scans of the netns list. > > 1. The "netdevice notifier" from the Wireless Extensions subsystem > insists on scanning the whole list regardless of the nature of the > change, nor wondering whether all these namespaces hold any wireless > interface, nor even whether the system has _any_ wireless hardware... > > for_each_net(net) { > while ((skb = skb_dequeue(&net->wext_nlevents))) > rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, > GFP_KERNEL); > } > Alex forwarded this mail to me and asked about 1. I checked 8bf862739a778, but I didn't see why wext_netdev_notifier_call() needs to iterate all netns. Is there a case where flushing messages in the notified dev's netns is not enough for wext dev ? ---8<--- diff --git a/net/wireless/wext-core.c b/net/wireless/wext-core.c index 838ad6541a17..d4b613fc650c 100644 --- a/net/wireless/wext-core.c +++ b/net/wireless/wext-core.c @@ -343,17 +343,22 @@ static const int compat_event_type_size[] = { /* IW event code */ -void wireless_nlevent_flush(void) +static void wireless_nlevent_flush_net(struct net *net) { struct sk_buff *skb; + + while ((skb = skb_dequeue(&net->wext_nlevents))) + rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, + GFP_KERNEL); +} + +void wireless_nlevent_flush(void) +{ struct net *net; down_read(&net_rwsem); - for_each_net(net) { - while ((skb = skb_dequeue(&net->wext_nlevents))) - rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, - GFP_KERNEL); - } + for_each_net(net) + wireless_nlevent_flush_net(net); up_read(&net_rwsem); } EXPORT_SYMBOL_GPL(wireless_nlevent_flush); @@ -361,6 +366,8 @@ EXPORT_SYMBOL_GPL(wireless_nlevent_flush); static int wext_netdev_notifier_call(struct notifier_block *nb, unsigned long state, void *ptr) { + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + /* * When a netdev changes state in any way, flush all pending messages * to avoid them going out in a strange order, e.g. RTM_NEWLINK after @@ -368,7 +375,7 @@ static int wext_netdev_notifier_call(struct notifier_block *nb, * or similar - all of which could otherwise happen due to delays from * schedule_work(). */ - wireless_nlevent_flush(); + wireless_nlevent_flush_net(dev_net(dev)); return NOTIFY_OK; } ---8<---