Commit 93642e14 authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller
Browse files

net: introduce dev_net notifier register/unregister variants



Introduce dev_net variants of netdev notifier register/unregister functions
and allow per-net notifier to follow the netdevice into the namespace it is
moved to.

Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1f637703
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -939,6 +939,11 @@ struct netdev_name_node {
int netdev_name_node_alt_create(struct net_device *dev, const char *name);
int netdev_name_node_alt_destroy(struct net_device *dev, const char *name);

struct netdev_net_notifier {
	struct list_head list;
	struct notifier_block *nb;
};

/*
 * This structure defines the management hooks for network devices.
 * The following hooks can be defined; unless noted otherwise, they are
@@ -1793,6 +1798,10 @@ enum netdev_priv_flags {
 *
 *	@wol_enabled:	Wake-on-LAN is enabled
 *
 *	@net_notifier_list:	List of per-net netdev notifier block
 *				that follow this device when it is moved
 *				to another network namespace.
 *
 *	FIXME: cleanup struct net_device such that network protocol info
 *	moves out.
 */
@@ -2085,6 +2094,8 @@ struct net_device {
	struct lock_class_key	addr_list_lock_key;
	bool			proto_down;
	unsigned		wol_enabled:1;

	struct list_head	net_notifier_list;
};
#define to_net_dev(d) container_of(d, struct net_device, dev)

@@ -2529,6 +2540,12 @@ 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);
int register_netdevice_notifier_dev_net(struct net_device *dev,
					struct notifier_block *nb,
					struct netdev_net_notifier *nn);
int unregister_netdevice_notifier_dev_net(struct net_device *dev,
					  struct notifier_block *nb,
					  struct netdev_net_notifier *nn);

struct netdev_notifier_info {
	struct net_device	*dev;
+46 −0
Original line number Diff line number Diff line
@@ -1874,6 +1874,48 @@ int unregister_netdevice_notifier_net(struct net *net,
}
EXPORT_SYMBOL(unregister_netdevice_notifier_net);

int register_netdevice_notifier_dev_net(struct net_device *dev,
					struct notifier_block *nb,
					struct netdev_net_notifier *nn)
{
	int err;

	rtnl_lock();
	err = __register_netdevice_notifier_net(dev_net(dev), nb, false);
	if (!err) {
		nn->nb = nb;
		list_add(&nn->list, &dev->net_notifier_list);
	}
	rtnl_unlock();
	return err;
}
EXPORT_SYMBOL(register_netdevice_notifier_dev_net);

int unregister_netdevice_notifier_dev_net(struct net_device *dev,
					  struct notifier_block *nb,
					  struct netdev_net_notifier *nn)
{
	int err;

	rtnl_lock();
	list_del(&nn->list);
	err = __unregister_netdevice_notifier_net(dev_net(dev), nb);
	rtnl_unlock();
	return err;
}
EXPORT_SYMBOL(unregister_netdevice_notifier_dev_net);

static void move_netdevice_notifiers_dev_net(struct net_device *dev,
					     struct net *net)
{
	struct netdev_net_notifier *nn;

	list_for_each_entry(nn, &dev->net_notifier_list, list) {
		__unregister_netdevice_notifier_net(dev_net(dev), nn->nb);
		__register_netdevice_notifier_net(net, nn->nb, true);
	}
}

/**
 *	call_netdevice_notifiers_info - call all network notifier blocks
 *	@val: value passed unmodified to notifier function
@@ -9786,6 +9828,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
	INIT_LIST_HEAD(&dev->adj_list.lower);
	INIT_LIST_HEAD(&dev->ptype_all);
	INIT_LIST_HEAD(&dev->ptype_specific);
	INIT_LIST_HEAD(&dev->net_notifier_list);
#ifdef CONFIG_NET_SCHED
	hash_init(dev->qdisc_hash);
#endif
@@ -10049,6 +10092,9 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
	kobject_uevent(&dev->dev.kobj, KOBJ_REMOVE);
	netdev_adjacent_del_links(dev);

	/* Move per-net netdevice notifiers that are following the netdevice */
	move_netdevice_notifiers_dev_net(dev, net);

	/* Actually switch the network namespace */
	dev_net_set(dev, net);
	dev->ifindex = new_ifindex;