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 + -
显示快捷键?