bond_sysfs.c

来自「linux2.6.16版本」· C语言 代码 · 共 1,359 行 · 第 1/3 页

C
1,359
字号
/* * 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/config.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/sched.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/string.h>#include <linux/ctype.h>#include <linux/inet.h>#include <linux/rtnetlink.h>/* #define BONDING_DEBUG 1 */#include "bonding.h"#define to_class_dev(obj) container_of(obj,struct class_device,kobj)#define to_net_dev(class) container_of(class, struct net_device, class_dev)#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[];static int expected_refcount = -1;static struct class *netdev_class;/*--------------------------- Data Structures -----------------------------*//* Bonding sysfs lock.  Why can't we just use the subsytem 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 *buffer){	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(buffer + res, "++more++");			break;		}		res += sprintf(buffer + res, "%s ",			       bond->dev->name);	}	res += sprintf(buffer + res, "\n");	res++;	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 res = count;	struct bonding *bond;	struct bonding *nxt;	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] == '+') {		/* Check to see if the bond already exists. */		list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)			if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) {				printk(KERN_ERR DRV_NAME					": cannot add bond %s; it already exists\n",					ifname);				res = -EPERM;				goto out;			}		printk(KERN_INFO DRV_NAME			": %s is being created...\n", ifname);		if (bond_create(ifname, &bonding_defaults, &bond)) {			printk(KERN_INFO DRV_NAME			": %s interface already exists. Bond creation failed.\n",			ifname);			res = -EPERM;		}		goto out;	}	if (command[0] == '-') {		list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list)			if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) {				rtnl_lock();				/* 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->class_dev.kobj.kref.refcount)							> expected_refcount){					rtnl_unlock();					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);				unregister_netdevice(bond->dev);				bond_deinit(bond->dev);		        	bond_destroy_sysfs_entry(bond);				rtnl_unlock();				goto out;			}		printk(KERN_ERR DRV_NAME			": unable to delete non-existent bond %s\n", ifname);		res = -ENODEV;		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:	up_write(&(bonding_rwsem));	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->class_dev.kobj), &(master->class_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->class_dev.kobj), &(slave->class_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->class_dev.kobj), "master");	sprintf(linkname,"slave_%s",slave->name);	sysfs_remove_link(&(master->class_dev.kobj), linkname);}/* * Show the slaves in the current bond. */static ssize_t bonding_show_slaves(struct class_device *cd, char *buf){	struct slave *slave;	int i, res = 0;	struct bonding *bond = to_bond(cd);	read_lock_bh(&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_bh(&bond->lock);	res += sprintf(buf + res, "\n");	res++;	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 class_device *cd, const char *buffer, size_t count){	char command[IFNAMSIZ + 1] = { 0, };	char *ifname;	int i, res, found, ret = count;	struct slave *slave;	struct net_device *dev = NULL;	struct bonding *bond = to_bond(cd);	/* Quick sanity check -- is the bond interface up? */	if (!(bond->dev->flags & IFF_UP)) {		printk(KERN_ERR DRV_NAME		       ": %s: Unable to update slaves because interface is down.\n",		       bond->dev->name);		ret = -EPERM;		goto out;	}	/* Note:  We can't hold bond->lock here, as bond_create grabs it. */	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_bh(&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_bh(&bond->lock);				goto out;			}		read_unlock_bh(&bond->lock);		printk(KERN_INFO DRV_NAME ": %s: Adding slave %s.\n",		       bond->dev->name, ifname);		dev = dev_get_by_name(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 */		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;			}		}		rtnl_lock();		res = bond_enslave(bond->dev, dev);		rtnl_unlock();		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;				break;			}		if (dev) {			printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n",				bond->dev->name, dev->name);			rtnl_lock();			res = bond_release(bond->dev, dev);			rtnl_unlock();			if (res) {				ret = res;				goto out;			}			/* set the slave MTU to the default */			if (dev->change_mtu) {				dev->change_mtu(dev, 1500);			} else {				dev->mtu = 1500;			}		}		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:	return ret;}static CLASS_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 class_device *cd, char *buf){	struct bonding *bond = to_bond(cd);	return sprintf(buf, "%s %d\n",			bond_mode_tbl[bond->params.mode].modename,			bond->params.mode) + 1;}static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size_t count){	int new_value, ret = count;	struct bonding *bond = to_bond(cd);	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((char *)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 {		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 CLASS_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 class_device *cd, char *buf){	int count;	struct bonding *bond = to_bond(cd);	if ((bond->params.mode != BOND_MODE_XOR) &&	    (bond->params.mode != BOND_MODE_8023AD)) {		// Not Applicable		count = sprintf(buf, "NA\n") + 1;	} else {		count = sprintf(buf, "%s %d\n",			xmit_hashtype_tbl[bond->params.xmit_policy].modename,			bond->params.xmit_policy) + 1;

⌨️ 快捷键说明

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