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

📄 bond_alb.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
				break;			}		}		if (!found) {			/* no slave has tmp_slave1's perm addr			 * as its curr addr			 */			free_mac_slave = tmp_slave1;			break;		}		if (!has_bond_addr) {			if (!memcmp(tmp_slave1->dev->dev_addr,				    bond->dev->dev_addr,				    ETH_ALEN)) {				has_bond_addr = tmp_slave1;			}		}	}	if (free_mac_slave) {		alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr,				       bond->alb_info.rlb_enabled);		printk(KERN_WARNING DRV_NAME		       ": Warning: the hw address of slave %s is in use by "		       "the bond; giving it the hw address of %s\n",		       slave->dev->name, free_mac_slave->dev->name);	} else if (has_bond_addr) {		printk(KERN_ERR DRV_NAME		       ": Error: the hw address of slave %s is in use by the "		       "bond; couldn't find a slave with a free hw address to "		       "give it (this should not have happened)\n",		       slave->dev->name);		return -EFAULT;	}	return 0;}/** * alb_set_mac_address * @bond: * @addr: * * In TLB mode all slaves are configured to the bond's hw address, but set * their dev_addr field to different addresses (based on their permanent hw * addresses). * * For each slave, this function sets the interface to the new address and then * changes its dev_addr field to its previous value. * * Unwinding assumes bond's mac address has not yet changed. */static int alb_set_mac_address(struct bonding *bond, void *addr){	struct sockaddr sa;	struct slave *slave, *stop_at;	char tmp_addr[ETH_ALEN];	int res;	int i;	if (bond->alb_info.rlb_enabled) {		return 0;	}	bond_for_each_slave(bond, slave, i) {		if (slave->dev->set_mac_address == NULL) {			res = -EOPNOTSUPP;			goto unwind;		}		/* save net_device's current hw address */		memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);		res = dev_set_mac_address(slave->dev, addr);		/* restore net_device's hw address */		memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);		if (res) {			goto unwind;		}	}	return 0;unwind:	memcpy(sa.sa_data, bond->dev->dev_addr, bond->dev->addr_len);	sa.sa_family = bond->dev->type;	/* unwind from head to the slave that failed */	stop_at = slave;	bond_for_each_slave_from_to(bond, slave, i, bond->first_slave, stop_at) {		memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN);		dev_set_mac_address(slave->dev, &sa);		memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN);	}	return res;}/************************ exported alb funcions ************************/int bond_alb_initialize(struct bonding *bond, int rlb_enabled){	int res;	res = tlb_initialize(bond);	if (res) {		return res;	}	if (rlb_enabled) {		bond->alb_info.rlb_enabled = 1;		/* initialize rlb */		res = rlb_initialize(bond);		if (res) {			tlb_deinitialize(bond);			return res;		}	}	return 0;}void bond_alb_deinitialize(struct bonding *bond){	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));	tlb_deinitialize(bond);	if (bond_info->rlb_enabled) {		rlb_deinitialize(bond);	}}int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev){	struct bonding *bond = bond_dev->priv;	struct ethhdr *eth_data;	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));	struct slave *tx_slave = NULL;	static u32 ip_bcast = 0xffffffff;	int hash_size = 0;	int do_tx_balance = 1;	u32 hash_index = 0;	u8 *hash_start = NULL;	int res = 1;	skb->mac.raw = (unsigned char *)skb->data;	eth_data = eth_hdr(skb);	/* make sure that the curr_active_slave and the slaves list do	 * not change during tx	 */	read_lock(&bond->lock);	read_lock(&bond->curr_slave_lock);	if (!BOND_IS_OK(bond)) {		goto out;	}	switch (ntohs(skb->protocol)) {	case ETH_P_IP:		if ((memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) ||		    (skb->nh.iph->daddr == ip_bcast) ||		    (skb->nh.iph->protocol == IPPROTO_IGMP)) {			do_tx_balance = 0;			break;		}		hash_start = (char*)&(skb->nh.iph->daddr);		hash_size = sizeof(skb->nh.iph->daddr);		break;	case ETH_P_IPV6:		if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) {			do_tx_balance = 0;			break;		}		hash_start = (char*)&(skb->nh.ipv6h->daddr);		hash_size = sizeof(skb->nh.ipv6h->daddr);		break;	case ETH_P_IPX:		if (ipx_hdr(skb)->ipx_checksum !=		    __constant_htons(IPX_NO_CHECKSUM)) {			/* something is wrong with this packet */			do_tx_balance = 0;			break;		}		if (ipx_hdr(skb)->ipx_type != IPX_TYPE_NCP) {			/* The only protocol worth balancing in			 * this family since it has an "ARP" like			 * mechanism			 */			do_tx_balance = 0;			break;		}		hash_start = (char*)eth_data->h_dest;		hash_size = ETH_ALEN;		break;	case ETH_P_ARP:		do_tx_balance = 0;		if (bond_info->rlb_enabled) {			tx_slave = rlb_arp_xmit(skb, bond);		}		break;	default:		do_tx_balance = 0;		break;	}	if (do_tx_balance) {		hash_index = _simple_hash(hash_start, hash_size);		tx_slave = tlb_choose_channel(bond, hash_index, skb->len);	}	if (!tx_slave) {		/* unbalanced or unassigned, send through primary */		tx_slave = bond->curr_active_slave;		bond_info->unbalanced_load += skb->len;	}	if (tx_slave && SLAVE_IS_OK(tx_slave)) {		if (tx_slave != bond->curr_active_slave) {			memcpy(eth_data->h_source,			       tx_slave->dev->dev_addr,			       ETH_ALEN);		}		res = bond_dev_queue_xmit(bond, skb, tx_slave->dev);	} else {		if (tx_slave) {			tlb_clear_slave(bond, tx_slave, 0);		}	}out:	if (res) {		/* no suitable interface, frame not sent */		dev_kfree_skb(skb);	}	read_unlock(&bond->curr_slave_lock);	read_unlock(&bond->lock);	return 0;}void bond_alb_monitor(struct bonding *bond){	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));	struct slave *slave;	int i;	read_lock(&bond->lock);	if (bond->kill_timers) {		goto out;	}	if (bond->slave_cnt == 0) {		bond_info->tx_rebalance_counter = 0;		bond_info->lp_counter = 0;		goto re_arm;	}	bond_info->tx_rebalance_counter++;	bond_info->lp_counter++;	/* send learning packets */	if (bond_info->lp_counter >= BOND_ALB_LP_TICKS) {		/* change of curr_active_slave involves swapping of mac addresses.		 * in order to avoid this swapping from happening while		 * sending the learning packets, the curr_slave_lock must be held for		 * read.		 */		read_lock(&bond->curr_slave_lock);		bond_for_each_slave(bond, slave, i) {			alb_send_learning_packets(slave,slave->dev->dev_addr);		}		read_unlock(&bond->curr_slave_lock);		bond_info->lp_counter = 0;	}	/* rebalance tx traffic */	if (bond_info->tx_rebalance_counter >= BOND_TLB_REBALANCE_TICKS) {		read_lock(&bond->curr_slave_lock);		bond_for_each_slave(bond, slave, i) {			tlb_clear_slave(bond, slave, 1);			if (slave == bond->curr_active_slave) {				SLAVE_TLB_INFO(slave).load =					bond_info->unbalanced_load /						BOND_TLB_REBALANCE_INTERVAL;				bond_info->unbalanced_load = 0;			}		}		read_unlock(&bond->curr_slave_lock);		bond_info->tx_rebalance_counter = 0;	}	/* handle rlb stuff */	if (bond_info->rlb_enabled) {		/* the following code changes the promiscuity of the		 * the curr_active_slave. It needs to be locked with a		 * write lock to protect from other code that also		 * sets the promiscuity.		 */		write_lock(&bond->curr_slave_lock);		if (bond_info->primary_is_promisc &&		    (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) {			bond_info->rlb_promisc_timeout_counter = 0;			/* If the primary was set to promiscuous mode			 * because a slave was disabled then			 * it can now leave promiscuous mode.			 */			dev_set_promiscuity(bond->curr_active_slave->dev, -1);			bond_info->primary_is_promisc = 0;		}		write_unlock(&bond->curr_slave_lock);		if (bond_info->rlb_rebalance) {			bond_info->rlb_rebalance = 0;			rlb_rebalance(bond);		}		/* check if clients need updating */		if (bond_info->rx_ntt) {			if (bond_info->rlb_update_delay_counter) {				--bond_info->rlb_update_delay_counter;			} else {				rlb_update_rx_clients(bond);				if (bond_info->rlb_update_retry_counter) {					--bond_info->rlb_update_retry_counter;				} else {					bond_info->rx_ntt = 0;				}			}		}	}re_arm:	mod_timer(&(bond_info->alb_timer), jiffies + alb_delta_in_ticks);out:	read_unlock(&bond->lock);}/* assumption: called before the slave is attached to the bond * and not locked by the bond lock */int bond_alb_init_slave(struct bonding *bond, struct slave *slave){	int res;	res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr,				     bond->alb_info.rlb_enabled);	if (res) {		return res;	}	/* caller must hold the bond lock for write since the mac addresses	 * are compared and may be swapped.	 */	write_lock_bh(&bond->lock);	res = alb_handle_addr_collision_on_attach(bond, slave);	write_unlock_bh(&bond->lock);	if (res) {		return res;	}	tlb_init_slave(slave);	/* order a rebalance ASAP */	bond->alb_info.tx_rebalance_counter = BOND_TLB_REBALANCE_TICKS;	if (bond->alb_info.rlb_enabled) {		bond->alb_info.rlb_rebalance = 1;	}	return 0;}/* Caller must hold bond lock for write */void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave){	if (bond->slave_cnt > 1) {		alb_change_hw_addr_on_detach(bond, slave);	}	tlb_clear_slave(bond, slave, 0);	if (bond->alb_info.rlb_enabled) {		bond->alb_info.next_rx_slave = NULL;		rlb_clear_slave(bond, slave);	}}/* Caller must hold bond lock for read */void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link){	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));	if (link == BOND_LINK_DOWN) {		tlb_clear_slave(bond, slave, 0);		if (bond->alb_info.rlb_enabled) {			rlb_clear_slave(bond, slave);		}	} else if (link == BOND_LINK_UP) {		/* order a rebalance ASAP */		bond_info->tx_rebalance_counter = BOND_TLB_REBALANCE_TICKS;		if (bond->alb_info.rlb_enabled) {			bond->alb_info.rlb_rebalance = 1;			/* If the updelay module parameter is smaller than the			 * forwarding delay of the switch the rebalance will			 * not work because the rebalance arp replies will			 * not be forwarded to the clients..			 */		}	}}/** * bond_alb_handle_active_change - assign new curr_active_slave * @bond: our bonding struct * @new_slave: new slave to assign * * Set the bond->curr_active_slave to @new_slave and handle * mac address swapping and promiscuity changes as needed. * * Caller must hold bond curr_slave_lock for write (or bond lock for write) */void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave){	struct slave *swap_slave;	int i;	if (bond->curr_active_slave == new_slave) {		return;	}	if (bond->curr_active_slave && bond->alb_info.primary_is_promisc) {		dev_set_promiscuity(bond->curr_active_slave->dev, -1);		bond->alb_info.primary_is_promisc = 0;		bond->alb_info.rlb_promisc_timeout_counter = 0;	}	swap_slave = bond->curr_active_slave;	bond->curr_active_slave = new_slave;	if (!new_slave || (bond->slave_cnt == 0)) {		return;	}	/* set the new curr_active_slave to the bonds mac address	 * i.e. swap mac addresses of old curr_active_slave and new curr_active_slave	 */	if (!swap_slave) {		struct slave *tmp_slave;		/* find slave that is holding the bond's mac address */		bond_for_each_slave(bond, tmp_slave, i) {			if (!memcmp(tmp_slave->dev->dev_addr,				    bond->dev->dev_addr, ETH_ALEN)) {				swap_slave = tmp_slave;				break;			}		}	}	/* curr_active_slave must be set before calling alb_swap_mac_addr */	if (swap_slave) {		/* swap mac address */		alb_swap_mac_addr(bond, swap_slave, new_slave);	} else {		/* set the new_slave to the bond mac address */		alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr,				       bond->alb_info.rlb_enabled);		/* fasten bond mac on new current slave */		alb_send_learning_packets(new_slave, bond->dev->dev_addr);	}}int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr){	struct bonding *bond = bond_dev->priv;	struct sockaddr *sa = addr;	struct slave *slave, *swap_slave;	int res;	int i;	if (!is_valid_ether_addr(sa->sa_data)) {		return -EADDRNOTAVAIL;	}	res = alb_set_mac_address(bond, addr);	if (res) {		return res;	}	memcpy(bond_dev->dev_addr, sa->sa_data, bond_dev->addr_len);	/* If there is no curr_active_slave there is nothing else to do.	 * Otherwise we'll need to pass the new address to it and handle	 * duplications.	 */	if (!bond->curr_active_slave) {		return 0;	}	swap_slave = NULL;	bond_for_each_slave(bond, slave, i) {		if (!memcmp(slave->dev->dev_addr, bond_dev->dev_addr, ETH_ALEN)) {			swap_slave = slave;			break;		}	}	if (swap_slave) {		alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave);	} else {		alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr,				       bond->alb_info.rlb_enabled);		alb_send_learning_packets(bond->curr_active_slave, bond_dev->dev_addr);		if (bond->alb_info.rlb_enabled) {			/* inform clients mac address has changed */			rlb_req_update_slave_clients(bond, bond->curr_active_slave);		}	}	return 0;}void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id){	if (bond->alb_info.current_alb_vlan &&	    (bond->alb_info.current_alb_vlan->vlan_id == vlan_id)) {		bond->alb_info.current_alb_vlan = NULL;	}	if (bond->alb_info.rlb_enabled) {		rlb_clear_vlan(bond, vlan_id);	}}

⌨️ 快捷键说明

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