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

📄 bond_alb.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
{	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));	struct rlb_client_info *client_info;	int ntt = 0;	u32 hash_index;	_lock_rx_hashtbl(bond);	hash_index = bond_info->rx_hashtbl_head;	for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {		client_info = &(bond_info->rx_hashtbl[hash_index]);		if ((client_info->slave == slave) &&		    memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) {			client_info->ntt = 1;			ntt = 1;		}	}	// update the team's flag only after the whole iteration	if (ntt) {		bond_info->rx_ntt = 1;		//fasten the change		bond_info->rlb_update_retry_counter = RLB_UPDATE_RETRY;	}	_unlock_rx_hashtbl(bond);}/* mark all clients using src_ip to be updated */static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip){	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));	struct rlb_client_info *client_info;	u32 hash_index;	_lock_rx_hashtbl(bond);	hash_index = bond_info->rx_hashtbl_head;	for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {		client_info = &(bond_info->rx_hashtbl[hash_index]);		if (!client_info->slave) {			printk(KERN_ERR DRV_NAME			       ": Error: found a client with no channel in "			       "the client's hash table\n");			continue;		}		/*update all clients using this src_ip, that are not assigned		 * to the team's address (curr_active_slave) and have a known		 * unicast mac address.		 */		if ((client_info->ip_src == src_ip) &&		    memcmp(client_info->slave->dev->dev_addr,			   bond->dev->dev_addr, ETH_ALEN) &&		    memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) {			client_info->ntt = 1;			bond_info->rx_ntt = 1;		}	}	_unlock_rx_hashtbl(bond);}/* Caller must hold both bond and ptr locks for read */static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bond){	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));	struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw;	struct slave *assigned_slave;	struct rlb_client_info *client_info;	u32 hash_index = 0;	_lock_rx_hashtbl(bond);	hash_index = _simple_hash((u8 *)&arp->ip_dst, sizeof(arp->ip_src));	client_info = &(bond_info->rx_hashtbl[hash_index]);	if (client_info->assigned) {		if ((client_info->ip_src == arp->ip_src) &&		    (client_info->ip_dst == arp->ip_dst)) {			/* the entry is already assigned to this client */			if (memcmp(arp->mac_dst, mac_bcast, ETH_ALEN)) {				/* update mac address from arp */				memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN);			}			assigned_slave = client_info->slave;			if (assigned_slave) {				_unlock_rx_hashtbl(bond);				return assigned_slave;			}		} else {			/* the entry is already assigned to some other client,			 * move the old client to primary (curr_active_slave) so			 * that the new client can be assigned to this entry.			 */			if (bond->curr_active_slave &&			    client_info->slave != bond->curr_active_slave) {				client_info->slave = bond->curr_active_slave;				rlb_update_client(client_info);			}		}	}	/* assign a new slave */	assigned_slave = rlb_next_rx_slave(bond);	if (assigned_slave) {		client_info->ip_src = arp->ip_src;		client_info->ip_dst = arp->ip_dst;		/* arp->mac_dst is broadcast for arp reqeusts.		 * will be updated with clients actual unicast mac address		 * upon receiving an arp reply.		 */		memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN);		client_info->slave = assigned_slave;		if (memcmp(client_info->mac_dst, mac_bcast, ETH_ALEN)) {			client_info->ntt = 1;			bond->alb_info.rx_ntt = 1;		} else {			client_info->ntt = 0;		}		if (!list_empty(&bond->vlan_list)) {			unsigned short vlan_id;			int res = vlan_get_tag(skb, &vlan_id);			if (!res) {				client_info->tag = 1;				client_info->vlan_id = vlan_id;			}		}		if (!client_info->assigned) {			u32 prev_tbl_head = bond_info->rx_hashtbl_head;			bond_info->rx_hashtbl_head = hash_index;			client_info->next = prev_tbl_head;			if (prev_tbl_head != RLB_NULL_INDEX) {				bond_info->rx_hashtbl[prev_tbl_head].prev =					hash_index;			}			client_info->assigned = 1;		}	}	_unlock_rx_hashtbl(bond);	return assigned_slave;}/* chooses (and returns) transmit channel for arp reply * does not choose channel for other arp types since they are * sent on the curr_active_slave */static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond){	struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw;	struct slave *tx_slave = NULL;	if (arp->op_code == __constant_htons(ARPOP_REPLY)) {		/* the arp must be sent on the selected		* rx channel		*/		tx_slave = rlb_choose_channel(skb, bond);		if (tx_slave) {			memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN);		}		dprintk("Server sent ARP Reply packet\n");	} else if (arp->op_code == __constant_htons(ARPOP_REQUEST)) {		/* Create an entry in the rx_hashtbl for this client as a		 * place holder.		 * When the arp reply is received the entry will be updated		 * with the correct unicast address of the client.		 */		rlb_choose_channel(skb, bond);		/* The ARP relpy packets must be delayed so that		 * they can cancel out the influence of the ARP request.		 */		bond->alb_info.rlb_update_delay_counter = RLB_UPDATE_DELAY;		/* arp requests are broadcast and are sent on the primary		 * the arp request will collapse all clients on the subnet to		 * the primary slave. We must register these clients to be		 * updated with their assigned mac.		 */		rlb_req_update_subnet_clients(bond, arp->ip_src);		dprintk("Server sent ARP Request packet\n");	}	return tx_slave;}/* Caller must hold bond lock for read */static void rlb_rebalance(struct bonding *bond){	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));	struct slave *assigned_slave;	struct rlb_client_info *client_info;	int ntt;	u32 hash_index;	_lock_rx_hashtbl(bond);	ntt = 0;	hash_index = bond_info->rx_hashtbl_head;	for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {		client_info = &(bond_info->rx_hashtbl[hash_index]);		assigned_slave = rlb_next_rx_slave(bond);		if (assigned_slave && (client_info->slave != assigned_slave)) {			client_info->slave = assigned_slave;			client_info->ntt = 1;			ntt = 1;		}	}	/* update the team's flag only after the whole iteration */	if (ntt) {		bond_info->rx_ntt = 1;	}	_unlock_rx_hashtbl(bond);}/* Caller must hold rx_hashtbl lock */static void rlb_init_table_entry(struct rlb_client_info *entry){	memset(entry, 0, sizeof(struct rlb_client_info));	entry->next = RLB_NULL_INDEX;	entry->prev = RLB_NULL_INDEX;}static int rlb_initialize(struct bonding *bond){	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));	struct packet_type *pk_type = &(BOND_ALB_INFO(bond).rlb_pkt_type);	int size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info);	int i;	spin_lock_init(&(bond_info->rx_hashtbl_lock));	_lock_rx_hashtbl(bond);	bond_info->rx_hashtbl = kmalloc(size, GFP_KERNEL);	if (!bond_info->rx_hashtbl) {		printk(KERN_ERR DRV_NAME		       ": Error: %s: Failed to allocate RLB hash table\n",		       bond->dev->name);		_unlock_rx_hashtbl(bond);		return -1;	}	bond_info->rx_hashtbl_head = RLB_NULL_INDEX;	for (i = 0; i < RLB_HASH_TABLE_SIZE; i++) {		rlb_init_table_entry(bond_info->rx_hashtbl + i);	}	_unlock_rx_hashtbl(bond);	/*initialize packet type*/	pk_type->type = __constant_htons(ETH_P_ARP);	pk_type->dev = bond->dev;	pk_type->func = rlb_arp_recv;	/* register to receive ARPs */	dev_add_pack(pk_type);	return 0;}static void rlb_deinitialize(struct bonding *bond){	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));	dev_remove_pack(&(bond_info->rlb_pkt_type));	_lock_rx_hashtbl(bond);	kfree(bond_info->rx_hashtbl);	bond_info->rx_hashtbl = NULL;	bond_info->rx_hashtbl_head = RLB_NULL_INDEX;	_unlock_rx_hashtbl(bond);}static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id){	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));	u32 curr_index;	_lock_rx_hashtbl(bond);	curr_index = bond_info->rx_hashtbl_head;	while (curr_index != RLB_NULL_INDEX) {		struct rlb_client_info *curr = &(bond_info->rx_hashtbl[curr_index]);		u32 next_index = bond_info->rx_hashtbl[curr_index].next;		u32 prev_index = bond_info->rx_hashtbl[curr_index].prev;		if (curr->tag && (curr->vlan_id == vlan_id)) {			if (curr_index == bond_info->rx_hashtbl_head) {				bond_info->rx_hashtbl_head = next_index;			}			if (prev_index != RLB_NULL_INDEX) {				bond_info->rx_hashtbl[prev_index].next = next_index;			}			if (next_index != RLB_NULL_INDEX) {				bond_info->rx_hashtbl[next_index].prev = prev_index;			}			rlb_init_table_entry(curr);		}		curr_index = next_index;	}	_unlock_rx_hashtbl(bond);}/*********************** tlb/rlb shared functions *********************/static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]){	struct bonding *bond = bond_get_bond_by_slave(slave);	struct learning_pkt pkt;	int size = sizeof(struct learning_pkt);	int i;	memset(&pkt, 0, size);	memcpy(pkt.mac_dst, mac_addr, ETH_ALEN);	memcpy(pkt.mac_src, mac_addr, ETH_ALEN);	pkt.type = __constant_htons(ETH_P_LOOP);	for (i = 0; i < MAX_LP_BURST; i++) {		struct sk_buff *skb;		char *data;		skb = dev_alloc_skb(size);		if (!skb) {			return;		}		data = skb_put(skb, size);		memcpy(data, &pkt, size);		skb->mac.raw = data;		skb->nh.raw = data + ETH_HLEN;		skb->protocol = pkt.type;		skb->priority = TC_PRIO_CONTROL;		skb->dev = slave->dev;		if (!list_empty(&bond->vlan_list)) {			struct vlan_entry *vlan;			vlan = bond_next_vlan(bond,					      bond->alb_info.current_alb_vlan);			bond->alb_info.current_alb_vlan = vlan;			if (!vlan) {				kfree_skb(skb);				continue;			}			skb = vlan_put_tag(skb, vlan->vlan_id);			if (!skb) {				printk(KERN_ERR DRV_NAME				       ": Error: failed to insert VLAN tag\n");				continue;			}		}		dev_queue_xmit(skb);	}}/* hw is a boolean parameter that determines whether we should try and * set the hw address of the device as well as the hw address of the * net_device */static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw){	struct net_device *dev = slave->dev;	struct sockaddr s_addr;	if (!hw) {		memcpy(dev->dev_addr, addr, dev->addr_len);		return 0;	}	/* for rlb each slave must have a unique hw mac addresses so that */	/* each slave will receive packets destined to a different mac */	memcpy(s_addr.sa_data, addr, dev->addr_len);	s_addr.sa_family = dev->type;	if (dev_set_mac_address(dev, &s_addr)) {		printk(KERN_ERR DRV_NAME		       ": Error: dev_set_mac_address of dev %s failed! ALB "		       "mode requires that the base driver support setting "		       "the hw address also when the network device's "		       "interface is open\n",		       dev->name);		return -EOPNOTSUPP;	}	return 0;}/* Caller must hold bond lock for write or curr_slave_lock for write*/static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct slave *slave2){	struct slave *disabled_slave = NULL;	u8 tmp_mac_addr[ETH_ALEN];	int slaves_state_differ;	slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2));	memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN);	alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr, bond->alb_info.rlb_enabled);	alb_set_slave_mac_addr(slave2, tmp_mac_addr, bond->alb_info.rlb_enabled);	/* fasten the change in the switch */	if (SLAVE_IS_OK(slave1)) {		alb_send_learning_packets(slave1, slave1->dev->dev_addr);		if (bond->alb_info.rlb_enabled) {			/* inform the clients that the mac address			 * has changed			 */			rlb_req_update_slave_clients(bond, slave1);		}	} else {		disabled_slave = slave1;	}	if (SLAVE_IS_OK(slave2)) {		alb_send_learning_packets(slave2, slave2->dev->dev_addr);		if (bond->alb_info.rlb_enabled) {			/* inform the clients that the mac address			 * has changed			 */			rlb_req_update_slave_clients(bond, slave2);		}	} else {		disabled_slave = slave2;	}	if (bond->alb_info.rlb_enabled && slaves_state_differ) {		/* A disabled slave was assigned an active mac addr */		rlb_teach_disabled_mac_on_primary(bond,						  disabled_slave->dev->dev_addr);	}}/** * alb_change_hw_addr_on_detach * @bond: bonding we're working on * @slave: the slave that was just detached * * We assume that @slave was already detached from the slave list. * * If @slave's permanent hw address is different both from its current * address and from @bond's address, then somewhere in the bond there's * a slave that has @slave's permanet address as its current address. * We'll make sure that that slave no longer uses @slave's permanent address. * * Caller must hold bond lock */static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave){	int perm_curr_diff;	int perm_bond_diff;	perm_curr_diff = memcmp(slave->perm_hwaddr,				slave->dev->dev_addr,				ETH_ALEN);	perm_bond_diff = memcmp(slave->perm_hwaddr,				bond->dev->dev_addr,				ETH_ALEN);	if (perm_curr_diff && perm_bond_diff) {		struct slave *tmp_slave;		int i, found = 0;		bond_for_each_slave(bond, tmp_slave, i) {			if (!memcmp(slave->perm_hwaddr,				    tmp_slave->dev->dev_addr,				    ETH_ALEN)) {				found = 1;				break;			}		}		if (found) {			alb_swap_mac_addr(bond, slave, tmp_slave);		}	}}/** * alb_handle_addr_collision_on_attach * @bond: bonding we're working on * @slave: the slave that was just attached * * checks uniqueness of slave's mac address and handles the case the * new slave uses the bonds mac address. * * If the permanent hw address of @slave is @bond's hw address, we need to * find a different hw address to give @slave, that isn't in use by any other * slave in the bond. This address must be, of course, one of the premanent * addresses of the other slaves. * * We go over the slave list, and for each slave there we compare its * permanent hw address with the current address of all the other slaves. * If no match was found, then we've found a slave with a permanent address * that isn't used by any other slave in the bond, so we can assign it to * @slave. * * assumption: this function is called before @slave is attached to the * 	       bond slave list. * * caller must hold the bond lock for write since the mac addresses are compared * and may be swapped. */static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slave *slave){	struct slave *tmp_slave1, *tmp_slave2, *free_mac_slave;	struct slave *has_bond_addr = bond->curr_active_slave;	int i, j, found = 0;	if (bond->slave_cnt == 0) {		/* this is the first slave */		return 0;	}	/* if slave's mac address differs from bond's mac address	 * check uniqueness of slave's mac address against the other	 * slaves in the bond.	 */	if (memcmp(slave->perm_hwaddr, bond->dev->dev_addr, ETH_ALEN)) {		bond_for_each_slave(bond, tmp_slave1, i) {			if (!memcmp(tmp_slave1->dev->dev_addr, slave->dev->dev_addr,				    ETH_ALEN)) {				found = 1;				break;			}		}		if (!found)			return 0;		/* Try setting slave mac to bond address and fall-through		   to code handling that situation below... */		alb_set_slave_mac_addr(slave, bond->dev->dev_addr,				       bond->alb_info.rlb_enabled);	}	/* The slave's address is equal to the address of the bond.	 * Search for a spare address in the bond for this slave.	 */	free_mac_slave = NULL;	bond_for_each_slave(bond, tmp_slave1, i) {		found = 0;		bond_for_each_slave(bond, tmp_slave2, j) {			if (!memcmp(tmp_slave1->perm_hwaddr,				    tmp_slave2->dev->dev_addr,				    ETH_ALEN)) {				found = 1;

⌨️ 快捷键说明

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