From 9b5957803cb444a99275355eb2309b6fecc63c5f Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Mon, 13 Aug 2012 10:06:51 -0700 Subject: Drivers: hv: Add KVP definitions for IP address injection Add the necessary definitions for supporting the IP injection functionality. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Reviewed-by: Olaf Hering Reviewed-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index d9834b3..8fbcf7b 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -69,7 +69,7 @@ enum key_index { }; static char kvp_send_buffer[4096]; -static char kvp_recv_buffer[4096]; +static char kvp_recv_buffer[4096 * 2]; static struct sockaddr_nl addr; static char *os_name = ""; -- cgit v1.1 From b47a81dcc5a806efb6d970608299129771588289 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Mon, 13 Aug 2012 10:06:52 -0700 Subject: Drivers: hv: kvp: Cleanup error handling in KVP In preparation to implementing IP injection, cleanup the way we propagate and handle errors both in the driver as well as in the user level daemon. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Reviewed-by: Olaf Hering Reviewed-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 66 ++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 33 deletions(-) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 8fbcf7b..069e2b38 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -71,13 +71,14 @@ enum key_index { static char kvp_send_buffer[4096]; static char kvp_recv_buffer[4096 * 2]; static struct sockaddr_nl addr; +static int in_hand_shake = 1; static char *os_name = ""; static char *os_major = ""; static char *os_minor = ""; static char *processor_arch; static char *os_build; -static char *lic_version; +static char *lic_version = "Unknown version"; static struct utsname uts_buf; @@ -394,7 +395,7 @@ static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value, return 1; } -static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, +static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, __u8 *value, int value_size) { struct kvp_record *record; @@ -406,16 +407,12 @@ static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, record = kvp_file_info[pool].records; if (index >= kvp_file_info[pool].num_records) { - /* - * This is an invalid index; terminate enumeration; - * - a NULL value will do the trick. - */ - strcpy(value, ""); - return; + return 1; } memcpy(key, record[index].key, key_size); memcpy(value, record[index].value, value_size); + return 0; } @@ -646,6 +643,8 @@ int main(void) char *p; char *key_value; char *key_name; + int op; + int pool; daemon(1, 0); openlog("KVP", 0, LOG_USER); @@ -687,7 +686,7 @@ int main(void) message->id.val = CN_KVP_VAL; hv_msg = (struct hv_kvp_msg *)message->data; - hv_msg->kvp_hdr.operation = KVP_OP_REGISTER; + hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1; message->ack = 0; message->len = sizeof(struct hv_kvp_msg); @@ -721,12 +720,21 @@ int main(void) incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data; - switch (hv_msg->kvp_hdr.operation) { - case KVP_OP_REGISTER: + /* + * We will use the KVP header information to pass back + * the error from this daemon. So, first copy the state + * and set the error code to success. + */ + op = hv_msg->kvp_hdr.operation; + pool = hv_msg->kvp_hdr.pool; + hv_msg->error = HV_S_OK; + + if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) { /* * Driver is registering with us; stash away the version * information. */ + in_hand_shake = 0; p = (char *)hv_msg->body.kvp_register.version; lic_version = malloc(strlen(p) + 1); if (lic_version) { @@ -737,44 +745,39 @@ int main(void) syslog(LOG_ERR, "malloc failed"); } continue; + } - /* - * The current protocol with the kernel component uses a - * NULL key name to pass an error condition. - * For the SET, GET and DELETE operations, - * use the existing protocol to pass back error. - */ - + switch (op) { case KVP_OP_SET: - if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool, + if (kvp_key_add_or_modify(pool, hv_msg->body.kvp_set.data.key, hv_msg->body.kvp_set.data.key_size, hv_msg->body.kvp_set.data.value, hv_msg->body.kvp_set.data.value_size)) - strcpy(hv_msg->body.kvp_set.data.key, ""); + hv_msg->error = HV_S_CONT; break; case KVP_OP_GET: - if (kvp_get_value(hv_msg->kvp_hdr.pool, + if (kvp_get_value(pool, hv_msg->body.kvp_set.data.key, hv_msg->body.kvp_set.data.key_size, hv_msg->body.kvp_set.data.value, hv_msg->body.kvp_set.data.value_size)) - strcpy(hv_msg->body.kvp_set.data.key, ""); + hv_msg->error = HV_S_CONT; break; case KVP_OP_DELETE: - if (kvp_key_delete(hv_msg->kvp_hdr.pool, + if (kvp_key_delete(pool, hv_msg->body.kvp_delete.key, hv_msg->body.kvp_delete.key_size)) - strcpy(hv_msg->body.kvp_delete.key, ""); + hv_msg->error = HV_S_CONT; break; default: break; } - if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE) + if (op != KVP_OP_ENUMERATE) goto kvp_done; /* @@ -782,13 +785,14 @@ int main(void) * both the key and the value; if not read from the * appropriate pool. */ - if (hv_msg->kvp_hdr.pool != KVP_POOL_AUTO) { - kvp_pool_enumerate(hv_msg->kvp_hdr.pool, + if (pool != KVP_POOL_AUTO) { + if (kvp_pool_enumerate(pool, hv_msg->body.kvp_enum_data.index, hv_msg->body.kvp_enum_data.data.key, HV_KVP_EXCHANGE_MAX_KEY_SIZE, hv_msg->body.kvp_enum_data.data.value, - HV_KVP_EXCHANGE_MAX_VALUE_SIZE); + HV_KVP_EXCHANGE_MAX_VALUE_SIZE)) + hv_msg->error = HV_S_CONT; goto kvp_done; } @@ -841,11 +845,7 @@ int main(void) strcpy(key_name, "ProcessorArchitecture"); break; default: - strcpy(key_value, "Unknown Key"); - /* - * We use a null key name to terminate enumeration. - */ - strcpy(key_name, ""); + hv_msg->error = HV_S_CONT; break; } /* -- cgit v1.1 From 0ecaa1985e39344ab308190063f8a60cb2a96155 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Thu, 16 Aug 2012 18:32:13 -0700 Subject: Tools: hv: Prepare to expand kvp_get_ip_address() functionality kvp_get_ip_address() implemented the functionality to retrieve IP address info. Make this function more generic so that we could retrieve additional per-interface information. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 129 ++++++++++++++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 45 deletions(-) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 069e2b38..3af37f00 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -492,7 +492,8 @@ done: } static int -kvp_get_ip_address(int family, char *buffer, int length) +kvp_get_ip_address(int family, char *if_name, int op, + void *out_buffer, int length) { struct ifaddrs *ifap; struct ifaddrs *curp; @@ -502,10 +503,19 @@ kvp_get_ip_address(int family, char *buffer, int length) const char *str; char tmp[50]; int error = 0; - + char *buffer; + struct hv_kvp_ipaddr_value *ip_buffer; + + if (op == KVP_OP_ENUMERATE) { + buffer = out_buffer; + } else { + ip_buffer = out_buffer; + buffer = (char *)ip_buffer->ip_addr; + ip_buffer->addr_family = 0; + } /* * On entry into this function, the buffer is capable of holding the - * maximum key value (2048 bytes). + * maximum key value. */ if (getifaddrs(&ifap)) { @@ -515,58 +525,87 @@ kvp_get_ip_address(int family, char *buffer, int length) curp = ifap; while (curp != NULL) { - if ((curp->ifa_addr != NULL) && - (curp->ifa_addr->sa_family == family)) { - if (family == AF_INET) { - struct sockaddr_in *addr = - (struct sockaddr_in *) curp->ifa_addr; - - str = inet_ntop(family, &addr->sin_addr, - tmp, 50); - if (str == NULL) { - strcpy(buffer, "inet_ntop failed\n"); - error = 1; - goto getaddr_done; - } - if (offset == 0) - strcpy(buffer, tmp); - else - strcat(buffer, tmp); - strcat(buffer, ";"); + if (curp->ifa_addr == NULL) { + curp = curp->ifa_next; + continue; + } - offset += strlen(str) + 1; - if ((length - offset) < (ipv4_len + 1)) - goto getaddr_done; + if ((if_name != NULL) && + (strncmp(curp->ifa_name, if_name, strlen(if_name)))) { + /* + * We want info about a specific interface; + * just continue. + */ + curp = curp->ifa_next; + continue; + } - } else { + /* + * We only support two address families: AF_INET and AF_INET6. + * If a family value of 0 is specified, we collect both + * supported address families; if not we gather info on + * the specified address family. + */ + if ((family != 0) && (curp->ifa_addr->sa_family != family)) { + curp = curp->ifa_next; + continue; + } + if ((curp->ifa_addr->sa_family != AF_INET) && + (curp->ifa_addr->sa_family != AF_INET6)) { + curp = curp->ifa_next; + continue; + } + + if ((curp->ifa_addr->sa_family == AF_INET) && + ((family == AF_INET) || (family == 0))) { + struct sockaddr_in *addr = + (struct sockaddr_in *) curp->ifa_addr; + + str = inet_ntop(AF_INET, &addr->sin_addr, tmp, 50); + if (str == NULL) { + strcpy(buffer, "inet_ntop failed\n"); + error = 1; + goto getaddr_done; + } + if (offset == 0) + strcpy(buffer, tmp); + else + strcat(buffer, tmp); + strcat(buffer, ";"); + + offset += strlen(str) + 1; + if ((length - offset) < (ipv4_len + 1)) + goto getaddr_done; + + } else if ((family == AF_INET6) || (family == 0)) { /* * We only support AF_INET and AF_INET6 * and the list of addresses is separated by a ";". */ - struct sockaddr_in6 *addr = + struct sockaddr_in6 *addr = (struct sockaddr_in6 *) curp->ifa_addr; - str = inet_ntop(family, + str = inet_ntop(AF_INET6, &addr->sin6_addr.s6_addr, tmp, 50); - if (str == NULL) { - strcpy(buffer, "inet_ntop failed\n"); - error = 1; - goto getaddr_done; - } - if (offset == 0) - strcpy(buffer, tmp); - else - strcat(buffer, tmp); - strcat(buffer, ";"); - offset += strlen(str) + 1; - if ((length - offset) < (ipv6_len + 1)) - goto getaddr_done; - + if (str == NULL) { + strcpy(buffer, "inet_ntop failed\n"); + error = 1; + goto getaddr_done; } + if (offset == 0) + strcpy(buffer, tmp); + else + strcat(buffer, tmp); + strcat(buffer, ";"); + offset += strlen(str) + 1; + if ((length - offset) < (ipv6_len + 1)) + goto getaddr_done; } + + curp = curp->ifa_next; } @@ -811,13 +850,13 @@ int main(void) strcpy(key_value, lic_version); break; case NetworkAddressIPv4: - kvp_get_ip_address(AF_INET, key_value, - HV_KVP_EXCHANGE_MAX_VALUE_SIZE); + kvp_get_ip_address(AF_INET, NULL, KVP_OP_ENUMERATE, + key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); strcpy(key_name, "NetworkAddressIPv4"); break; case NetworkAddressIPv6: - kvp_get_ip_address(AF_INET6, key_value, - HV_KVP_EXCHANGE_MAX_VALUE_SIZE); + kvp_get_ip_address(AF_INET6, NULL, KVP_OP_ENUMERATE, + key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); strcpy(key_name, "NetworkAddressIPv6"); break; case OSBuildNumber: -- cgit v1.1 From af733015c9f59a0993cb9a64e6904aed8612e8b3 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Thu, 16 Aug 2012 18:32:14 -0700 Subject: Tools: hv: Further refactor kvp_get_ip_address() In preparation for making kvp_get_ip_address() more generic, factor out the code for handling IP addresses. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 94 ++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 52 deletions(-) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 3af37f00..3dc989f 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -491,17 +491,50 @@ done: return; } +static int kvp_process_ip_address(void *addrp, + int family, char *buffer, + int length, int *offset) +{ + struct sockaddr_in *addr; + struct sockaddr_in6 *addr6; + int addr_length; + char tmp[50]; + const char *str; + + if (family == AF_INET) { + addr = (struct sockaddr_in *)addrp; + str = inet_ntop(family, &addr->sin_addr, tmp, 50); + addr_length = INET_ADDRSTRLEN; + } else { + addr6 = (struct sockaddr_in6 *)addrp; + str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50); + addr_length = INET6_ADDRSTRLEN; + } + + if ((length - *offset) < addr_length + 1) + return 1; + if (str == NULL) { + strcpy(buffer, "inet_ntop failed\n"); + return 1; + } + if (*offset == 0) + strcpy(buffer, tmp); + else + strcat(buffer, tmp); + strcat(buffer, ";"); + + *offset += strlen(str) + 1; + return 0; +} + static int kvp_get_ip_address(int family, char *if_name, int op, void *out_buffer, int length) { struct ifaddrs *ifap; struct ifaddrs *curp; - int ipv4_len = strlen("255.255.255.255") + 1; - int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1; int offset = 0; const char *str; - char tmp[50]; int error = 0; char *buffer; struct hv_kvp_ipaddr_value *ip_buffer; @@ -556,55 +589,12 @@ kvp_get_ip_address(int family, char *if_name, int op, continue; } - if ((curp->ifa_addr->sa_family == AF_INET) && - ((family == AF_INET) || (family == 0))) { - struct sockaddr_in *addr = - (struct sockaddr_in *) curp->ifa_addr; - - str = inet_ntop(AF_INET, &addr->sin_addr, tmp, 50); - if (str == NULL) { - strcpy(buffer, "inet_ntop failed\n"); - error = 1; - goto getaddr_done; - } - if (offset == 0) - strcpy(buffer, tmp); - else - strcat(buffer, tmp); - strcat(buffer, ";"); - - offset += strlen(str) + 1; - if ((length - offset) < (ipv4_len + 1)) - goto getaddr_done; - - } else if ((family == AF_INET6) || (family == 0)) { - - /* - * We only support AF_INET and AF_INET6 - * and the list of addresses is separated by a ";". - */ - struct sockaddr_in6 *addr = - (struct sockaddr_in6 *) curp->ifa_addr; - - str = inet_ntop(AF_INET6, - &addr->sin6_addr.s6_addr, - tmp, 50); - if (str == NULL) { - strcpy(buffer, "inet_ntop failed\n"); - error = 1; - goto getaddr_done; - } - if (offset == 0) - strcpy(buffer, tmp); - else - strcat(buffer, tmp); - strcat(buffer, ";"); - offset += strlen(str) + 1; - if ((length - offset) < (ipv6_len + 1)) - goto getaddr_done; - - } - + error = kvp_process_ip_address(curp->ifa_addr, + curp->ifa_addr->sa_family, + buffer, + length, &offset); + if (error) + goto getaddr_done; curp = curp->ifa_next; } -- cgit v1.1 From 0d5b6b197f9b9a58ead8ac5e68e38c068c31ba4c Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Thu, 16 Aug 2012 18:32:15 -0700 Subject: Tools: hv: Gather address family information Now, gather address family information for the specified interface. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 3dc989f..13ae098 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -589,6 +589,17 @@ kvp_get_ip_address(int family, char *if_name, int op, continue; } + if (op == KVP_OP_GET_IP_INFO) { + /* + * Gather info other than the IP address. + * IP address info will be gathered later. + */ + if (curp->ifa_addr->sa_family == AF_INET) + ip_buffer->addr_family |= ADDR_FAMILY_IPV4; + else + ip_buffer->addr_family |= ADDR_FAMILY_IPV6; + } + error = kvp_process_ip_address(curp->ifa_addr, curp->ifa_addr->sa_family, buffer, -- cgit v1.1 From 04405784591117539eac4f5348c86d66dc0dd4f1 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Thu, 16 Aug 2012 18:32:16 -0700 Subject: Tools: hv: Gather subnet information Now, gather sub-net information for the specified interface. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 13ae098..de1724c 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -534,6 +534,7 @@ kvp_get_ip_address(int family, char *if_name, int op, struct ifaddrs *ifap; struct ifaddrs *curp; int offset = 0; + int sn_offset = 0; const char *str; int error = 0; char *buffer; @@ -594,12 +595,38 @@ kvp_get_ip_address(int family, char *if_name, int op, * Gather info other than the IP address. * IP address info will be gathered later. */ - if (curp->ifa_addr->sa_family == AF_INET) + if (curp->ifa_addr->sa_family == AF_INET) { ip_buffer->addr_family |= ADDR_FAMILY_IPV4; - else + /* + * Get subnet info. + */ + error = kvp_process_ip_address( + curp->ifa_netmask, + AF_INET, + (char *) + ip_buffer->sub_net, + length, + &sn_offset); + if (error) + goto gather_ipaddr; + } else { ip_buffer->addr_family |= ADDR_FAMILY_IPV6; + /* + * Get subnet info. + */ + error = kvp_process_ip_address( + curp->ifa_netmask, + AF_INET6, + (char *) + ip_buffer->sub_net, + length, + &sn_offset); + if (error) + goto gather_ipaddr; + } } +gather_ipaddr: error = kvp_process_ip_address(curp->ifa_addr, curp->ifa_addr->sa_family, buffer, -- cgit v1.1 From 6a60a6a8ea97795a288469c21262522894a1e6db Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Thu, 16 Aug 2012 18:32:17 -0700 Subject: Tools: hv: Represent the ipv6 mask using CIDR notation Transform ipv6 subnet information to CIDR notation. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index de1724c..a63e83a 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -491,6 +491,15 @@ done: return; } +static unsigned int hweight32(unsigned int *w) +{ + unsigned int res = *w - ((*w >> 1) & 0x55555555); + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res + (res >> 4)) & 0x0F0F0F0F; + res = res + (res >> 8); + return (res + (res >> 16)) & 0x000000FF; +} + static int kvp_process_ip_address(void *addrp, int family, char *buffer, int length, int *offset) @@ -535,10 +544,15 @@ kvp_get_ip_address(int family, char *if_name, int op, struct ifaddrs *curp; int offset = 0; int sn_offset = 0; - const char *str; int error = 0; char *buffer; struct hv_kvp_ipaddr_value *ip_buffer; + char cidr_mask[5]; /* /xyz */ + int weight; + int i; + unsigned int *w; + char *sn_str; + struct sockaddr_in6 *addr6; if (op == KVP_OP_ENUMERATE) { buffer = out_buffer; @@ -611,18 +625,30 @@ kvp_get_ip_address(int family, char *if_name, int op, goto gather_ipaddr; } else { ip_buffer->addr_family |= ADDR_FAMILY_IPV6; + /* - * Get subnet info. + * Get subnet info in CIDR format. */ - error = kvp_process_ip_address( - curp->ifa_netmask, - AF_INET6, - (char *) - ip_buffer->sub_net, - length, - &sn_offset); - if (error) + weight = 0; + sn_str = (char *)ip_buffer->sub_net; + addr6 = (struct sockaddr_in6 *) + curp->ifa_netmask; + w = addr6->sin6_addr.s6_addr32; + + for (i = 0; i < 4; i++) + weight += hweight32(&w[i]); + + sprintf(cidr_mask, "/%d", weight); + if ((length - sn_offset) < + (strlen(cidr_mask) + 1)) goto gather_ipaddr; + + if (sn_offset == 0) + strcpy(sn_str, cidr_mask); + else + strcat(sn_str, cidr_mask); + strcat((char *)ip_buffer->sub_net, ";"); + sn_offset += strlen(sn_str) + 1; } } -- cgit v1.1 From 4a52c4af48a2a35282ddc4dcf2df83486d636754 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Thu, 16 Aug 2012 18:32:18 -0700 Subject: Tools: hv: Gather ipv[4,6] gateway information Gather information on the default gateways - ipv4/ipv6. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index a63e83a..65d54c8 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -491,6 +491,68 @@ done: return; } +static void kvp_process_ipconfig_file(char *cmd, + char *config_buf, int len, + int element_size, int offset) +{ + char buf[256]; + char *p; + char *x; + FILE *file; + + /* + * First execute the command. + */ + file = popen(cmd, "r"); + if (file == NULL) + return; + + if (offset == 0) + memset(config_buf, 0, len); + while ((p = fgets(buf, sizeof(buf), file)) != NULL) { + if ((len - strlen(config_buf)) < (element_size + 1)) + break; + + x = strchr(p, '\n'); + *x = '\0'; + strcat(config_buf, p); + strcat(config_buf, ";"); + } + pclose(file); +} + +static void kvp_get_ipconfig_info(char *if_name, + struct hv_kvp_ipaddr_value *buffer) +{ + char cmd[512]; + + /* + * Get the address of default gateway (ipv4). + */ + sprintf(cmd, "%s %s", "ip route show dev", if_name); + strcat(cmd, " | awk '/default/ {print $3 }'"); + + /* + * Execute the command to gather gateway info. + */ + kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, + (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0); + + /* + * Get the address of default gateway (ipv6). + */ + sprintf(cmd, "%s %s", "ip -f inet6 route show dev", if_name); + strcat(cmd, " | awk '/default/ {print $3 }'"); + + /* + * Execute the command to gather gateway info (ipv6). + */ + kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, + (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1); + +} + + static unsigned int hweight32(unsigned int *w) { unsigned int res = *w - ((*w >> 1) & 0x55555555); @@ -650,6 +712,12 @@ kvp_get_ip_address(int family, char *if_name, int op, strcat((char *)ip_buffer->sub_net, ";"); sn_offset += strlen(sn_str) + 1; } + + /* + * Collect other ip related configuration info. + */ + + kvp_get_ipconfig_info(if_name, ip_buffer); } gather_ipaddr: -- cgit v1.1 From 00b8335517b50b716960377b63a9ae63ed72322c Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Tue, 4 Sep 2012 14:46:33 -0700 Subject: Tools: hv: Get rid of some unused variables Get rid of unused variables. Reported-by: Ben Hutchings Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 65d54c8..d12d714 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -196,7 +196,7 @@ static void kvp_update_mem_state(int pool) } static int kvp_file_init(void) { - int ret, fd; + int fd; FILE *filep; size_t records_read; __u8 *fname; @@ -312,7 +312,6 @@ static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value, int value_size) { int i; - int j, k; int num_records; struct kvp_record *record; int num_blocks; -- cgit v1.1 From d0cbc156a7689348e56ac9b871c988b59b9f9ff0 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Tue, 4 Sep 2012 14:46:34 -0700 Subject: Tools: hv: Correctly type string variables Correctly type character strings. Reported-by: Ben Hutchings Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index d12d714..026bf0e 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -86,8 +86,8 @@ static struct utsname uts_buf; #define ENTRIES_PER_BLOCK 50 struct kvp_record { - __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; - __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; + char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; + char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; }; struct kvp_file_state { @@ -95,7 +95,7 @@ struct kvp_file_state { int num_blocks; struct kvp_record *records; int num_records; - __u8 fname[MAX_FILE_NAME]; + char fname[MAX_FILE_NAME]; }; static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT]; @@ -199,7 +199,7 @@ static int kvp_file_init(void) int fd; FILE *filep; size_t records_read; - __u8 *fname; + char *fname; struct kvp_record *record; struct kvp_record *readp; int num_blocks; -- cgit v1.1 From d82c37ce6896734a4a2a9b74c22084fe47824466 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Tue, 4 Sep 2012 14:46:35 -0700 Subject: Tools: hv: Add an example script to retrieve DNS entries To keep the KVP daemon code free of distro specific details, we invoke an external script to retrieve the DNS entries. This is an example script that was used to test the KVP code. This script has to be implemented in a Distro specific fashion. For instance on distros that ship with Network Manager enabled, this script can be based on NM APIs. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_get_dns_info.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100755 tools/hv/hv_get_dns_info.sh (limited to 'tools') diff --git a/tools/hv/hv_get_dns_info.sh b/tools/hv/hv_get_dns_info.sh new file mode 100755 index 0000000..058c17b --- /dev/null +++ b/tools/hv/hv_get_dns_info.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# This example script parses /etc/resolv.conf to retrive DNS information. +# In the interest of keeping the KVP daemon code free of distro specific +# information; the kvp daemon code invokes this external script to gather +# DNS information. +# This script is expected to print the nameserver values to stdout. +# Each Distro is expected to implement this script in a distro specific +# fashion. For instance on Distros that ship with Network Manager enabled, +# this script can be based on the Network Manager APIs for retrieving DNS +# entries. + +cat /etc/resolv.conf 2>/dev/null | awk '/^nameserver/ { print $2 }' -- cgit v1.1 From 969298879c89dc30f8272ce2aa64dadd9315fd58 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Tue, 4 Sep 2012 14:46:36 -0700 Subject: Tools: hv: Gather DNS information Now, gather DNS information. Invoke an external script (that can be distro dependent) to gather the DNS information. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 026bf0e..cfa23a1 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -549,6 +549,29 @@ static void kvp_get_ipconfig_info(char *if_name, kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way, (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1); + + /* + * Gather the DNS state. + * Since there is no standard way to get this information + * across various distributions of interest; we just invoke + * an external script that needs to be ported across distros + * of interest. + * + * Following is the expected format of the information from the script: + * + * ipaddr1 (nameserver1) + * ipaddr2 (nameserver2) + * . + * . + */ + + sprintf(cmd, "%s", "hv_get_dns_info"); + + /* + * Execute the command to gather DNS info. + */ + kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr, + (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0); } -- cgit v1.1 From 2aea3c712826824dbbbaa7b9c0b70936819304b4 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Wed, 5 Sep 2012 13:50:10 -0700 Subject: Tools: hv: Add an example script to retrieve dhcp state To keep the KVP daemon code free of distro specific details, we invoke an external script to retrieve the DHCP state. This is an example script that was used to test the KVP code. This script has to be implemented in a Distro specific fashion. For instance on distros that ship with Network Manager enabled, this script can be based on NM APIs. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_get_dhcp_info.sh | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100755 tools/hv/hv_get_dhcp_info.sh (limited to 'tools') diff --git a/tools/hv/hv_get_dhcp_info.sh b/tools/hv/hv_get_dhcp_info.sh new file mode 100755 index 0000000..ccd3e95 --- /dev/null +++ b/tools/hv/hv_get_dhcp_info.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# This example script retrieves the DHCP state of a given interface. +# In the interest of keeping the KVP daemon code free of distro specific +# information; the kvp daemon code invokes this external script to gather +# DHCP setting for the specific interface. +# +# Input: Name of the interface +# +# Output: The script prints the string "Enabled" to stdout to indicate +# that DHCP is enabled on the interface. If DHCP is not enabled, +# the script prints the string "Disabled" to stdout. +# +# Each Distro is expected to implement this script in a distro specific +# fashion. For instance on Distros that ship with Network Manager enabled, +# this script can be based on the Network Manager APIs for retrieving DHCP +# information. + +if_file="/etc/sysconfig/network-scripts/ifcfg-"$1 + +dhcp=$(grep "dhcp" $if_file 2>/dev/null) + +if [ "$dhcp" != "" ]; +then +echo "Enabled" +else +echo "Disabled" +fi -- cgit v1.1 From c050372591bed4488a32e8bf271ae471af5098eb Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Wed, 5 Sep 2012 13:50:11 -0700 Subject: Tools: hv: Gather DHCP information Collect information on dhcp setting for the specified interface. We invoke an external (Distro specific) script to get this information. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index cfa23a1..6fb2c1c 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -524,6 +524,9 @@ static void kvp_get_ipconfig_info(char *if_name, struct hv_kvp_ipaddr_value *buffer) { char cmd[512]; + char dhcp_info[128]; + char *p; + FILE *file; /* * Get the address of default gateway (ipv4). @@ -572,6 +575,34 @@ static void kvp_get_ipconfig_info(char *if_name, */ kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr, (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0); + + /* + * Gather the DHCP state. + * We will gather this state by invoking an external script. + * The parameter to the script is the interface name. + * Here is the expected output: + * + * Enabled: DHCP enabled. + */ + + sprintf(cmd, "%s %s", "hv_get_dhcp_info", if_name); + + file = popen(cmd, "r"); + if (file == NULL) + return; + + p = fgets(dhcp_info, sizeof(dhcp_info), file); + if (p == NULL) { + pclose(file); + return; + } + + if (!strncmp(p, "Enabled", 7)) + buffer->dhcp_enabled = 1; + else + buffer->dhcp_enabled = 0; + + pclose(file); } -- cgit v1.1 From 1fbdba4edd071daffbba1c172abb44bbe6a4344a Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Wed, 5 Sep 2012 13:50:12 -0700 Subject: Tools: hv: Add an example script to configure an interface To keep the KVP daemon code free of distro specific details, we invoke an external script to configure the interface. This is an example script that was used to test the KVP code. This script has to be implemented in a Distro specific fashion. For instance on distros that ship with Network Manager enabled, this script can be based on NM APIs. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_set_ifconfig.sh | 68 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100755 tools/hv/hv_set_ifconfig.sh (limited to 'tools') diff --git a/tools/hv/hv_set_ifconfig.sh b/tools/hv/hv_set_ifconfig.sh new file mode 100755 index 0000000..3e9427e --- /dev/null +++ b/tools/hv/hv_set_ifconfig.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +# This example script activates an interface based on the specified +# configuration. +# +# In the interest of keeping the KVP daemon code free of distro specific +# information; the kvp daemon code invokes this external script to configure +# the interface. +# +# The only argument to this script is the configuration file that is to +# be used to configure the interface. +# +# Each Distro is expected to implement this script in a distro specific +# fashion. For instance on Distros that ship with Network Manager enabled, +# this script can be based on the Network Manager APIs for configuring the +# interface. +# +# This example script is based on a RHEL environment. +# +# Here is the format of the ip configuration file: +# +# HWADDR=macaddr +# IF_NAME=interface name +# DHCP=yes (This is optional; if yes, DHCP is configured) +# +# IPADDR=ipaddr1 +# IPADDR_1=ipaddr2 +# IPADDR_x=ipaddry (where y = x + 1) +# +# NETMASK=netmask1 +# NETMASK_x=netmasky (where y = x + 1) +# +# GATEWAY=ipaddr1 +# GATEWAY_x=ipaddry (where y = x + 1) +# +# DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc) +# +# IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be +# tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as +# IPV6NETMASK. +# +# The host can specify multiple ipv4 and ipv6 addresses to be +# configured for the interface. Furthermore, the configuration +# needs to be persistent. A subsequent GET call on the interface +# is expected to return the configuration that is set via the SET +# call. +# + + + +echo "IPV6INIT=yes" >> $1 +echo "NM_CONTROLLED=no" >> $1 +echo "PEERDNS=yes" >> $1 +echo "ONBOOT=yes" >> $1 + +dhcp=$(grep "DHCP" $1 2>/dev/null) +if [ "$dhcp" != "" ]; +then +echo "BOOTPROTO=dhcp" >> $1; +fi + +cp $1 /etc/sysconfig/network-scripts/ + + +interface=$(echo $1 | awk -F - '{ print $2 }') + +/sbin/ifdown $interface 2>/dev/null +/sbin/ifup $interfac 2>/dev/null -- cgit v1.1 From 32061b4d3830e61975ede409df389804507fd220 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Wed, 5 Sep 2012 13:50:13 -0700 Subject: Tools: hv: Implement the KVP verb - KVP_OP_SET_IP_INFO Implement the KVP verb - KVP_OP_SET_IP_INFO. This operation configures the specified interface based on the given configuration. Since configuring an interface is very distro specific, we invoke an external (Distro specific) script to configure the interface. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 443 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 443 insertions(+) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 6fb2c1c..ac144b9 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,7 @@ #include #include #include +#include /* * KVP protocol: The user mode component first registers with the @@ -68,6 +70,14 @@ enum key_index { ProcessorArchitecture }; + +enum { + IPADDR = 0, + NETMASK, + GATEWAY, + DNS +}; + static char kvp_send_buffer[4096]; static char kvp_recv_buffer[4096 * 2]; static struct sockaddr_nl addr; @@ -81,6 +91,11 @@ static char *os_build; static char *lic_version = "Unknown version"; static struct utsname uts_buf; +/* + * The location of the interface configuration file. + */ + +#define KVP_CONFIG_LOC "/var/opt/" #define MAX_FILE_NAME 100 #define ENTRIES_PER_BLOCK 50 @@ -490,6 +505,104 @@ done: return; } + + +/* + * Retrieve an interface name corresponding to the specified guid. + * If there is a match, the function returns a pointer + * to the interface name and if not, a NULL is returned. + * If a match is found, the caller is responsible for + * freeing the memory. + */ + +static char *kvp_get_if_name(char *guid) +{ + DIR *dir; + struct dirent *entry; + FILE *file; + char *p, *q, *x; + char *if_name = NULL; + char buf[256]; + char *kvp_net_dir = "/sys/class/net/"; + char dev_id[256]; + + dir = opendir(kvp_net_dir); + if (dir == NULL) + return NULL; + + snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir); + q = dev_id + strlen(kvp_net_dir); + + while ((entry = readdir(dir)) != NULL) { + /* + * Set the state for the next pass. + */ + *q = '\0'; + strcat(dev_id, entry->d_name); + strcat(dev_id, "/device/device_id"); + + 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'; + + if (!strcmp(p, guid)) { + /* + * Found the guid 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; +} + +/* + * Retrieve the MAC address given the interface name. + */ + +static char *kvp_if_name_to_mac(char *if_name) +{ + FILE *file; + char *p, *x; + char buf[256]; + char addr_file[256]; + int i; + char *mac_addr = NULL; + + snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/", + if_name, "/address"); + + file = fopen(addr_file, "r"); + if (file == NULL) + return NULL; + + 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]); + mac_addr = strdup(p); + } + + fclose(file); + return mac_addr; +} + + static void kvp_process_ipconfig_file(char *cmd, char *config_buf, int len, int element_size, int offset) @@ -790,6 +903,315 @@ getaddr_done: } +static int expand_ipv6(char *addr, int type) +{ + int ret; + struct in6_addr v6_addr; + + ret = inet_pton(AF_INET6, addr, &v6_addr); + + if (ret != 1) { + if (type == NETMASK) + return 1; + return 0; + } + + sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:" + "%02x%02x:%02x%02x:%02x%02x", + (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1], + (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3], + (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5], + (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7], + (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9], + (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11], + (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13], + (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]); + + return 1; + +} + +static int is_ipv4(char *addr) +{ + int ret; + struct in_addr ipv4_addr; + + ret = inet_pton(AF_INET, addr, &ipv4_addr); + + if (ret == 1) + return 1; + return 0; +} + +static int parse_ip_val_buffer(char *in_buf, int *offset, + char *out_buf, int out_len) +{ + char *x; + char *start; + + /* + * in_buf has sequence of characters that are seperated by + * the character ';'. The last sequence does not have the + * terminating ";" character. + */ + start = in_buf + *offset; + + x = strchr(start, ';'); + if (x) + *x = 0; + else + x = start + strlen(start); + + if (strlen(start) != 0) { + int i = 0; + /* + * Get rid of leading spaces. + */ + while (start[i] == ' ') + i++; + + if ((x - start) <= out_len) { + strcpy(out_buf, (start + i)); + *offset += (x - start) + 1; + return 1; + } + } + return 0; +} + +static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3) +{ + int ret; + + ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3); + + if (ret < 0) + return HV_E_FAIL; + + return 0; +} + + +static int process_ip_string(FILE *f, char *ip_string, int type) +{ + int error = 0; + char addr[INET6_ADDRSTRLEN]; + int i = 0; + int j = 0; + char str[256]; + char sub_str[10]; + int offset = 0; + + memset(addr, 0, sizeof(addr)); + + while (parse_ip_val_buffer(ip_string, &offset, addr, + (MAX_IP_ADDR_SIZE * 2))) { + + sub_str[0] = 0; + if (is_ipv4(addr)) { + switch (type) { + case IPADDR: + snprintf(str, sizeof(str), "%s", "IPADDR"); + break; + case NETMASK: + snprintf(str, sizeof(str), "%s", "NETMASK"); + break; + case GATEWAY: + snprintf(str, sizeof(str), "%s", "GATEWAY"); + break; + case DNS: + snprintf(str, sizeof(str), "%s", "DNS"); + break; + } + if (i != 0) { + if (type != DNS) { + snprintf(sub_str, sizeof(sub_str), + "_%d", i++); + } else { + snprintf(sub_str, sizeof(sub_str), + "%d", ++i); + } + } else if (type == DNS) { + snprintf(sub_str, sizeof(sub_str), "%d", ++i); + } + + + } else if (expand_ipv6(addr, type)) { + switch (type) { + case IPADDR: + snprintf(str, sizeof(str), "%s", "IPV6ADDR"); + break; + case NETMASK: + snprintf(str, sizeof(str), "%s", "IPV6NETMASK"); + break; + case GATEWAY: + snprintf(str, sizeof(str), "%s", + "IPV6_DEFAULTGW"); + break; + case DNS: + snprintf(str, sizeof(str), "%s", "DNS"); + break; + } + if ((j != 0) || (type == DNS)) { + if (type != DNS) { + snprintf(sub_str, sizeof(sub_str), + "_%d", j++); + } else { + snprintf(sub_str, sizeof(sub_str), + "%d", ++i); + } + } else if (type == DNS) { + snprintf(sub_str, sizeof(sub_str), + "%d", ++i); + } + } else { + return HV_INVALIDARG; + } + + error = kvp_write_file(f, str, sub_str, addr); + if (error) + return error; + memset(addr, 0, sizeof(addr)); + } + + return 0; +} + +static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) +{ + int error = 0; + char if_file[128]; + FILE *file; + char cmd[512]; + char *mac_addr; + + /* + * Set the configuration for the specified interface with + * the information provided. Since there is no standard + * way to configure an interface, we will have an external + * script that does the job of configuring the interface and + * flushing the configuration. + * + * The parameters passed to this external script are: + * 1. A configuration file that has the specified configuration. + * + * We will embed the name of the interface in the configuration + * file: ifcfg-ethx (where ethx is the interface name). + * + * The information provided here may be more than what is needed + * in a given distro to configure the interface and so are free + * ignore information that may not be relevant. + * + * Here is the format of the ip configuration file: + * + * HWADDR=macaddr + * IF_NAME=interface name + * DHCP=yes (This is optional; if yes, DHCP is configured) + * + * IPADDR=ipaddr1 + * IPADDR_1=ipaddr2 + * IPADDR_x=ipaddry (where y = x + 1) + * + * NETMASK=netmask1 + * NETMASK_x=netmasky (where y = x + 1) + * + * GATEWAY=ipaddr1 + * GATEWAY_x=ipaddry (where y = x + 1) + * + * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc) + * + * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be + * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as + * IPV6NETMASK. + * + * The host can specify multiple ipv4 and ipv6 addresses to be + * configured for the interface. Furthermore, the configuration + * needs to be persistent. A subsequent GET call on the interface + * is expected to return the configuration that is set via the SET + * call. + */ + + snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC, + "hyperv/ifcfg-", if_name); + + file = fopen(if_file, "w"); + + if (file == NULL) { + syslog(LOG_ERR, "Failed to open config file"); + return HV_E_FAIL; + } + + /* + * First write out the MAC address. + */ + + mac_addr = kvp_if_name_to_mac(if_name); + if (mac_addr == NULL) { + error = HV_E_FAIL; + goto setval_error; + } + + error = kvp_write_file(file, "HWADDR", "", mac_addr); + if (error) + goto setval_error; + + error = kvp_write_file(file, "IF_NAME", "", if_name); + if (error) + goto setval_error; + + if (new_val->dhcp_enabled) { + error = kvp_write_file(file, "DHCP", "", "yes"); + if (error) + goto setval_error; + + /* + * We are done!. + */ + goto setval_done; + } + + /* + * Write the configuration for ipaddress, netmask, gateway and + * name servers. + */ + + error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR); + if (error) + goto setval_error; + + error = process_ip_string(file, (char *)new_val->sub_net, NETMASK); + if (error) + goto setval_error; + + error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY); + if (error) + goto setval_error; + + error = process_ip_string(file, (char *)new_val->dns_addr, DNS); + if (error) + goto setval_error; + +setval_done: + free(mac_addr); + fclose(file); + + /* + * Now that we have populated the configuration file, + * invoke the external script to do its magic. + */ + + snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file); + system(cmd); + return 0; + +setval_error: + syslog(LOG_ERR, "Failed to write config file"); + free(mac_addr); + fclose(file); + return error; +} + + static int kvp_get_domain_name(char *buffer, int length) { @@ -859,6 +1281,8 @@ int main(void) char *key_name; int op; int pool; + char *if_name; + struct hv_kvp_ipaddr_value *kvp_ip_val; daemon(1, 0); openlog("KVP", 0, LOG_USER); @@ -962,6 +1386,25 @@ int main(void) } switch (op) { + case KVP_OP_SET_IP_INFO: + kvp_ip_val = &hv_msg->body.kvp_ip_val; + if_name = kvp_get_if_name( + (char *)kvp_ip_val->adapter_id); + if (if_name == NULL) { + /* + * We could not map the guid to an + * interface name; return error. + */ + hv_msg->error = HV_GUID_NOTFOUND; + break; + } + error = kvp_set_ip_info(if_name, kvp_ip_val); + if (error) + hv_msg->error = error; + + free(if_name); + break; + case KVP_OP_SET: if (kvp_key_add_or_modify(pool, hv_msg->body.kvp_set.data.key, -- cgit v1.1 From 4a3b97e5799571397ade963c760b7406d8e9a8a6 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Wed, 5 Sep 2012 13:50:14 -0700 Subject: Tools: hv: Rename the function kvp_get_ip_address() Rename the function kvp_get_ip_address() to better reflect the functionality being implemented. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index ac144b9..849c438 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -765,7 +765,7 @@ static int kvp_process_ip_address(void *addrp, } static int -kvp_get_ip_address(int family, char *if_name, int op, +kvp_get_ip_info(int family, char *if_name, int op, void *out_buffer, int length) { struct ifaddrs *ifap; @@ -1468,12 +1468,12 @@ int main(void) strcpy(key_value, lic_version); break; case NetworkAddressIPv4: - kvp_get_ip_address(AF_INET, NULL, KVP_OP_ENUMERATE, + kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE, key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); strcpy(key_name, "NetworkAddressIPv4"); break; case NetworkAddressIPv6: - kvp_get_ip_address(AF_INET6, NULL, KVP_OP_ENUMERATE, + kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE, key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE); strcpy(key_name, "NetworkAddressIPv6"); break; -- cgit v1.1 From 16e87100e62330cb1e58ee772cacb7d4e6d5b61b Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Wed, 5 Sep 2012 13:50:15 -0700 Subject: Tools: hv: Implement the KVP verb - KVP_OP_GET_IP_INFO Now implement the KVP verb - KVP_OP_GET_IP_INFO. This operation retrieves IP information for the specified interface. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 849c438..c8e1013 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -603,6 +603,69 @@ static char *kvp_if_name_to_mac(char *if_name) } +/* + * 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, *q, *x; + char *if_name = NULL; + char buf[256]; + char *kvp_net_dir = "/sys/class/net/"; + char dev_id[256]; + int i; + + dir = opendir(kvp_net_dir); + if (dir == NULL) + return NULL; + + snprintf(dev_id, sizeof(dev_id), kvp_net_dir); + q = dev_id + strlen(kvp_net_dir); + + while ((entry = readdir(dir)) != NULL) { + /* + * Set the state for the next pass. + */ + *q = '\0'; + + strcat(dev_id, entry->d_name); + strcat(dev_id, "/address"); + + 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, int len, int element_size, int offset) @@ -749,10 +812,10 @@ static int kvp_process_ip_address(void *addrp, } if ((length - *offset) < addr_length + 1) - return 1; + return HV_E_FAIL; if (str == NULL) { strcpy(buffer, "inet_ntop failed\n"); - return 1; + return HV_E_FAIL; } if (*offset == 0) strcpy(buffer, tmp); @@ -796,7 +859,7 @@ kvp_get_ip_info(int family, char *if_name, int op, if (getifaddrs(&ifap)) { strcpy(buffer, "getifaddrs failed\n"); - return 1; + return HV_E_FAIL; } curp = ifap; @@ -1386,6 +1449,30 @@ int main(void) } 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)); + + if (error) + hv_msg->error = error; + + free(if_name); + break; + case KVP_OP_SET_IP_INFO: kvp_ip_val = &hv_msg->body.kvp_ip_val; if_name = kvp_get_if_name( -- cgit v1.1 From d5ab482799e7c4c4b7c0aa67e8710dce28115d03 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 5 Sep 2012 14:37:35 -0700 Subject: tools/hv: Fix file handle leak Match up each fopen() with an fclose(). Signed-off-by: Ben Hutchings Signed-off-by: K. Y. Srinivasan Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index c8e1013..4514fb4 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -160,7 +160,7 @@ static void kvp_update_file(int pool) sizeof(struct kvp_record), kvp_file_info[pool].num_records, filep); - fflush(filep); + fclose(filep); kvp_release_lock(pool); } @@ -207,6 +207,7 @@ static void kvp_update_mem_state(int pool) kvp_file_info[pool].records = record; kvp_file_info[pool].num_records = records_read; + fclose(filep); kvp_release_lock(pool); } static int kvp_file_init(void) -- cgit v1.1 From 6bb22fea25624ab593eee376fa5fb82d1b13f45a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 5 Sep 2012 14:37:36 -0700 Subject: tools/hv: Fix exit() error code Linux native exit codes are 8-bit unsigned values. exit(-1) results in an exit code of 255, which is usually reserved for shells reporting 'command not found'. Use the portable value EXIT_FAILURE. (Not that this matters much for a daemon.) Signed-off-by: Ben Hutchings Signed-off-by: K. Y. Srinivasan Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 4514fb4..01b3ca5 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -122,7 +122,7 @@ static void kvp_acquire_lock(int pool) if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) { syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool); - exit(-1); + exit(EXIT_FAILURE); } } @@ -134,7 +134,7 @@ static void kvp_release_lock(int pool) if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) { perror("fcntl"); syslog(LOG_ERR, "Failed to release the lock pool: %d", pool); - exit(-1); + exit(EXIT_FAILURE); } } @@ -153,7 +153,7 @@ static void kvp_update_file(int pool) if (!filep) { kvp_release_lock(pool); syslog(LOG_ERR, "Failed to open file, pool: %d", pool); - exit(-1); + exit(EXIT_FAILURE); } bytes_written = fwrite(kvp_file_info[pool].records, @@ -179,7 +179,7 @@ static void kvp_update_mem_state(int pool) if (!filep) { kvp_release_lock(pool); syslog(LOG_ERR, "Failed to open file, pool: %d", pool); - exit(-1); + exit(EXIT_FAILURE); } while (!feof(filep)) { readp = &record[records_read]; @@ -196,7 +196,7 @@ static void kvp_update_mem_state(int pool) if (record == NULL) { syslog(LOG_ERR, "malloc failed"); - exit(-1); + exit(EXIT_FAILURE); } continue; } @@ -225,7 +225,7 @@ static int kvp_file_init(void) if (access("/var/opt/hyperv", F_OK)) { if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) { syslog(LOG_ERR, " Failed to create /var/opt/hyperv"); - exit(-1); + exit(EXIT_FAILURE); } } @@ -1358,13 +1358,13 @@ int main(void) if (kvp_file_init()) { syslog(LOG_ERR, "Failed to initialize the pools"); - exit(-1); + exit(EXIT_FAILURE); } fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); if (fd < 0) { syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd); - exit(-1); + exit(EXIT_FAILURE); } addr.nl_family = AF_NETLINK; addr.nl_pad = 0; @@ -1376,7 +1376,7 @@ int main(void) if (error < 0) { syslog(LOG_ERR, "bind failed; error:%d", error); close(fd); - exit(-1); + exit(EXIT_FAILURE); } sock_opt = addr.nl_groups; setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt)); @@ -1396,7 +1396,7 @@ int main(void) if (len < 0) { syslog(LOG_ERR, "netlink_send failed; error:%d", len); close(fd); - exit(-1); + exit(EXIT_FAILURE); } pfd.fd = fd; @@ -1608,7 +1608,7 @@ kvp_done: len = netlink_send(fd, incoming_cn_msg); if (len < 0) { syslog(LOG_ERR, "net_link send failed; error:%d", len); - exit(-1); + exit(EXIT_FAILURE); } } -- cgit v1.1 From 436473bc2173499ae274d0f50111d1e355006caf Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 5 Sep 2012 14:37:37 -0700 Subject: tools/hv: Check for read/write errors hv_kvp_daemon currently does not check whether fread() or fwrite() succeed. Add the necessary checks. Also, remove the incorrect use of feof() before fread(). Signed-off-by: Ben Hutchings Signed-off-by: K. Y. Srinivasan Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 01b3ca5..3922abc 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -160,7 +160,12 @@ static void kvp_update_file(int pool) sizeof(struct kvp_record), kvp_file_info[pool].num_records, filep); - fclose(filep); + if (ferror(filep) || fclose(filep)) { + kvp_release_lock(pool); + syslog(LOG_ERR, "Failed to write file, pool: %d", pool); + exit(EXIT_FAILURE); + } + kvp_release_lock(pool); } @@ -181,12 +186,17 @@ static void kvp_update_mem_state(int pool) syslog(LOG_ERR, "Failed to open file, pool: %d", pool); exit(EXIT_FAILURE); } - while (!feof(filep)) { + for (;;) { readp = &record[records_read]; records_read += fread(readp, sizeof(struct kvp_record), ENTRIES_PER_BLOCK * num_blocks, filep); + if (ferror(filep)) { + syslog(LOG_ERR, "Failed to read file, pool: %d", pool); + exit(EXIT_FAILURE); + } + if (!feof(filep)) { /* * We have more data to read. @@ -249,12 +259,18 @@ static int kvp_file_init(void) fclose(filep); return 1; } - while (!feof(filep)) { + for (;;) { readp = &record[records_read]; records_read += fread(readp, sizeof(struct kvp_record), ENTRIES_PER_BLOCK, filep); + if (ferror(filep)) { + syslog(LOG_ERR, "Failed to read file, pool: %d", + i); + exit(EXIT_FAILURE); + } + if (!feof(filep)) { /* * We have more data to read. -- cgit v1.1 From 44c8b25fb3b4b67442426abdc2371e750f7a393e Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 6 Sep 2012 13:32:14 -0700 Subject: tools/hv: Parse /etc/os-release There is a new convention, used by systemd and supported by most distributions, to put basic OS release information in /etc/os-release. Added some additional error checking on strdup() Signed-off-by: Ben Hutchings Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_kvp_daemon.c | 59 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c index 3922abc..5959aff 100644 --- a/tools/hv/hv_kvp_daemon.c +++ b/tools/hv/hv_kvp_daemon.c @@ -454,6 +454,7 @@ void kvp_get_os_info(void) uname(&uts_buf); os_build = uts_buf.release; + os_name = uts_buf.sysname; processor_arch = uts_buf.machine; /* @@ -465,20 +466,70 @@ void kvp_get_os_info(void) if (p) *p = '\0'; + /* + * Parse the /etc/os-release file if present: + * http://www.freedesktop.org/software/systemd/man/os-release.html + */ + file = fopen("/etc/os-release", "r"); + if (file != NULL) { + while (fgets(buf, sizeof(buf), file)) { + char *value, *q; + + /* Ignore comments */ + if (buf[0] == '#') + continue; + + /* Split into name=value */ + p = strchr(buf, '='); + if (!p) + continue; + *p++ = 0; + + /* Remove quotes and newline; un-escape */ + value = p; + q = p; + while (*p) { + if (*p == '\\') { + ++p; + if (!*p) + break; + *q++ = *p++; + } else if (*p == '\'' || *p == '"' || + *p == '\n') { + ++p; + } else { + *q++ = *p++; + } + } + *q = 0; + + if (!strcmp(buf, "NAME")) { + p = strdup(value); + if (!p) + break; + os_name = p; + } else if (!strcmp(buf, "VERSION_ID")) { + p = strdup(value); + if (!p) + break; + os_major = p; + } + } + fclose(file); + return; + } + + /* Fallback for older RH/SUSE releases */ file = fopen("/etc/SuSE-release", "r"); if (file != NULL) goto kvp_osinfo_found; file = fopen("/etc/redhat-release", "r"); if (file != NULL) goto kvp_osinfo_found; - /* - * Add code for other supported platforms. - */ /* * We don't have information about the os. */ - os_name = uts_buf.sysname; return; kvp_osinfo_found: -- cgit v1.1