aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJiri Pirko <jiri@resnulli.us>2013-01-03 17:48:49 -0500
committerDavid S. Miller <davem@davemloft.net>2013-01-04 16:31:49 -0500
commit9ff162a8b96c96238773972e26288a366e403b0c (patch)
treeae74065e46364c807a1996e5268aec349d9d86d4 /net
parent04e406dcc54cfd84d333ea673fa986fb5a1840e7 (diff)
net: introduce upper device lists
This lists are supposed to serve for storing pointers to all upper devices. Eventually it will replace dev->master pointer which is used for bonding, bridge, team but it cannot be used for vlan, macvlan where there might be multiple upper present. In case the upper link is replacement for dev->master, it is marked with "master" flag. New upper device list resolves this limitation. Also, the information stored in lists is used for preventing looping setups like "bond->somethingelse->samebond" Signed-off-by: Jiri Pirko <jiri@resnulli.us> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/dev.c239
1 files changed, 235 insertions, 4 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index bddb2f2ccaa9..53a9fefbc9af 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4600,6 +4600,232 @@ static int __init dev_proc_init(void)
4600#endif /* CONFIG_PROC_FS */ 4600#endif /* CONFIG_PROC_FS */
4601 4601
4602 4602
4603struct netdev_upper {
4604 struct net_device *dev;
4605 bool master;
4606 struct list_head list;
4607 struct rcu_head rcu;
4608 struct list_head search_list;
4609};
4610
4611static void __append_search_uppers(struct list_head *search_list,
4612 struct net_device *dev)
4613{
4614 struct netdev_upper *upper;
4615
4616 list_for_each_entry(upper, &dev->upper_dev_list, list) {
4617 /* check if this upper is not already in search list */
4618 if (list_empty(&upper->search_list))
4619 list_add_tail(&upper->search_list, search_list);
4620 }
4621}
4622
4623static bool __netdev_search_upper_dev(struct net_device *dev,
4624 struct net_device *upper_dev)
4625{
4626 LIST_HEAD(search_list);
4627 struct netdev_upper *upper;
4628 struct netdev_upper *tmp;
4629 bool ret = false;
4630
4631 __append_search_uppers(&search_list, dev);
4632 list_for_each_entry(upper, &search_list, search_list) {
4633 if (upper->dev == upper_dev) {
4634 ret = true;
4635 break;
4636 }
4637 __append_search_uppers(&search_list, upper->dev);
4638 }
4639 list_for_each_entry_safe(upper, tmp, &search_list, search_list)
4640 INIT_LIST_HEAD(&upper->search_list);
4641 return ret;
4642}
4643
4644static struct netdev_upper *__netdev_find_upper(struct net_device *dev,
4645 struct net_device *upper_dev)
4646{
4647 struct netdev_upper *upper;
4648
4649 list_for_each_entry(upper, &dev->upper_dev_list, list) {
4650 if (upper->dev == upper_dev)
4651 return upper;
4652 }
4653 return NULL;
4654}
4655
4656/**
4657 * netdev_has_upper_dev - Check if device is linked to an upper device
4658 * @dev: device
4659 * @upper_dev: upper device to check
4660 *
4661 * Find out if a device is linked to specified upper device and return true
4662 * in case it is. Note that this checks only immediate upper device,
4663 * not through a complete stack of devices. The caller must hold the RTNL lock.
4664 */
4665bool netdev_has_upper_dev(struct net_device *dev,
4666 struct net_device *upper_dev)
4667{
4668 ASSERT_RTNL();
4669
4670 return __netdev_find_upper(dev, upper_dev);
4671}
4672EXPORT_SYMBOL(netdev_has_upper_dev);
4673
4674/**
4675 * netdev_has_any_upper_dev - Check if device is linked to some device
4676 * @dev: device
4677 *
4678 * Find out if a device is linked to an upper device and return true in case
4679 * it is. The caller must hold the RTNL lock.
4680 */
4681bool netdev_has_any_upper_dev(struct net_device *dev)
4682{
4683 ASSERT_RTNL();
4684
4685 return !list_empty(&dev->upper_dev_list);
4686}
4687EXPORT_SYMBOL(netdev_has_any_upper_dev);
4688
4689/**
4690 * netdev_master_upper_dev_get - Get master upper device
4691 * @dev: device
4692 *
4693 * Find a master upper device and return pointer to it or NULL in case
4694 * it's not there. The caller must hold the RTNL lock.
4695 */
4696struct net_device *netdev_master_upper_dev_get(struct net_device *dev)
4697{
4698 struct netdev_upper *upper;
4699
4700 ASSERT_RTNL();
4701
4702 if (list_empty(&dev->upper_dev_list))
4703 return NULL;
4704
4705 upper = list_first_entry(&dev->upper_dev_list,
4706 struct netdev_upper, list);
4707 if (likely(upper->master))
4708 return upper->dev;
4709 return NULL;
4710}
4711EXPORT_SYMBOL(netdev_master_upper_dev_get);
4712
4713/**
4714 * netdev_master_upper_dev_get_rcu - Get master upper device
4715 * @dev: device
4716 *
4717 * Find a master upper device and return pointer to it or NULL in case
4718 * it's not there. The caller must hold the RCU read lock.
4719 */
4720struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev)
4721{
4722 struct netdev_upper *upper;
4723
4724 upper = list_first_or_null_rcu(&dev->upper_dev_list,
4725 struct netdev_upper, list);
4726 if (upper && likely(upper->master))
4727 return upper->dev;
4728 return NULL;
4729}
4730EXPORT_SYMBOL(netdev_master_upper_dev_get_rcu);
4731
4732static int __netdev_upper_dev_link(struct net_device *dev,
4733 struct net_device *upper_dev, bool master)
4734{
4735 struct netdev_upper *upper;
4736
4737 ASSERT_RTNL();
4738
4739 if (dev == upper_dev)
4740 return -EBUSY;
4741
4742 /* To prevent loops, check if dev is not upper device to upper_dev. */
4743 if (__netdev_search_upper_dev(upper_dev, dev))
4744 return -EBUSY;
4745
4746 if (__netdev_find_upper(dev, upper_dev))
4747 return -EEXIST;
4748
4749 if (master && netdev_master_upper_dev_get(dev))
4750 return -EBUSY;
4751
4752 upper = kmalloc(sizeof(*upper), GFP_KERNEL);
4753 if (!upper)
4754 return -ENOMEM;
4755
4756 upper->dev = upper_dev;
4757 upper->master = master;
4758 INIT_LIST_HEAD(&upper->search_list);
4759
4760 /* Ensure that master upper link is always the first item in list. */
4761 if (master)
4762 list_add_rcu(&upper->list, &dev->upper_dev_list);
4763 else
4764 list_add_tail_rcu(&upper->list, &dev->upper_dev_list);
4765 dev_hold(upper_dev);
4766
4767 return 0;
4768}
4769
4770/**
4771 * netdev_upper_dev_link - Add a link to the upper device
4772 * @dev: device
4773 * @upper_dev: new upper device
4774 *
4775 * Adds a link to device which is upper to this one. The caller must hold
4776 * the RTNL lock. On a failure a negative errno code is returned.
4777 * On success the reference counts are adjusted and the function
4778 * returns zero.
4779 */
4780int netdev_upper_dev_link(struct net_device *dev,
4781 struct net_device *upper_dev)
4782{
4783 return __netdev_upper_dev_link(dev, upper_dev, false);
4784}
4785EXPORT_SYMBOL(netdev_upper_dev_link);
4786
4787/**
4788 * netdev_master_upper_dev_link - Add a master link to the upper device
4789 * @dev: device
4790 * @upper_dev: new upper device
4791 *
4792 * Adds a link to device which is upper to this one. In this case, only
4793 * one master upper device can be linked, although other non-master devices
4794 * might be linked as well. The caller must hold the RTNL lock.
4795 * On a failure a negative errno code is returned. On success the reference
4796 * counts are adjusted and the function returns zero.
4797 */
4798int netdev_master_upper_dev_link(struct net_device *dev,
4799 struct net_device *upper_dev)
4800{
4801 return __netdev_upper_dev_link(dev, upper_dev, true);
4802}
4803EXPORT_SYMBOL(netdev_master_upper_dev_link);
4804
4805/**
4806 * netdev_upper_dev_unlink - Removes a link to upper device
4807 * @dev: device
4808 * @upper_dev: new upper device
4809 *
4810 * Removes a link to device which is upper to this one. The caller must hold
4811 * the RTNL lock.
4812 */
4813void netdev_upper_dev_unlink(struct net_device *dev,
4814 struct net_device *upper_dev)
4815{
4816 struct netdev_upper *upper;
4817
4818 ASSERT_RTNL();
4819
4820 upper = __netdev_find_upper(dev, upper_dev);
4821 if (!upper)
4822 return;
4823 list_del_rcu(&upper->list);
4824 dev_put(upper_dev);
4825 kfree_rcu(upper, rcu);
4826}
4827EXPORT_SYMBOL(netdev_upper_dev_unlink);
4828
4603/** 4829/**
4604 * netdev_set_master - set up master pointer 4830 * netdev_set_master - set up master pointer
4605 * @slave: slave device 4831 * @slave: slave device
@@ -4613,19 +4839,23 @@ static int __init dev_proc_init(void)
4613int netdev_set_master(struct net_device *slave, struct net_device *master) 4839int netdev_set_master(struct net_device *slave, struct net_device *master)
4614{ 4840{
4615 struct net_device *old = slave->master; 4841 struct net_device *old = slave->master;
4842 int err;
4616 4843
4617 ASSERT_RTNL(); 4844 ASSERT_RTNL();
4618 4845
4619 if (master) { 4846 if (master) {
4620 if (old) 4847 if (old)
4621 return -EBUSY; 4848 return -EBUSY;
4622 dev_hold(master); 4849 err = netdev_master_upper_dev_link(slave, master);
4850 if (err)
4851 return err;
4623 } 4852 }
4624 4853
4625 slave->master = master; 4854 slave->master = master;
4626 4855
4627 if (old) 4856 if (old)
4628 dev_put(old); 4857 netdev_upper_dev_unlink(slave, master);
4858
4629 return 0; 4859 return 0;
4630} 4860}
4631EXPORT_SYMBOL(netdev_set_master); 4861EXPORT_SYMBOL(netdev_set_master);
@@ -5503,8 +5733,8 @@ static void rollback_registered_many(struct list_head *head)
5503 if (dev->netdev_ops->ndo_uninit) 5733 if (dev->netdev_ops->ndo_uninit)
5504 dev->netdev_ops->ndo_uninit(dev); 5734 dev->netdev_ops->ndo_uninit(dev);
5505 5735
5506 /* Notifier chain MUST detach us from master device. */ 5736 /* Notifier chain MUST detach us all upper devices. */
5507 WARN_ON(dev->master); 5737 WARN_ON(netdev_has_any_upper_dev(dev));
5508 5738
5509 /* Remove entries from kobject tree */ 5739 /* Remove entries from kobject tree */
5510 netdev_unregister_kobject(dev); 5740 netdev_unregister_kobject(dev);
@@ -6212,6 +6442,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
6212 INIT_LIST_HEAD(&dev->napi_list); 6442 INIT_LIST_HEAD(&dev->napi_list);
6213 INIT_LIST_HEAD(&dev->unreg_list); 6443 INIT_LIST_HEAD(&dev->unreg_list);
6214 INIT_LIST_HEAD(&dev->link_watch_list); 6444 INIT_LIST_HEAD(&dev->link_watch_list);
6445 INIT_LIST_HEAD(&dev->upper_dev_list);
6215 dev->priv_flags = IFF_XMIT_DST_RELEASE; 6446 dev->priv_flags = IFF_XMIT_DST_RELEASE;
6216 setup(dev); 6447 setup(dev);
6217 6448