| 
									
										
										
										
											2013-10-18 17:43:33 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * drivers/net/bond/bond_netlink.c - Netlink interface for bonding | 
					
						
							|  |  |  |  * Copyright (c) 2013 Jiri Pirko <jiri@resnulli.us> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  * the Free Software Foundation; either version 2 of the License, or | 
					
						
							|  |  |  |  * (at your option) any later version. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/module.h>
 | 
					
						
							|  |  |  | #include <linux/errno.h>
 | 
					
						
							|  |  |  | #include <linux/netdevice.h>
 | 
					
						
							|  |  |  | #include <linux/etherdevice.h>
 | 
					
						
							|  |  |  | #include <linux/if_link.h>
 | 
					
						
							|  |  |  | #include <linux/if_ether.h>
 | 
					
						
							|  |  |  | #include <net/netlink.h>
 | 
					
						
							|  |  |  | #include <net/rtnetlink.h>
 | 
					
						
							|  |  |  | #include "bonding.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:38 +02:00
										 |  |  | static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = { | 
					
						
							|  |  |  | 	[IFLA_BOND_MODE]		= { .type = NLA_U8 }, | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:39 +02:00
										 |  |  | 	[IFLA_BOND_ACTIVE_SLAVE]	= { .type = NLA_U32 }, | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:38 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:33 +02:00
										 |  |  | 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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:38 +02:00
										 |  |  | static int bond_changelink(struct net_device *bond_dev, | 
					
						
							|  |  |  | 			   struct nlattr *tb[], struct nlattr *data[]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct bonding *bond = netdev_priv(bond_dev); | 
					
						
							|  |  |  | 	int err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (data && data[IFLA_BOND_MODE]) { | 
					
						
							|  |  |  | 		int mode = nla_get_u8(data[IFLA_BOND_MODE]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		err = bond_option_mode_set(bond, mode); | 
					
						
							|  |  |  | 		if (err) | 
					
						
							|  |  |  | 			return err; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:39 +02:00
										 |  |  | 	if (data && data[IFLA_BOND_ACTIVE_SLAVE]) { | 
					
						
							|  |  |  | 		int ifindex = nla_get_u32(data[IFLA_BOND_ACTIVE_SLAVE]); | 
					
						
							|  |  |  | 		struct net_device *slave_dev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (ifindex == 0) { | 
					
						
							|  |  |  | 			slave_dev = NULL; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			slave_dev = __dev_get_by_index(dev_net(bond_dev), | 
					
						
							|  |  |  | 						       ifindex); | 
					
						
							|  |  |  | 			if (!slave_dev) | 
					
						
							|  |  |  | 				return -ENODEV; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		err = bond_option_active_slave_set(bond, slave_dev); | 
					
						
							|  |  |  | 		if (err) | 
					
						
							|  |  |  | 			return err; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:38 +02:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int bond_newlink(struct net *src_net, struct net_device *bond_dev, | 
					
						
							|  |  |  | 			struct nlattr *tb[], struct nlattr *data[]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = bond_changelink(bond_dev, tb, data); | 
					
						
							|  |  |  | 	if (err < 0) | 
					
						
							|  |  |  | 		return err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return register_netdevice(bond_dev); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static size_t bond_get_size(const struct net_device *bond_dev) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-01 13:18:44 +03:00
										 |  |  | 	return nla_total_size(sizeof(u8)) +	/* IFLA_BOND_MODE */ | 
					
						
							|  |  |  | 		nla_total_size(sizeof(u32));	/* IFLA_BOND_ACTIVE_SLAVE */ | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:38 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int bond_fill_info(struct sk_buff *skb, | 
					
						
							|  |  |  | 			  const struct net_device *bond_dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct bonding *bond = netdev_priv(bond_dev); | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:39 +02:00
										 |  |  | 	struct net_device *slave_dev = bond_option_active_slave_get(bond); | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:38 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:39 +02:00
										 |  |  | 	if (nla_put_u8(skb, IFLA_BOND_MODE, bond->params.mode) || | 
					
						
							|  |  |  | 	    (slave_dev && | 
					
						
							|  |  |  | 	     nla_put_u32(skb, IFLA_BOND_ACTIVE_SLAVE, slave_dev->ifindex))) | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:38 +02:00
										 |  |  | 		goto nla_put_failure; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | nla_put_failure: | 
					
						
							|  |  |  | 	return -EMSGSIZE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:33 +02:00
										 |  |  | struct rtnl_link_ops bond_link_ops __read_mostly = { | 
					
						
							|  |  |  | 	.kind			= "bond", | 
					
						
							|  |  |  | 	.priv_size		= sizeof(struct bonding), | 
					
						
							|  |  |  | 	.setup			= bond_setup, | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:38 +02:00
										 |  |  | 	.maxtype		= IFLA_BOND_MAX, | 
					
						
							|  |  |  | 	.policy			= bond_policy, | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:33 +02:00
										 |  |  | 	.validate		= bond_validate, | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:38 +02:00
										 |  |  | 	.newlink		= bond_newlink, | 
					
						
							|  |  |  | 	.changelink		= bond_changelink, | 
					
						
							|  |  |  | 	.get_size		= bond_get_size, | 
					
						
							|  |  |  | 	.fill_info		= bond_fill_info, | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:33 +02:00
										 |  |  | 	.get_num_tx_queues	= bond_get_num_tx_queues, | 
					
						
							|  |  |  | 	.get_num_rx_queues	= bond_get_num_tx_queues, /* Use the same number
 | 
					
						
							|  |  |  | 							     as for TX queues */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int __init bond_netlink_init(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return rtnl_link_register(&bond_link_ops); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-10-19 19:09:18 -04:00
										 |  |  | void bond_netlink_fini(void) | 
					
						
							| 
									
										
										
										
											2013-10-18 17:43:33 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	rtnl_link_unregister(&bond_link_ops); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MODULE_ALIAS_RTNL_LINK("bond"); |