bond_main.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,408 行 · 第 1/5 页

C
2,408
字号
			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: Error: 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 -------------------------------*//* * Set the carrier state for the master according to the state of its * slaves.  If any slaves are up, the master is up.  In 802.3ad mode, * do special 802.3ad magic. * * Returns zero if carrier state does not change, nonzero if it does. */static int bond_set_carrier(struct bonding *bond){	struct slave *slave;	int i;	if (bond->slave_cnt == 0)		goto down;	if (bond->params.mode == BOND_MODE_8023AD)		return bond_3ad_set_carrier(bond);	bond_for_each_slave(bond, slave, i) {		if (slave->link == BOND_LINK_UP) {			if (!netif_carrier_ok(bond->dev)) {				netif_carrier_on(bond->dev);				return 1;			}			return 0;		}	}down:	if (netif_carrier_ok(bond->dev)) {		netif_carrier_off(bond->dev);		return 1;	}	return 0;}/* * 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) {		int 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);		}	}}/* * Add a Multicast address to slaves * according to mode */static void bond_mc_add(struct bonding *bond, void *addr, int alen){	if (USES_PRIMARY(bond->params.mode)) {		/* write lock already acquired */		if (bond->curr_active_slave) {			dev_mc_add(bond->curr_active_slave->dev, addr, alen, 0);		}	} else {		struct slave *slave;		int i;		bond_for_each_slave(bond, slave, i) {			dev_mc_add(slave->dev, addr, alen, 0);		}	}}/* * Remove a multicast address from slave * according to mode */static void bond_mc_delete(struct bonding *bond, void *addr, int alen){	if (USES_PRIMARY(bond->params.mode)) {		/* write lock already acquired */		if (bond->curr_active_slave) {			dev_mc_delete(bond->curr_active_slave->dev, addr, alen, 0);		}	} else {		struct slave *slave;		int i;		bond_for_each_slave(bond, slave, i) {			dev_mc_delete(slave->dev, addr, alen, 0);		}	}}/* * Totally destroys the mc_list in bond */static void bond_mc_list_destroy(struct bonding *bond){	struct dev_mc_list *dmi;	dmi = bond->mc_list;	while (dmi) {		bond->mc_list = dmi->next;		kfree(dmi);		dmi = bond->mc_list;	}}/* * Copy all the Multicast addresses from src to the bonding device dst */static int bond_mc_list_copy(struct dev_mc_list *mc_list, struct bonding *bond,			     gfp_t gfp_flag){	struct dev_mc_list *dmi, *new_dmi;	for (dmi = mc_list; dmi; dmi = dmi->next) {		new_dmi = kmalloc(sizeof(struct dev_mc_list), gfp_flag);		if (!new_dmi) {			/* FIXME: Potential memory leak !!! */			return -ENOMEM;		}		new_dmi->next = bond->mc_list;		bond->mc_list = new_dmi;		new_dmi->dmi_addrlen = dmi->dmi_addrlen;		memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen);		new_dmi->dmi_users = dmi->dmi_users;		new_dmi->dmi_gusers = dmi->dmi_gusers;	}	return 0;}/* * flush all members of flush->mc_list from device dev->mc_list */static void bond_mc_list_flush(struct net_device *bond_dev, struct net_device *slave_dev){	struct bonding *bond = bond_dev->priv;	struct dev_mc_list *dmi;	for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) {		dev_mc_delete(slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);	}	if (bond->params.mode == BOND_MODE_8023AD) {		/* del lacpdu mc addr from mc list */		u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;		dev_mc_delete(slave_dev, lacpdu_multicast, ETH_ALEN, 0);	}}/*--------------------------- Active slave change ---------------------------*//* * Update the mc list and multicast-related flags for the new and * old active slaves (if any) according to the multicast mode, and * promiscuous flags unconditionally. */static void bond_mc_swap(struct bonding *bond, struct slave *new_active, struct slave *old_active){	struct dev_mc_list *dmi;	if (!USES_PRIMARY(bond->params.mode)) {		/* nothing to do -  mc list is already up-to-date on		 * all slaves		 */		return;	}	if (old_active) {		if (bond->dev->flags & IFF_PROMISC) {			dev_set_promiscuity(old_active->dev, -1);		}		if (bond->dev->flags & IFF_ALLMULTI) {			dev_set_allmulti(old_active->dev, -1);		}		for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) {			dev_mc_delete(old_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);		}	}	if (new_active) {		if (bond->dev->flags & IFF_PROMISC) {			dev_set_promiscuity(new_active->dev, 1);		}		if (bond->dev->flags & IFF_ALLMULTI) {			dev_set_allmulti(new_active->dev, 1);		}		for (dmi = bond->dev->mc_list; dmi; dmi = dmi->next) {			dev_mc_add(new_active->dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);		}	}}/** * find_best_interface - select the best available slave to be the active one

⌨️ 快捷键说明

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