tools/hv: Fix IP reporting by KVP daemon with SRIOV

On Hyper-V the VF NIC has the same MAC as the related synthetic NIC.
VF NIC can work under the synthetic NIC transparently, without its
own IP address. The existing KVP daemon only gets IP from the first
NIC matching a MAC address, and may not be able to find the IP in
this case.

This patch fixes the problem by searching the NIC matching the MAC,
and having an IP address. So, the IP address will be found and
reported to the host successfully.

Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Haiyang Zhang 2018-03-04 22:17:11 -07:00 committed by Greg Kroah-Hartman
parent 661e50bc85
commit 4ba6341286

View File

@ -634,64 +634,6 @@ static char *kvp_if_name_to_mac(char *if_name)
return mac_addr;
}
/*
* Retrieve the interface name given tha MAC address.
*/
static char *kvp_mac_to_if_name(char *mac)
{
DIR *dir;
struct dirent *entry;
FILE *file;
char *p, *x;
char *if_name = NULL;
char buf[256];
char dev_id[PATH_MAX];
unsigned int i;
dir = opendir(KVP_NET_DIR);
if (dir == NULL)
return NULL;
while ((entry = readdir(dir)) != NULL) {
/*
* Set the state for the next pass.
*/
snprintf(dev_id, sizeof(dev_id), "%s%s/address", KVP_NET_DIR,
entry->d_name);
file = fopen(dev_id, "r");
if (file == NULL)
continue;
p = fgets(buf, sizeof(buf), file);
if (p) {
x = strchr(p, '\n');
if (x)
*x = '\0';
for (i = 0; i < strlen(p); i++)
p[i] = toupper(p[i]);
if (!strcmp(p, mac)) {
/*
* Found the MAC match; return the interface
* name. The caller will free the memory.
*/
if_name = strdup(entry->d_name);
fclose(file);
break;
}
}
fclose(file);
}
closedir(dir);
return if_name;
}
static void kvp_process_ipconfig_file(char *cmd,
char *config_buf, unsigned int len,
int element_size, int offset)
@ -997,6 +939,70 @@ kvp_get_ip_info(int family, char *if_name, int op,
return error;
}
/*
* Retrieve the IP given the MAC address.
*/
static int kvp_mac_to_ip(struct hv_kvp_ipaddr_value *kvp_ip_val)
{
char *mac = (char *)kvp_ip_val->adapter_id;
DIR *dir;
struct dirent *entry;
FILE *file;
char *p, *x;
char *if_name = NULL;
char buf[256];
char dev_id[PATH_MAX];
unsigned int i;
int error = HV_E_FAIL;
dir = opendir(KVP_NET_DIR);
if (dir == NULL)
return HV_E_FAIL;
while ((entry = readdir(dir)) != NULL) {
/*
* Set the state for the next pass.
*/
snprintf(dev_id, sizeof(dev_id), "%s%s/address", KVP_NET_DIR,
entry->d_name);
file = fopen(dev_id, "r");
if (file == NULL)
continue;
p = fgets(buf, sizeof(buf), file);
fclose(file);
if (!p)
continue;
x = strchr(p, '\n');
if (x)
*x = '\0';
for (i = 0; i < strlen(p); i++)
p[i] = toupper(p[i]);
if (strcmp(p, mac))
continue;
/*
* Found the MAC match.
* A NIC (e.g. VF) matching the MAC, but without IP, is skipped.
*/
if_name = entry->d_name;
if (!if_name)
continue;
error = kvp_get_ip_info(0, if_name, KVP_OP_GET_IP_INFO,
kvp_ip_val, MAX_IP_ADDR_SIZE * 2);
if (!error && strlen((char *)kvp_ip_val->ip_addr))
break;
}
closedir(dir);
return error;
}
static int expand_ipv6(char *addr, int type)
{
@ -1472,26 +1478,12 @@ int main(int argc, char *argv[])
switch (op) {
case KVP_OP_GET_IP_INFO:
kvp_ip_val = &hv_msg->body.kvp_ip_val;
if_name =
kvp_mac_to_if_name((char *)kvp_ip_val->adapter_id);
if (if_name == NULL) {
/*
* We could not map the mac address to an
* interface name; return error.
*/
hv_msg->error = HV_E_FAIL;
break;
}
error = kvp_get_ip_info(
0, if_name, KVP_OP_GET_IP_INFO,
kvp_ip_val,
(MAX_IP_ADDR_SIZE * 2));
error = kvp_mac_to_ip(kvp_ip_val);
if (error)
hv_msg->error = error;
free(if_name);
break;
case KVP_OP_SET_IP_INFO: