bond_main.c

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

C
2,361
字号
		       ": %s: Error: 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 = vlan_group_get_device(bond->vlgrp, vid);			slave_dev->vlan_rx_kill_vid(slave_dev, vid);			vlan_group_set_device(bond->vlgrp, 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 = vlan_group_get_device(bond->vlgrp, vlan->vlan_id);		slave_dev->vlan_rx_kill_vid(slave_dev, vlan->vlan_id);		vlan_group_set_device(bond->vlgrp, 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;	struct ethtool_cmd etool;	int res;	/* Fake speed and duplex */	slave->speed = SPEED_100;	slave->duplex = DUPLEX_FULL;	if (!slave_dev->ethtool_ops || !slave_dev->ethtool_ops->get_settings)		return -1;	res = slave_dev->ethtool_ops->get_settings(slave_dev, &etool);	if (res < 0)		return -1;	switch (etool.speed) {	case SPEED_10:	case SPEED_100:	case SPEED_1000:	case SPEED_10000:		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;	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);			}		}	}	/*	 * Some drivers cache ETHTOOL_GLINK for a period of time so we only	 * attempt to get link status from it 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 reporting, report that either there's no dev->do_ioctl,	 * or both SIOCGMIIREG and get_link 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);		}	}}/* * Retrieve the list of registered multicast addresses for the bonding * device and retransmit an IGMP JOIN request to the current active * slave. */static void bond_resend_igmp_join_requests(struct bonding *bond){	struct in_device *in_dev;	struct ip_mc_list *im;	rcu_read_lock();	in_dev = __in_dev_get_rcu(bond->dev);	if (in_dev) {		for (im = in_dev->mc_list; im; im = im->next) {			ip_mc_rejoin_group(im);		}	}	rcu_read_unlock();}/* * 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;	}        bond->mc_list = NULL;}/* * 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);		}

⌨️ 快捷键说明

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