bond_sysfs.c

来自「linux 内核源代码」· C语言 代码 · 共 1,485 行 · 第 1/3 页

C
1,485
字号
/* * Copyright(c) 2004-2005 Intel Corporation. All rights reserved. * * 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. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. * * The full GNU General Public License is included in this distribution in the * file called LICENSE. * */#include <linux/kernel.h>#include <linux/module.h>#include <linux/device.h>#include <linux/sysdev.h>#include <linux/fs.h>#include <linux/types.h>#include <linux/string.h>#include <linux/netdevice.h>#include <linux/inetdevice.h>#include <linux/in.h>#include <linux/sysfs.h>#include <linux/ctype.h>#include <linux/inet.h>#include <linux/rtnetlink.h>#include <net/net_namespace.h>/* #define BONDING_DEBUG 1 */#include "bonding.h"#define to_dev(obj)	container_of(obj,struct device,kobj)#define to_bond(cd)	((struct bonding *)(to_net_dev(cd)->priv))/*---------------------------- Declarations -------------------------------*/extern struct list_head bond_dev_list;extern struct bond_params bonding_defaults;extern struct bond_parm_tbl bond_mode_tbl[];extern struct bond_parm_tbl bond_lacp_tbl[];extern struct bond_parm_tbl xmit_hashtype_tbl[];extern struct bond_parm_tbl arp_validate_tbl[];static int expected_refcount = -1;static struct class *netdev_class;/*--------------------------- Data Structures -----------------------------*//* Bonding sysfs lock.  Why can't we just use the subsystem lock? * Because kobject_register tries to acquire the subsystem lock.  If * we already hold the lock (which we would if the user was creating * a new bond through the sysfs interface), we deadlock. * This lock is only needed when deleting a bond - we need to make sure * that we don't collide with an ongoing ioctl. */struct rw_semaphore bonding_rwsem;/*------------------------------ Functions --------------------------------*//* * "show" function for the bond_masters attribute. * The class parameter is ignored. */static ssize_t bonding_show_bonds(struct class *cls, char *buf){	int res = 0;	struct bonding *bond;	down_read(&(bonding_rwsem));	list_for_each_entry(bond, &bond_dev_list, bond_list) {		if (res > (PAGE_SIZE - IFNAMSIZ)) {			/* not enough space for another interface name */			if ((PAGE_SIZE - res) > 10)				res = PAGE_SIZE - 10;			res += sprintf(buf + res, "++more++ ");			break;		}		res += sprintf(buf + res, "%s ", bond->dev->name);	}	if (res)		buf[res-1] = '\n'; /* eat the leftover space */	up_read(&(bonding_rwsem));	return res;}/* * "store" function for the bond_masters attribute.  This is what * creates and deletes entire bonds. * * The class parameter is ignored. * */static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t count){	char command[IFNAMSIZ + 1] = {0, };	char *ifname;	int rv, res = count;	struct bonding *bond;	struct bonding *nxt;	sscanf(buffer, "%16s", command); /* IFNAMSIZ*/	ifname = command + 1;	if ((strlen(command) <= 1) ||	    !dev_valid_name(ifname))		goto err_no_cmd;	if (command[0] == '+') {		printk(KERN_INFO DRV_NAME			": %s is being created...\n", ifname);		rv = bond_create(ifname, &bonding_defaults, &bond);		if (rv) {			printk(KERN_INFO DRV_NAME ": Bond creation failed.\n");			res = rv;		}		goto out;	}	if (command[0] == '-') {		rtnl_lock();		down_write(&bonding_rwsem);		list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)			if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) {				/* check the ref count on the bond's kobject.				 * If it's > expected, then there's a file open,				 * and we have to fail.				 */				if (atomic_read(&bond->dev->dev.kobj.kref.refcount)							> expected_refcount){					printk(KERN_INFO DRV_NAME						": Unable remove bond %s due to open references.\n",						ifname);					res = -EPERM;					goto out;				}				printk(KERN_INFO DRV_NAME					": %s is being deleted...\n",					bond->dev->name);				bond_destroy(bond);				up_write(&bonding_rwsem);				rtnl_unlock();				goto out;			}		printk(KERN_ERR DRV_NAME			": unable to delete non-existent bond %s\n", ifname);		res = -ENODEV;		up_write(&bonding_rwsem);		rtnl_unlock();		goto out;	}err_no_cmd:	printk(KERN_ERR DRV_NAME		": no command found in bonding_masters. Use +ifname or -ifname.\n");	res = -EPERM;	/* Always return either count or an error.  If you return 0, you'll	 * get called forever, which is bad.	 */out:	return res;}/* class attribute for bond_masters file.  This ends up in /sys/class/net */static CLASS_ATTR(bonding_masters,  S_IWUSR | S_IRUGO,		  bonding_show_bonds, bonding_store_bonds);int bond_create_slave_symlinks(struct net_device *master, struct net_device *slave){	char linkname[IFNAMSIZ+7];	int ret = 0;	/* first, create a link from the slave back to the master */	ret = sysfs_create_link(&(slave->dev.kobj), &(master->dev.kobj),				"master");	if (ret)		return ret;	/* next, create a link from the master to the slave */	sprintf(linkname,"slave_%s",slave->name);	ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),				linkname);	return ret;}void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *slave){	char linkname[IFNAMSIZ+7];	sysfs_remove_link(&(slave->dev.kobj), "master");	sprintf(linkname,"slave_%s",slave->name);	sysfs_remove_link(&(master->dev.kobj), linkname);}/* * Show the slaves in the current bond. */static ssize_t bonding_show_slaves(struct device *d,				   struct device_attribute *attr, char *buf){	struct slave *slave;	int i, res = 0;	struct bonding *bond = to_bond(d);	read_lock(&bond->lock);	bond_for_each_slave(bond, slave, i) {		if (res > (PAGE_SIZE - IFNAMSIZ)) {			/* not enough space for another interface name */			if ((PAGE_SIZE - res) > 10)				res = PAGE_SIZE - 10;			res += sprintf(buf + res, "++more++ ");			break;		}		res += sprintf(buf + res, "%s ", slave->dev->name);	}	read_unlock(&bond->lock);	if (res)		buf[res-1] = '\n'; /* eat the leftover space */	return res;}/* * Set the slaves in the current bond.  The bond interface must be * up for this to succeed. * This function is largely the same flow as bonding_update_bonds(). */static ssize_t bonding_store_slaves(struct device *d,				    struct device_attribute *attr,				    const char *buffer, size_t count){	char command[IFNAMSIZ + 1] = { 0, };	char *ifname;	int i, res, found, ret = count;	u32 original_mtu;	struct slave *slave;	struct net_device *dev = NULL;	struct bonding *bond = to_bond(d);	/* Quick sanity check -- is the bond interface up? */	if (!(bond->dev->flags & IFF_UP)) {		printk(KERN_WARNING DRV_NAME		       ": %s: doing slave updates when interface is down.\n",		       bond->dev->name);	}	/* Note:  We can't hold bond->lock here, as bond_create grabs it. */	rtnl_lock();	down_write(&(bonding_rwsem));	sscanf(buffer, "%16s", command); /* IFNAMSIZ*/	ifname = command + 1;	if ((strlen(command) <= 1) ||	    !dev_valid_name(ifname))		goto err_no_cmd;	if (command[0] == '+') {		/* Got a slave name in ifname.  Is it already in the list? */		found = 0;		read_lock(&bond->lock);		bond_for_each_slave(bond, slave, i)			if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {				printk(KERN_ERR DRV_NAME				       ": %s: Interface %s is already enslaved!\n",				       bond->dev->name, ifname);				ret = -EPERM;				read_unlock(&bond->lock);				goto out;			}		read_unlock(&bond->lock);		printk(KERN_INFO DRV_NAME ": %s: Adding slave %s.\n",		       bond->dev->name, ifname);		dev = dev_get_by_name(&init_net, ifname);		if (!dev) {			printk(KERN_INFO DRV_NAME			       ": %s: Interface %s does not exist!\n",			       bond->dev->name, ifname);			ret = -EPERM;			goto out;		}		else			dev_put(dev);		if (dev->flags & IFF_UP) {			printk(KERN_ERR DRV_NAME			       ": %s: Error: Unable to enslave %s "			       "because it is already up.\n",			       bond->dev->name, dev->name);			ret = -EPERM;			goto out;		}		/* If this is the first slave, then we need to set		   the master's hardware address to be the same as the		   slave's. */		if (!(*((u32 *) & (bond->dev->dev_addr[0])))) {			memcpy(bond->dev->dev_addr, dev->dev_addr,			       dev->addr_len);		}		/* Set the slave's MTU to match the bond */		original_mtu = dev->mtu;		if (dev->mtu != bond->dev->mtu) {			if (dev->change_mtu) {				res = dev->change_mtu(dev,						      bond->dev->mtu);				if (res) {					ret = res;					goto out;				}			} else {				dev->mtu = bond->dev->mtu;			}		}		res = bond_enslave(bond->dev, dev);		bond_for_each_slave(bond, slave, i)			if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0)				slave->original_mtu = original_mtu;		if (res) {			ret = res;		}		goto out;	}	if (command[0] == '-') {		dev = NULL;		bond_for_each_slave(bond, slave, i)			if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {				dev = slave->dev;				original_mtu = slave->original_mtu;				break;			}		if (dev) {			printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n",				bond->dev->name, dev->name);			if (bond->setup_by_slave)				res = bond_release_and_destroy(bond->dev, dev);			else				res = bond_release(bond->dev, dev);			if (res) {				ret = res;				goto out;			}			/* set the slave MTU to the default */			if (dev->change_mtu) {				dev->change_mtu(dev, original_mtu);			} else {				dev->mtu = original_mtu;			}		}		else {			printk(KERN_ERR DRV_NAME ": unable to remove non-existent slave %s for bond %s.\n",				ifname, bond->dev->name);			ret = -ENODEV;		}		goto out;	}err_no_cmd:	printk(KERN_ERR DRV_NAME ": no command found in slaves file for bond %s. Use +ifname or -ifname.\n", bond->dev->name);	ret = -EPERM;out:	up_write(&(bonding_rwsem));	rtnl_unlock();	return ret;}static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves);/* * Show and set the bonding mode.  The bond interface must be down to * change the mode. */static ssize_t bonding_show_mode(struct device *d,				 struct device_attribute *attr, char *buf){	struct bonding *bond = to_bond(d);	return sprintf(buf, "%s %d\n",			bond_mode_tbl[bond->params.mode].modename,			bond->params.mode);}static ssize_t bonding_store_mode(struct device *d,				  struct device_attribute *attr,				  const char *buf, size_t count){	int new_value, ret = count;	struct bonding *bond = to_bond(d);	if (bond->dev->flags & IFF_UP) {		printk(KERN_ERR DRV_NAME		       ": unable to update mode of %s because interface is up.\n",		       bond->dev->name);		ret = -EPERM;		goto out;	}	new_value = bond_parse_parm(buf, bond_mode_tbl);	if (new_value < 0)  {		printk(KERN_ERR DRV_NAME		       ": %s: Ignoring invalid mode value %.*s.\n",		       bond->dev->name,		       (int)strlen(buf) - 1, buf);		ret = -EINVAL;		goto out;	} else {		if (bond->params.mode == BOND_MODE_8023AD)			bond_unset_master_3ad_flags(bond);		if (bond->params.mode == BOND_MODE_ALB)			bond_unset_master_alb_flags(bond);		bond->params.mode = new_value;		bond_set_mode_ops(bond, bond->params.mode);		printk(KERN_INFO DRV_NAME ": %s: setting mode to %s (%d).\n",			bond->dev->name, bond_mode_tbl[new_value].modename, new_value);	}out:	return ret;}static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode);/* * Show and set the bonding transmit hash method.  The bond interface must be down to * change the xmit hash policy. */static ssize_t bonding_show_xmit_hash(struct device *d,				      struct device_attribute *attr,				      char *buf){	struct bonding *bond = to_bond(d);	return sprintf(buf, "%s %d\n",		       xmit_hashtype_tbl[bond->params.xmit_policy].modename,		       bond->params.xmit_policy);}static ssize_t bonding_store_xmit_hash(struct device *d,				       struct device_attribute *attr,				       const char *buf, size_t count){	int new_value, ret = count;	struct bonding *bond = to_bond(d);	if (bond->dev->flags & IFF_UP) {		printk(KERN_ERR DRV_NAME		       "%s: Interface is up. Unable to update xmit policy.\n",		       bond->dev->name);		ret = -EPERM;		goto out;	}	new_value = bond_parse_parm(buf, xmit_hashtype_tbl);	if (new_value < 0)  {		printk(KERN_ERR DRV_NAME		       ": %s: Ignoring invalid xmit hash policy value %.*s.\n",		       bond->dev->name,		       (int)strlen(buf) - 1, buf);		ret = -EINVAL;		goto out;	} else {		bond->params.xmit_policy = new_value;		bond_set_mode_ops(bond, bond->params.mode);		printk(KERN_INFO DRV_NAME ": %s: setting xmit hash policy to %s (%d).\n",			bond->dev->name, xmit_hashtype_tbl[new_value].modename, new_value);	}out:	return ret;}static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash);/* * Show and set arp_validate. */static ssize_t bonding_show_arp_validate(struct device *d,					 struct device_attribute *attr,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?