hv_netvsc: pair VF based on serial number
Matching network device based on MAC address is problematic since a non VF network device can be creted with a duplicate MAC address causing confusion and problems. The VMBus API does provide a serial number that is a better matching method. Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									a15f2c08c7
								
							
						
					
					
						commit
						00d7ddba11
					
				| @ -1203,6 +1203,9 @@ static void netvsc_send_vf(struct net_device *ndev, | ||||
| 
 | ||||
| 	net_device_ctx->vf_alloc = nvmsg->msg.v4_msg.vf_assoc.allocated; | ||||
| 	net_device_ctx->vf_serial = nvmsg->msg.v4_msg.vf_assoc.serial; | ||||
| 	netdev_info(ndev, "VF slot %u %s\n", | ||||
| 		    net_device_ctx->vf_serial, | ||||
| 		    net_device_ctx->vf_alloc ? "added" : "removed"); | ||||
| } | ||||
| 
 | ||||
| static  void netvsc_receive_inband(struct net_device *ndev, | ||||
|  | ||||
| @ -1894,20 +1894,6 @@ out_unlock: | ||||
| 	rtnl_unlock(); | ||||
| } | ||||
| 
 | ||||
| static struct net_device *get_netvsc_bymac(const u8 *mac) | ||||
| { | ||||
| 	struct net_device_context *ndev_ctx; | ||||
| 
 | ||||
| 	list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) { | ||||
| 		struct net_device *dev = hv_get_drvdata(ndev_ctx->device_ctx); | ||||
| 
 | ||||
| 		if (ether_addr_equal(mac, dev->perm_addr)) | ||||
| 			return dev; | ||||
| 	} | ||||
| 
 | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static struct net_device *get_netvsc_byref(struct net_device *vf_netdev) | ||||
| { | ||||
| 	struct net_device_context *net_device_ctx; | ||||
| @ -2036,26 +2022,48 @@ static void netvsc_vf_setup(struct work_struct *w) | ||||
| 	rtnl_unlock(); | ||||
| } | ||||
| 
 | ||||
| /* Find netvsc by VMBus serial number.
 | ||||
|  * The PCI hyperv controller records the serial number as the slot. | ||||
|  */ | ||||
| static struct net_device *get_netvsc_byslot(const struct net_device *vf_netdev) | ||||
| { | ||||
| 	struct device *parent = vf_netdev->dev.parent; | ||||
| 	struct net_device_context *ndev_ctx; | ||||
| 	struct pci_dev *pdev; | ||||
| 
 | ||||
| 	if (!parent || !dev_is_pci(parent)) | ||||
| 		return NULL; /* not a PCI device */ | ||||
| 
 | ||||
| 	pdev = to_pci_dev(parent); | ||||
| 	if (!pdev->slot) { | ||||
| 		netdev_notice(vf_netdev, "no PCI slot information\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) { | ||||
| 		if (!ndev_ctx->vf_alloc) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (ndev_ctx->vf_serial == pdev->slot->number) | ||||
| 			return hv_get_drvdata(ndev_ctx->device_ctx); | ||||
| 	} | ||||
| 
 | ||||
| 	netdev_notice(vf_netdev, | ||||
| 		      "no netdev found for slot %u\n", pdev->slot->number); | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static int netvsc_register_vf(struct net_device *vf_netdev) | ||||
| { | ||||
| 	struct net_device *ndev; | ||||
| 	struct net_device_context *net_device_ctx; | ||||
| 	struct device *pdev = vf_netdev->dev.parent; | ||||
| 	struct netvsc_device *netvsc_dev; | ||||
| 	struct net_device *ndev; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (vf_netdev->addr_len != ETH_ALEN) | ||||
| 		return NOTIFY_DONE; | ||||
| 
 | ||||
| 	if (!pdev || !dev_is_pci(pdev) || dev_is_pf(pdev)) | ||||
| 		return NOTIFY_DONE; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * We will use the MAC address to locate the synthetic interface to | ||||
| 	 * associate with the VF interface. If we don't find a matching | ||||
| 	 * synthetic interface, move on. | ||||
| 	 */ | ||||
| 	ndev = get_netvsc_bymac(vf_netdev->perm_addr); | ||||
| 	ndev = get_netvsc_byslot(vf_netdev); | ||||
| 	if (!ndev) | ||||
| 		return NOTIFY_DONE; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user