⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bond_main.c

📁 h内核
💻 C
📖 第 1 页 / 共 5 页
字号:
	    !(slave_dev->features & NETIF_F_HW_VLAN_TX)) {		res = vlan_get_tag(skb, &vlan_id);		if (res) {			return -EINVAL;		}		skb->dev = slave_dev;		skb = vlan_put_tag(skb, vlan_id);		if (!skb) {			/* vlan_put_tag() frees the skb in case of error,			 * so return success here so the calling functions			 * won't attempt to free is again.			 */			return 0;		}	} else {		skb->dev = slave_dev;	}	skb->priority = 1;	dev_queue_xmit(skb);	return 0;}/* * In the following 3 functions, bond_vlan_rx_register(), bond_vlan_rx_add_vid * and bond_vlan_rx_kill_vid, We don't protect the slave list iteration with a * lock because: * a. This operation is performed in IOCTL context, * b. The operation is protected by the RTNL semaphore in the 8021q code, * c. Holding a lock with BH disabled while directly calling a base driver *    entry point is generally a BAD idea. *  * The design of synchronization/protection for this operation in the 8021q * module is good for one or more VLAN devices over a single physical device * and cannot be extended for a teaming solution like bonding, so there is a * potential race condition here where a net device from the vlan group might * be referenced (either by a base driver or the 8021q code) while it is being * removed from the system. However, it turns out we're not making matters * worse, and if it works for regular VLAN usage it will work here too.*//** * bond_vlan_rx_register - Propagates registration to slaves * @bond_dev: bonding net device that got called * @grp: vlan group being registered */static void bond_vlan_rx_register(struct net_device *bond_dev, struct vlan_group *grp){	struct bonding *bond = bond_dev->priv;	struct slave *slave;	int i;	bond->vlgrp = grp;	bond_for_each_slave(bond, slave, i) {		struct net_device *slave_dev = slave->dev;		if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&		    slave_dev->vlan_rx_register) {			slave_dev->vlan_rx_register(slave_dev, grp);		}	}}/** * bond_vlan_rx_add_vid - Propagates adding an id to slaves * @bond_dev: bonding net device that got called * @vid: vlan id being added */static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid){	struct bonding *bond = bond_dev->priv;	struct slave *slave;	int i, res;	bond_for_each_slave(bond, slave, i) {		struct net_device *slave_dev = slave->dev;		if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) &&		    slave_dev->vlan_rx_add_vid) {			slave_dev->vlan_rx_add_vid(slave_dev, vid);		}	}	res = bond_add_vlan(bond, vid);	if (res) {		printk(KERN_ERR DRV_NAME		       ": %s: Failed to add vlan id %d\n",		       bond_dev->name, vid);	}}/** * bond_vlan_rx_kill_vid - Propagates deleting an id to slaves * @bond_dev: bonding net device that got called * @vid: vlan id being removed */static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid){	struct bonding *bond = bond_dev->priv;	struct slave *slave;	struct net_device *vlan_dev;	int i, res;	bond_for_each_slave(bond, slave, i) {		struct net_device *slave_dev = slave->dev;		if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) &&		    slave_dev->vlan_rx_kill_vid) {			/* Save and then restore vlan_dev in the grp array,			 * since the slave's driver might clear it.			 */			vlan_dev = bond->vlgrp->vlan_devices[vid];			slave_dev->vlan_rx_kill_vid(slave_dev, vid);			bond->vlgrp->vlan_devices[vid] = vlan_dev;		}	}	res = bond_del_vlan(bond, vid);	if (res) {		printk(KERN_ERR DRV_NAME		       ": %s: Failed to remove vlan id %d\n",		       bond_dev->name, vid);	}}static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev){	struct vlan_entry *vlan;	write_lock_bh(&bond->lock);	if (list_empty(&bond->vlan_list)) {		goto out;	}	if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&	    slave_dev->vlan_rx_register) {		slave_dev->vlan_rx_register(slave_dev, bond->vlgrp);	}	if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) ||	    !(slave_dev->vlan_rx_add_vid)) {		goto out;	}	list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {		slave_dev->vlan_rx_add_vid(slave_dev, vlan->vlan_id);	}out:	write_unlock_bh(&bond->lock);}static void bond_del_vlans_from_slave(struct bonding *bond, struct net_device *slave_dev){	struct vlan_entry *vlan;	struct net_device *vlan_dev;	write_lock_bh(&bond->lock);	if (list_empty(&bond->vlan_list)) {		goto out;	}	if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) ||	    !(slave_dev->vlan_rx_kill_vid)) {		goto unreg;	}	list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {		/* Save and then restore vlan_dev in the grp array,		 * since the slave's driver might clear it.		 */		vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id];		slave_dev->vlan_rx_kill_vid(slave_dev, vlan->vlan_id);		bond->vlgrp->vlan_devices[vlan->vlan_id] = vlan_dev;	}unreg:	if ((slave_dev->features & NETIF_F_HW_VLAN_RX) &&	    slave_dev->vlan_rx_register) {		slave_dev->vlan_rx_register(slave_dev, NULL);	}out:	write_unlock_bh(&bond->lock);}/*------------------------------- Link status -------------------------------*//* * Get link speed and duplex from the slave's base driver * using ethtool. If for some reason the call fails or the * values are invalid, fake speed and duplex to 100/Full * and return error. */static int bond_update_speed_duplex(struct slave *slave){	struct net_device *slave_dev = slave->dev;	static int (* ioctl)(struct net_device *, struct ifreq *, int);	struct ifreq ifr;	struct ethtool_cmd etool;	/* Fake speed and duplex */	slave->speed = SPEED_100;	slave->duplex = DUPLEX_FULL;	if (slave_dev->ethtool_ops) {		u32 res;		if (!slave_dev->ethtool_ops->get_settings) {			return -1;		}		res = slave_dev->ethtool_ops->get_settings(slave_dev, &etool);		if (res < 0) {			return -1;		}		goto verify;	}	ioctl = slave_dev->do_ioctl;	strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ);	etool.cmd = ETHTOOL_GSET;	ifr.ifr_data = (char*)&etool;	if (!ioctl || (IOCTL(slave_dev, &ifr, SIOCETHTOOL) < 0)) {		return -1;	}verify:	switch (etool.speed) {	case SPEED_10:	case SPEED_100:	case SPEED_1000:		break;	default:		return -1;	}	switch (etool.duplex) {	case DUPLEX_FULL:	case DUPLEX_HALF:		break;	default:		return -1;	}	slave->speed = etool.speed;	slave->duplex = etool.duplex;	return 0;}/* * if <dev> supports MII link status reporting, check its link status. * * We either do MII/ETHTOOL ioctls, or check netif_carrier_ok(), * depening upon the setting of the use_carrier parameter. * * Return either BMSR_LSTATUS, meaning that the link is up (or we * can't tell and just pretend it is), or 0, meaning that the link is * down. * * If reporting is non-zero, instead of faking link up, return -1 if * both ETHTOOL and MII ioctls fail (meaning the device does not * support them).  If use_carrier is set, return whatever it says. * It'd be nice if there was a good way to tell if a driver supports * netif_carrier, but there really isn't. */static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_dev, int reporting){	static int (* ioctl)(struct net_device *, struct ifreq *, int);	struct ifreq ifr;	struct mii_ioctl_data *mii;	struct ethtool_value etool;	if (bond->params.use_carrier) {		return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0;	}	ioctl = slave_dev->do_ioctl;	if (ioctl) {		/* TODO: set pointer to correct ioctl on a per team member */		/*       bases to make this more efficient. that is, once  */		/*       we determine the correct ioctl, we will always    */		/*       call it and not the others for that team          */		/*       member.                                           */		/*		 * We cannot assume that SIOCGMIIPHY will also read a		 * register; not all network drivers (e.g., e100)		 * support that.		 */		/* Yes, the mii is overlaid on the ifreq.ifr_ifru */		strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ);		mii = if_mii(&ifr);		if (IOCTL(slave_dev, &ifr, SIOCGMIIPHY) == 0) {			mii->reg_num = MII_BMSR;			if (IOCTL(slave_dev, &ifr, SIOCGMIIREG) == 0) {				return (mii->val_out & BMSR_LSTATUS);			}		}	}	/* try SIOCETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */	/* for a period of time so we attempt to get link status   */	/* from it last if the above MII ioctls fail...            */	if (slave_dev->ethtool_ops) {		if (slave_dev->ethtool_ops->get_link) {			u32 link;			link = slave_dev->ethtool_ops->get_link(slave_dev);			return link ? BMSR_LSTATUS : 0;		}	}	if (ioctl) {		strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ);		etool.cmd = ETHTOOL_GLINK;		ifr.ifr_data = (char*)&etool;		if (IOCTL(slave_dev, &ifr, SIOCETHTOOL) == 0) {			if (etool.data == 1) {				return BMSR_LSTATUS;			} else {				dprintk("SIOCETHTOOL shows link down\n");				return 0;			}		}	}	/*	 * If reporting, report that either there's no dev->do_ioctl,	 * or both SIOCGMIIREG and SIOCETHTOOL failed (meaning that we	 * cannot report link status).  If not reporting, pretend	 * we're ok.	 */	return (reporting ? -1 : BMSR_LSTATUS);}/*----------------------------- Multicast list ------------------------------*//* * Returns 0 if dmi1 and dmi2 are the same, non-0 otherwise */static inline int bond_is_dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2){	return memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0 &&			dmi1->dmi_addrlen == dmi2->dmi_addrlen;}/* * returns dmi entry if found, NULL otherwise */static struct dev_mc_list *bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct dev_mc_list *mc_list){	struct dev_mc_list *idmi;	for (idmi = mc_list; idmi; idmi = idmi->next) {		if (bond_is_dmi_same(dmi, idmi)) {			return idmi;		}	}	return NULL;}/* * Push the promiscuity flag down to appropriate slaves */static void bond_set_promiscuity(struct bonding *bond, int inc){	if (USES_PRIMARY(bond->params.mode)) {		/* write lock already acquired */		if (bond->curr_active_slave) {			dev_set_promiscuity(bond->curr_active_slave->dev, inc);		}	} else {		struct slave *slave;		int i;		bond_for_each_slave(bond, slave, i) {			dev_set_promiscuity(slave->dev, inc);		}	}}/* * Push the allmulti flag down to all slaves */static void bond_set_allmulti(struct bonding *bond, int inc){	if (USES_PRIMARY(bond->params.mode)) {		/* write lock already acquired */		if (bond->curr_active_slave) {			dev_set_allmulti(bond->curr_active_slave->dev, inc);		}	} else {		struct slave *slave;		int i;		bond_for_each_slave(bond, slave, i) {			dev_set_allmulti(slave->dev, inc);

⌨️ 快捷键说明

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