bond: Implement a basic set of rtnl link ops
authorEric W. Biederman <ebiederm@aristanetworks.com>
Thu, 29 Oct 2009 14:18:25 +0000 (14:18 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 30 Oct 2009 19:41:21 +0000 (12:41 -0700)
This implements a basic set of rtnl link ops and takes advantage of
the fact that rtnl_link_unregister kills all of the surviving
devices to all us to kill bond_free_all.  A module alias
is added so ip link add can pull in the bonding module.

Signed-off-by: Eric W. Biederman <ebiederm@aristanetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/bonding/bond_main.c

index db9640b43d01208122c6d64b7b6b78bf1cecaff6..405971374fe246f71d97662ad7ab0fc7b7302a01 100644 (file)
@@ -4612,22 +4612,6 @@ static void bond_uninit(struct net_device *bond_dev)
        netif_addr_unlock_bh(bond_dev);
 }
 
-/* Unregister and free all bond devices.
- * Caller must hold rtnl_lock.
- */
-static void bond_free_all(void)
-{
-       struct bonding *bond, *nxt;
-
-       list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
-               struct net_device *bond_dev = bond->dev;
-
-               unregister_netdevice(bond_dev);
-       }
-
-       bond_destroy_proc_dir();
-}
-
 /*------------------------- Module initialization ---------------------------*/
 
 /*
@@ -5065,6 +5049,23 @@ static int bond_init(struct net_device *bond_dev)
        return 0;
 }
 
+static int bond_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+       if (tb[IFLA_ADDRESS]) {
+               if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+                       return -EINVAL;
+               if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+                       return -EADDRNOTAVAIL;
+       }
+       return 0;
+}
+
+static struct rtnl_link_ops bond_link_ops __read_mostly = {
+       .kind           = "bond",
+       .setup          = bond_setup,
+       .validate       = bond_validate,
+};
+
 /* Create a new bond based on the specified name and bonding parameters.
  * If name is NULL, obtain a suitable "bond%d" name for us.
  * Caller must NOT hold rtnl_lock; we need to release it here before we
@@ -5086,6 +5087,8 @@ int bond_create(const char *name)
                goto out;
        }
 
+       bond_dev->rtnl_link_ops = &bond_link_ops;
+
        if (!name) {
                res = dev_alloc_name(bond_dev, "bond%d");
                if (res < 0)
@@ -5115,6 +5118,10 @@ static int __init bonding_init(void)
 
        bond_create_proc_dir();
 
+       res = rtnl_link_register(&bond_link_ops);
+       if (res)
+               goto err;
+
        for (i = 0; i < max_bonds; i++) {
                res = bond_create(NULL);
                if (res)
@@ -5128,14 +5135,12 @@ static int __init bonding_init(void)
        register_netdevice_notifier(&bond_netdev_notifier);
        register_inetaddr_notifier(&bond_inetaddr_notifier);
        bond_register_ipv6_notifier();
-
-       goto out;
-err:
-       rtnl_lock();
-       bond_free_all();
-       rtnl_unlock();
 out:
        return res;
+err:
+       rtnl_link_unregister(&bond_link_ops);
+       bond_destroy_proc_dir();
+       goto out;
 
 }
 
@@ -5147,9 +5152,8 @@ static void __exit bonding_exit(void)
 
        bond_destroy_sysfs();
 
-       rtnl_lock();
-       bond_free_all();
-       rtnl_unlock();
+       rtnl_link_unregister(&bond_link_ops);
+       bond_destroy_proc_dir();
 }
 
 module_init(bonding_init);
@@ -5158,3 +5162,4 @@ MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 MODULE_DESCRIPTION(DRV_DESCRIPTION ", v" DRV_VERSION);
 MODULE_AUTHOR("Thomas Davis, tadavis@lbl.gov and many others");
+MODULE_ALIAS_RTNL_LINK("bond");