Commit a30c7b42 authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller

net: introduce per-netns netdevice notifiers

Often the code for example in drivers is interested in getting notifier
call only from certain network namespace. In addition to the existing
global netdevice notifier chain introduce per-netns chains and allow
users to register to that. Eventually this would eliminate unnecessary
overhead in case there are many netdevices in many network namespaces.
Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent afa0df59
...@@ -2504,6 +2504,9 @@ const char *netdev_cmd_to_name(enum netdev_cmd cmd); ...@@ -2504,6 +2504,9 @@ const char *netdev_cmd_to_name(enum netdev_cmd cmd);
int register_netdevice_notifier(struct notifier_block *nb); int register_netdevice_notifier(struct notifier_block *nb);
int unregister_netdevice_notifier(struct notifier_block *nb); int unregister_netdevice_notifier(struct notifier_block *nb);
int register_netdevice_notifier_net(struct net *net, struct notifier_block *nb);
int unregister_netdevice_notifier_net(struct net *net,
struct notifier_block *nb);
struct netdev_notifier_info { struct netdev_notifier_info {
struct net_device *dev; struct net_device *dev;
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/ns_common.h> #include <linux/ns_common.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/notifier.h>
struct user_namespace; struct user_namespace;
struct proc_dir_entry; struct proc_dir_entry;
...@@ -96,6 +97,8 @@ struct net { ...@@ -96,6 +97,8 @@ struct net {
struct list_head dev_base_head; struct list_head dev_base_head;
struct hlist_head *dev_name_head; struct hlist_head *dev_name_head;
struct hlist_head *dev_index_head; struct hlist_head *dev_index_head;
struct raw_notifier_head netdev_chain;
unsigned int dev_base_seq; /* protected by rtnl_mutex */ unsigned int dev_base_seq; /* protected by rtnl_mutex */
int ifindex; int ifindex;
unsigned int dev_unreg_count; unsigned int dev_unreg_count;
......
...@@ -1874,6 +1874,80 @@ int unregister_netdevice_notifier(struct notifier_block *nb) ...@@ -1874,6 +1874,80 @@ int unregister_netdevice_notifier(struct notifier_block *nb)
} }
EXPORT_SYMBOL(unregister_netdevice_notifier); EXPORT_SYMBOL(unregister_netdevice_notifier);
/**
* register_netdevice_notifier_net - register a per-netns network notifier block
* @net: network namespace
* @nb: notifier
*
* Register a notifier to be called when network device events occur.
* The notifier passed is linked into the kernel structures and must
* not be reused until it has been unregistered. A negative errno code
* is returned on a failure.
*
* When registered all registration and up events are replayed
* to the new notifier to allow device to have a race free
* view of the network device list.
*/
int register_netdevice_notifier_net(struct net *net, struct notifier_block *nb)
{
int err;
rtnl_lock();
err = raw_notifier_chain_register(&net->netdev_chain, nb);
if (err)
goto unlock;
if (dev_boot_phase)
goto unlock;
err = call_netdevice_register_net_notifiers(nb, net);
if (err)
goto chain_unregister;
unlock:
rtnl_unlock();
return err;
chain_unregister:
raw_notifier_chain_unregister(&netdev_chain, nb);
goto unlock;
}
EXPORT_SYMBOL(register_netdevice_notifier_net);
/**
* unregister_netdevice_notifier_net - unregister a per-netns
* network notifier block
* @net: network namespace
* @nb: notifier
*
* Unregister a notifier previously registered by
* register_netdevice_notifier(). The notifier is unlinked into the
* kernel structures and may then be reused. A negative errno code
* is returned on a failure.
*
* After unregistering unregister and down device events are synthesized
* for all devices on the device list to the removed notifier to remove
* the need for special case cleanup code.
*/
int unregister_netdevice_notifier_net(struct net *net,
struct notifier_block *nb)
{
int err;
rtnl_lock();
err = raw_notifier_chain_unregister(&net->netdev_chain, nb);
if (err)
goto unlock;
call_netdevice_unregister_net_notifiers(nb, net);
unlock:
rtnl_unlock();
return err;
}
EXPORT_SYMBOL(unregister_netdevice_notifier_net);
/** /**
* call_netdevice_notifiers_info - call all network notifier blocks * call_netdevice_notifiers_info - call all network notifier blocks
* @val: value passed unmodified to notifier function * @val: value passed unmodified to notifier function
...@@ -1886,7 +1960,18 @@ EXPORT_SYMBOL(unregister_netdevice_notifier); ...@@ -1886,7 +1960,18 @@ EXPORT_SYMBOL(unregister_netdevice_notifier);
static int call_netdevice_notifiers_info(unsigned long val, static int call_netdevice_notifiers_info(unsigned long val,
struct netdev_notifier_info *info) struct netdev_notifier_info *info)
{ {
struct net *net = dev_net(info->dev);
int ret;
ASSERT_RTNL(); ASSERT_RTNL();
/* Run per-netns notifier block chain first, then run the global one.
* Hopefully, one day, the global one is going to be removed after
* all notifier block registrators get converted to be per-netns.
*/
ret = raw_notifier_call_chain(&net->netdev_chain, val, info);
if (ret & NOTIFY_STOP_MASK)
return ret;
return raw_notifier_call_chain(&netdev_chain, val, info); return raw_notifier_call_chain(&netdev_chain, val, info);
} }
...@@ -9785,6 +9870,8 @@ static int __net_init netdev_init(struct net *net) ...@@ -9785,6 +9870,8 @@ static int __net_init netdev_init(struct net *net)
if (net->dev_index_head == NULL) if (net->dev_index_head == NULL)
goto err_idx; goto err_idx;
RAW_INIT_NOTIFIER_HEAD(&net->netdev_chain);
return 0; return 0;
err_idx: err_idx:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment