aboutsummaryrefslogtreecommitdiffstats
path: root/tools/hv
diff options
context:
space:
mode:
Diffstat (limited to 'tools/hv')
-rwxr-xr-xtools/hv/hv_get_dhcp_info.sh28
-rwxr-xr-xtools/hv/hv_get_dns_info.sh13
-rw-r--r--tools/hv/hv_kvp_daemon.c1036
-rwxr-xr-xtools/hv/hv_set_ifconfig.sh68
4 files changed, 1033 insertions, 112 deletions
diff --git a/tools/hv/hv_get_dhcp_info.sh b/tools/hv/hv_get_dhcp_info.sh
new file mode 100755
index 00000000000..ccd3e953276
--- /dev/null
+++ b/tools/hv/hv_get_dhcp_info.sh
@@ -0,0 +1,28 @@
1#!/bin/bash
2
3# This example script retrieves the DHCP state of a given interface.
4# In the interest of keeping the KVP daemon code free of distro specific
5# information; the kvp daemon code invokes this external script to gather
6# DHCP setting for the specific interface.
7#
8# Input: Name of the interface
9#
10# Output: The script prints the string "Enabled" to stdout to indicate
11# that DHCP is enabled on the interface. If DHCP is not enabled,
12# the script prints the string "Disabled" to stdout.
13#
14# Each Distro is expected to implement this script in a distro specific
15# fashion. For instance on Distros that ship with Network Manager enabled,
16# this script can be based on the Network Manager APIs for retrieving DHCP
17# information.
18
19if_file="/etc/sysconfig/network-scripts/ifcfg-"$1
20
21dhcp=$(grep "dhcp" $if_file 2>/dev/null)
22
23if [ "$dhcp" != "" ];
24then
25echo "Enabled"
26else
27echo "Disabled"
28fi
diff --git a/tools/hv/hv_get_dns_info.sh b/tools/hv/hv_get_dns_info.sh
new file mode 100755
index 00000000000..058c17b46ff
--- /dev/null
+++ b/tools/hv/hv_get_dns_info.sh
@@ -0,0 +1,13 @@
1#!/bin/bash
2
3# This example script parses /etc/resolv.conf to retrive DNS information.
4# In the interest of keeping the KVP daemon code free of distro specific
5# information; the kvp daemon code invokes this external script to gather
6# DNS information.
7# This script is expected to print the nameserver values to stdout.
8# Each Distro is expected to implement this script in a distro specific
9# fashion. For instance on Distros that ship with Network Manager enabled,
10# this script can be based on the Network Manager APIs for retrieving DNS
11# entries.
12
13cat /etc/resolv.conf 2>/dev/null | awk '/^nameserver/ { print $2 }'
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index d9834b36294..5959affd882 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -31,6 +31,7 @@
31#include <stdlib.h> 31#include <stdlib.h>
32#include <unistd.h> 32#include <unistd.h>
33#include <string.h> 33#include <string.h>
34#include <ctype.h>
34#include <errno.h> 35#include <errno.h>
35#include <arpa/inet.h> 36#include <arpa/inet.h>
36#include <linux/connector.h> 37#include <linux/connector.h>
@@ -41,6 +42,7 @@
41#include <syslog.h> 42#include <syslog.h>
42#include <sys/stat.h> 43#include <sys/stat.h>
43#include <fcntl.h> 44#include <fcntl.h>
45#include <dirent.h>
44 46
45/* 47/*
46 * KVP protocol: The user mode component first registers with the 48 * KVP protocol: The user mode component first registers with the
@@ -68,25 +70,39 @@ enum key_index {
68 ProcessorArchitecture 70 ProcessorArchitecture
69}; 71};
70 72
73
74enum {
75 IPADDR = 0,
76 NETMASK,
77 GATEWAY,
78 DNS
79};
80
71static char kvp_send_buffer[4096]; 81static char kvp_send_buffer[4096];
72static char kvp_recv_buffer[4096]; 82static char kvp_recv_buffer[4096 * 2];
73static struct sockaddr_nl addr; 83static struct sockaddr_nl addr;
84static int in_hand_shake = 1;
74 85
75static char *os_name = ""; 86static char *os_name = "";
76static char *os_major = ""; 87static char *os_major = "";
77static char *os_minor = ""; 88static char *os_minor = "";
78static char *processor_arch; 89static char *processor_arch;
79static char *os_build; 90static char *os_build;
80static char *lic_version; 91static char *lic_version = "Unknown version";
81static struct utsname uts_buf; 92static struct utsname uts_buf;
82 93
94/*
95 * The location of the interface configuration file.
96 */
97
98#define KVP_CONFIG_LOC "/var/opt/"
83 99
84#define MAX_FILE_NAME 100 100#define MAX_FILE_NAME 100
85#define ENTRIES_PER_BLOCK 50 101#define ENTRIES_PER_BLOCK 50
86 102
87struct kvp_record { 103struct kvp_record {
88 __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; 104 char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
89 __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE]; 105 char value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
90}; 106};
91 107
92struct kvp_file_state { 108struct kvp_file_state {
@@ -94,7 +110,7 @@ struct kvp_file_state {
94 int num_blocks; 110 int num_blocks;
95 struct kvp_record *records; 111 struct kvp_record *records;
96 int num_records; 112 int num_records;
97 __u8 fname[MAX_FILE_NAME]; 113 char fname[MAX_FILE_NAME];
98}; 114};
99 115
100static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT]; 116static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
@@ -106,7 +122,7 @@ static void kvp_acquire_lock(int pool)
106 122
107 if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) { 123 if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
108 syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool); 124 syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
109 exit(-1); 125 exit(EXIT_FAILURE);
110 } 126 }
111} 127}
112 128
@@ -118,7 +134,7 @@ static void kvp_release_lock(int pool)
118 if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) { 134 if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
119 perror("fcntl"); 135 perror("fcntl");
120 syslog(LOG_ERR, "Failed to release the lock pool: %d", pool); 136 syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
121 exit(-1); 137 exit(EXIT_FAILURE);
122 } 138 }
123} 139}
124 140
@@ -137,14 +153,19 @@ static void kvp_update_file(int pool)
137 if (!filep) { 153 if (!filep) {
138 kvp_release_lock(pool); 154 kvp_release_lock(pool);
139 syslog(LOG_ERR, "Failed to open file, pool: %d", pool); 155 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
140 exit(-1); 156 exit(EXIT_FAILURE);
141 } 157 }
142 158
143 bytes_written = fwrite(kvp_file_info[pool].records, 159 bytes_written = fwrite(kvp_file_info[pool].records,
144 sizeof(struct kvp_record), 160 sizeof(struct kvp_record),
145 kvp_file_info[pool].num_records, filep); 161 kvp_file_info[pool].num_records, filep);
146 162
147 fflush(filep); 163 if (ferror(filep) || fclose(filep)) {
164 kvp_release_lock(pool);
165 syslog(LOG_ERR, "Failed to write file, pool: %d", pool);
166 exit(EXIT_FAILURE);
167 }
168
148 kvp_release_lock(pool); 169 kvp_release_lock(pool);
149} 170}
150 171
@@ -163,14 +184,19 @@ static void kvp_update_mem_state(int pool)
163 if (!filep) { 184 if (!filep) {
164 kvp_release_lock(pool); 185 kvp_release_lock(pool);
165 syslog(LOG_ERR, "Failed to open file, pool: %d", pool); 186 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
166 exit(-1); 187 exit(EXIT_FAILURE);
167 } 188 }
168 while (!feof(filep)) { 189 for (;;) {
169 readp = &record[records_read]; 190 readp = &record[records_read];
170 records_read += fread(readp, sizeof(struct kvp_record), 191 records_read += fread(readp, sizeof(struct kvp_record),
171 ENTRIES_PER_BLOCK * num_blocks, 192 ENTRIES_PER_BLOCK * num_blocks,
172 filep); 193 filep);
173 194
195 if (ferror(filep)) {
196 syslog(LOG_ERR, "Failed to read file, pool: %d", pool);
197 exit(EXIT_FAILURE);
198 }
199
174 if (!feof(filep)) { 200 if (!feof(filep)) {
175 /* 201 /*
176 * We have more data to read. 202 * We have more data to read.
@@ -180,7 +206,7 @@ static void kvp_update_mem_state(int pool)
180 206
181 if (record == NULL) { 207 if (record == NULL) {
182 syslog(LOG_ERR, "malloc failed"); 208 syslog(LOG_ERR, "malloc failed");
183 exit(-1); 209 exit(EXIT_FAILURE);
184 } 210 }
185 continue; 211 continue;
186 } 212 }
@@ -191,14 +217,15 @@ static void kvp_update_mem_state(int pool)
191 kvp_file_info[pool].records = record; 217 kvp_file_info[pool].records = record;
192 kvp_file_info[pool].num_records = records_read; 218 kvp_file_info[pool].num_records = records_read;
193 219
220 fclose(filep);
194 kvp_release_lock(pool); 221 kvp_release_lock(pool);
195} 222}
196static int kvp_file_init(void) 223static int kvp_file_init(void)
197{ 224{
198 int ret, fd; 225 int fd;
199 FILE *filep; 226 FILE *filep;
200 size_t records_read; 227 size_t records_read;
201 __u8 *fname; 228 char *fname;
202 struct kvp_record *record; 229 struct kvp_record *record;
203 struct kvp_record *readp; 230 struct kvp_record *readp;
204 int num_blocks; 231 int num_blocks;
@@ -208,7 +235,7 @@ static int kvp_file_init(void)
208 if (access("/var/opt/hyperv", F_OK)) { 235 if (access("/var/opt/hyperv", F_OK)) {
209 if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) { 236 if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
210 syslog(LOG_ERR, " Failed to create /var/opt/hyperv"); 237 syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
211 exit(-1); 238 exit(EXIT_FAILURE);
212 } 239 }
213 } 240 }
214 241
@@ -232,12 +259,18 @@ static int kvp_file_init(void)
232 fclose(filep); 259 fclose(filep);
233 return 1; 260 return 1;
234 } 261 }
235 while (!feof(filep)) { 262 for (;;) {
236 readp = &record[records_read]; 263 readp = &record[records_read];
237 records_read += fread(readp, sizeof(struct kvp_record), 264 records_read += fread(readp, sizeof(struct kvp_record),
238 ENTRIES_PER_BLOCK, 265 ENTRIES_PER_BLOCK,
239 filep); 266 filep);
240 267
268 if (ferror(filep)) {
269 syslog(LOG_ERR, "Failed to read file, pool: %d",
270 i);
271 exit(EXIT_FAILURE);
272 }
273
241 if (!feof(filep)) { 274 if (!feof(filep)) {
242 /* 275 /*
243 * We have more data to read. 276 * We have more data to read.
@@ -311,7 +344,6 @@ static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
311 int value_size) 344 int value_size)
312{ 345{
313 int i; 346 int i;
314 int j, k;
315 int num_records; 347 int num_records;
316 struct kvp_record *record; 348 struct kvp_record *record;
317 int num_blocks; 349 int num_blocks;
@@ -394,7 +426,7 @@ static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
394 return 1; 426 return 1;
395} 427}
396 428
397static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, 429static int kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
398 __u8 *value, int value_size) 430 __u8 *value, int value_size)
399{ 431{
400 struct kvp_record *record; 432 struct kvp_record *record;
@@ -406,16 +438,12 @@ static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
406 record = kvp_file_info[pool].records; 438 record = kvp_file_info[pool].records;
407 439
408 if (index >= kvp_file_info[pool].num_records) { 440 if (index >= kvp_file_info[pool].num_records) {
409 /* 441 return 1;
410 * This is an invalid index; terminate enumeration;
411 * - a NULL value will do the trick.
412 */
413 strcpy(value, "");
414 return;
415 } 442 }
416 443
417 memcpy(key, record[index].key, key_size); 444 memcpy(key, record[index].key, key_size);
418 memcpy(value, record[index].value, value_size); 445 memcpy(value, record[index].value, value_size);
446 return 0;
419} 447}
420 448
421 449
@@ -426,6 +454,7 @@ void kvp_get_os_info(void)
426 454
427 uname(&uts_buf); 455 uname(&uts_buf);
428 os_build = uts_buf.release; 456 os_build = uts_buf.release;
457 os_name = uts_buf.sysname;
429 processor_arch = uts_buf.machine; 458 processor_arch = uts_buf.machine;
430 459
431 /* 460 /*
@@ -437,20 +466,70 @@ void kvp_get_os_info(void)
437 if (p) 466 if (p)
438 *p = '\0'; 467 *p = '\0';
439 468
469 /*
470 * Parse the /etc/os-release file if present:
471 * http://www.freedesktop.org/software/systemd/man/os-release.html
472 */
473 file = fopen("/etc/os-release", "r");
474 if (file != NULL) {
475 while (fgets(buf, sizeof(buf), file)) {
476 char *value, *q;
477
478 /* Ignore comments */
479 if (buf[0] == '#')
480 continue;
481
482 /* Split into name=value */
483 p = strchr(buf, '=');
484 if (!p)
485 continue;
486 *p++ = 0;
487
488 /* Remove quotes and newline; un-escape */
489 value = p;
490 q = p;
491 while (*p) {
492 if (*p == '\\') {
493 ++p;
494 if (!*p)
495 break;
496 *q++ = *p++;
497 } else if (*p == '\'' || *p == '"' ||
498 *p == '\n') {
499 ++p;
500 } else {
501 *q++ = *p++;
502 }
503 }
504 *q = 0;
505
506 if (!strcmp(buf, "NAME")) {
507 p = strdup(value);
508 if (!p)
509 break;
510 os_name = p;
511 } else if (!strcmp(buf, "VERSION_ID")) {
512 p = strdup(value);
513 if (!p)
514 break;
515 os_major = p;
516 }
517 }
518 fclose(file);
519 return;
520 }
521
522 /* Fallback for older RH/SUSE releases */
440 file = fopen("/etc/SuSE-release", "r"); 523 file = fopen("/etc/SuSE-release", "r");
441 if (file != NULL) 524 if (file != NULL)
442 goto kvp_osinfo_found; 525 goto kvp_osinfo_found;
443 file = fopen("/etc/redhat-release", "r"); 526 file = fopen("/etc/redhat-release", "r");
444 if (file != NULL) 527 if (file != NULL)
445 goto kvp_osinfo_found; 528 goto kvp_osinfo_found;
446 /*
447 * Add code for other supported platforms.
448 */
449 529
450 /* 530 /*
451 * We don't have information about the os. 531 * We don't have information about the os.
452 */ 532 */
453 os_name = uts_buf.sysname;
454 return; 533 return;
455 534
456kvp_osinfo_found: 535kvp_osinfo_found:
@@ -494,82 +573,458 @@ done:
494 return; 573 return;
495} 574}
496 575
576
577
578/*
579 * Retrieve an interface name corresponding to the specified guid.
580 * If there is a match, the function returns a pointer
581 * to the interface name and if not, a NULL is returned.
582 * If a match is found, the caller is responsible for
583 * freeing the memory.
584 */
585
586static char *kvp_get_if_name(char *guid)
587{
588 DIR *dir;
589 struct dirent *entry;
590 FILE *file;
591 char *p, *q, *x;
592 char *if_name = NULL;
593 char buf[256];
594 char *kvp_net_dir = "/sys/class/net/";
595 char dev_id[256];
596
597 dir = opendir(kvp_net_dir);
598 if (dir == NULL)
599 return NULL;
600
601 snprintf(dev_id, sizeof(dev_id), "%s", kvp_net_dir);
602 q = dev_id + strlen(kvp_net_dir);
603
604 while ((entry = readdir(dir)) != NULL) {
605 /*
606 * Set the state for the next pass.
607 */
608 *q = '\0';
609 strcat(dev_id, entry->d_name);
610 strcat(dev_id, "/device/device_id");
611
612 file = fopen(dev_id, "r");
613 if (file == NULL)
614 continue;
615
616 p = fgets(buf, sizeof(buf), file);
617 if (p) {
618 x = strchr(p, '\n');
619 if (x)
620 *x = '\0';
621
622 if (!strcmp(p, guid)) {
623 /*
624 * Found the guid match; return the interface
625 * name. The caller will free the memory.
626 */
627 if_name = strdup(entry->d_name);
628 fclose(file);
629 break;
630 }
631 }
632 fclose(file);
633 }
634
635 closedir(dir);
636 return if_name;
637}
638
639/*
640 * Retrieve the MAC address given the interface name.
641 */
642
643static char *kvp_if_name_to_mac(char *if_name)
644{
645 FILE *file;
646 char *p, *x;
647 char buf[256];
648 char addr_file[256];
649 int i;
650 char *mac_addr = NULL;
651
652 snprintf(addr_file, sizeof(addr_file), "%s%s%s", "/sys/class/net/",
653 if_name, "/address");
654
655 file = fopen(addr_file, "r");
656 if (file == NULL)
657 return NULL;
658
659 p = fgets(buf, sizeof(buf), file);
660 if (p) {
661 x = strchr(p, '\n');
662 if (x)
663 *x = '\0';
664 for (i = 0; i < strlen(p); i++)
665 p[i] = toupper(p[i]);
666 mac_addr = strdup(p);
667 }
668
669 fclose(file);
670 return mac_addr;
671}
672
673
674/*
675 * Retrieve the interface name given tha MAC address.
676 */
677
678static char *kvp_mac_to_if_name(char *mac)
679{
680 DIR *dir;
681 struct dirent *entry;
682 FILE *file;
683 char *p, *q, *x;
684 char *if_name = NULL;
685 char buf[256];
686 char *kvp_net_dir = "/sys/class/net/";
687 char dev_id[256];
688 int i;
689
690 dir = opendir(kvp_net_dir);
691 if (dir == NULL)
692 return NULL;
693
694 snprintf(dev_id, sizeof(dev_id), kvp_net_dir);
695 q = dev_id + strlen(kvp_net_dir);
696
697 while ((entry = readdir(dir)) != NULL) {
698 /*
699 * Set the state for the next pass.
700 */
701 *q = '\0';
702
703 strcat(dev_id, entry->d_name);
704 strcat(dev_id, "/address");
705
706 file = fopen(dev_id, "r");
707 if (file == NULL)
708 continue;
709
710 p = fgets(buf, sizeof(buf), file);
711 if (p) {
712 x = strchr(p, '\n');
713 if (x)
714 *x = '\0';
715
716 for (i = 0; i < strlen(p); i++)
717 p[i] = toupper(p[i]);
718
719 if (!strcmp(p, mac)) {
720 /*
721 * Found the MAC match; return the interface
722 * name. The caller will free the memory.
723 */
724 if_name = strdup(entry->d_name);
725 fclose(file);
726 break;
727 }
728 }
729 fclose(file);
730 }
731
732 closedir(dir);
733 return if_name;
734}
735
736
737static void kvp_process_ipconfig_file(char *cmd,
738 char *config_buf, int len,
739 int element_size, int offset)
740{
741 char buf[256];
742 char *p;
743 char *x;
744 FILE *file;
745
746 /*
747 * First execute the command.
748 */
749 file = popen(cmd, "r");
750 if (file == NULL)
751 return;
752
753 if (offset == 0)
754 memset(config_buf, 0, len);
755 while ((p = fgets(buf, sizeof(buf), file)) != NULL) {
756 if ((len - strlen(config_buf)) < (element_size + 1))
757 break;
758
759 x = strchr(p, '\n');
760 *x = '\0';
761 strcat(config_buf, p);
762 strcat(config_buf, ";");
763 }
764 pclose(file);
765}
766
767static void kvp_get_ipconfig_info(char *if_name,
768 struct hv_kvp_ipaddr_value *buffer)
769{
770 char cmd[512];
771 char dhcp_info[128];
772 char *p;
773 FILE *file;
774
775 /*
776 * Get the address of default gateway (ipv4).
777 */
778 sprintf(cmd, "%s %s", "ip route show dev", if_name);
779 strcat(cmd, " | awk '/default/ {print $3 }'");
780
781 /*
782 * Execute the command to gather gateway info.
783 */
784 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
785 (MAX_GATEWAY_SIZE * 2), INET_ADDRSTRLEN, 0);
786
787 /*
788 * Get the address of default gateway (ipv6).
789 */
790 sprintf(cmd, "%s %s", "ip -f inet6 route show dev", if_name);
791 strcat(cmd, " | awk '/default/ {print $3 }'");
792
793 /*
794 * Execute the command to gather gateway info (ipv6).
795 */
796 kvp_process_ipconfig_file(cmd, (char *)buffer->gate_way,
797 (MAX_GATEWAY_SIZE * 2), INET6_ADDRSTRLEN, 1);
798
799
800 /*
801 * Gather the DNS state.
802 * Since there is no standard way to get this information
803 * across various distributions of interest; we just invoke
804 * an external script that needs to be ported across distros
805 * of interest.
806 *
807 * Following is the expected format of the information from the script:
808 *
809 * ipaddr1 (nameserver1)
810 * ipaddr2 (nameserver2)
811 * .
812 * .
813 */
814
815 sprintf(cmd, "%s", "hv_get_dns_info");
816
817 /*
818 * Execute the command to gather DNS info.
819 */
820 kvp_process_ipconfig_file(cmd, (char *)buffer->dns_addr,
821 (MAX_IP_ADDR_SIZE * 2), INET_ADDRSTRLEN, 0);
822
823 /*
824 * Gather the DHCP state.
825 * We will gather this state by invoking an external script.
826 * The parameter to the script is the interface name.
827 * Here is the expected output:
828 *
829 * Enabled: DHCP enabled.
830 */
831
832 sprintf(cmd, "%s %s", "hv_get_dhcp_info", if_name);
833
834 file = popen(cmd, "r");
835 if (file == NULL)
836 return;
837
838 p = fgets(dhcp_info, sizeof(dhcp_info), file);
839 if (p == NULL) {
840 pclose(file);
841 return;
842 }
843
844 if (!strncmp(p, "Enabled", 7))
845 buffer->dhcp_enabled = 1;
846 else
847 buffer->dhcp_enabled = 0;
848
849 pclose(file);
850}
851
852
853static unsigned int hweight32(unsigned int *w)
854{
855 unsigned int res = *w - ((*w >> 1) & 0x55555555);
856 res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
857 res = (res + (res >> 4)) & 0x0F0F0F0F;
858 res = res + (res >> 8);
859 return (res + (res >> 16)) & 0x000000FF;
860}
861
862static int kvp_process_ip_address(void *addrp,
863 int family, char *buffer,
864 int length, int *offset)
865{
866 struct sockaddr_in *addr;
867 struct sockaddr_in6 *addr6;
868 int addr_length;
869 char tmp[50];
870 const char *str;
871
872 if (family == AF_INET) {
873 addr = (struct sockaddr_in *)addrp;
874 str = inet_ntop(family, &addr->sin_addr, tmp, 50);
875 addr_length = INET_ADDRSTRLEN;
876 } else {
877 addr6 = (struct sockaddr_in6 *)addrp;
878 str = inet_ntop(family, &addr6->sin6_addr.s6_addr, tmp, 50);
879 addr_length = INET6_ADDRSTRLEN;
880 }
881
882 if ((length - *offset) < addr_length + 1)
883 return HV_E_FAIL;
884 if (str == NULL) {
885 strcpy(buffer, "inet_ntop failed\n");
886 return HV_E_FAIL;
887 }
888 if (*offset == 0)
889 strcpy(buffer, tmp);
890 else
891 strcat(buffer, tmp);
892 strcat(buffer, ";");
893
894 *offset += strlen(str) + 1;
895 return 0;
896}
897
497static int 898static int
498kvp_get_ip_address(int family, char *buffer, int length) 899kvp_get_ip_info(int family, char *if_name, int op,
900 void *out_buffer, int length)
499{ 901{
500 struct ifaddrs *ifap; 902 struct ifaddrs *ifap;
501 struct ifaddrs *curp; 903 struct ifaddrs *curp;
502 int ipv4_len = strlen("255.255.255.255") + 1;
503 int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1;
504 int offset = 0; 904 int offset = 0;
505 const char *str; 905 int sn_offset = 0;
506 char tmp[50];
507 int error = 0; 906 int error = 0;
508 907 char *buffer;
908 struct hv_kvp_ipaddr_value *ip_buffer;
909 char cidr_mask[5]; /* /xyz */
910 int weight;
911 int i;
912 unsigned int *w;
913 char *sn_str;
914 struct sockaddr_in6 *addr6;
915
916 if (op == KVP_OP_ENUMERATE) {
917 buffer = out_buffer;
918 } else {
919 ip_buffer = out_buffer;
920 buffer = (char *)ip_buffer->ip_addr;
921 ip_buffer->addr_family = 0;
922 }
509 /* 923 /*
510 * On entry into this function, the buffer is capable of holding the 924 * On entry into this function, the buffer is capable of holding the
511 * maximum key value (2048 bytes). 925 * maximum key value.
512 */ 926 */
513 927
514 if (getifaddrs(&ifap)) { 928 if (getifaddrs(&ifap)) {
515 strcpy(buffer, "getifaddrs failed\n"); 929 strcpy(buffer, "getifaddrs failed\n");
516 return 1; 930 return HV_E_FAIL;
517 } 931 }
518 932
519 curp = ifap; 933 curp = ifap;
520 while (curp != NULL) { 934 while (curp != NULL) {
521 if ((curp->ifa_addr != NULL) && 935 if (curp->ifa_addr == NULL) {
522 (curp->ifa_addr->sa_family == family)) { 936 curp = curp->ifa_next;
523 if (family == AF_INET) { 937 continue;
524 struct sockaddr_in *addr = 938 }
525 (struct sockaddr_in *) curp->ifa_addr;
526
527 str = inet_ntop(family, &addr->sin_addr,
528 tmp, 50);
529 if (str == NULL) {
530 strcpy(buffer, "inet_ntop failed\n");
531 error = 1;
532 goto getaddr_done;
533 }
534 if (offset == 0)
535 strcpy(buffer, tmp);
536 else
537 strcat(buffer, tmp);
538 strcat(buffer, ";");
539 939
540 offset += strlen(str) + 1; 940 if ((if_name != NULL) &&
541 if ((length - offset) < (ipv4_len + 1)) 941 (strncmp(curp->ifa_name, if_name, strlen(if_name)))) {
542 goto getaddr_done; 942 /*
943 * We want info about a specific interface;
944 * just continue.
945 */
946 curp = curp->ifa_next;
947 continue;
948 }
543 949
544 } else { 950 /*
951 * We only support two address families: AF_INET and AF_INET6.
952 * If a family value of 0 is specified, we collect both
953 * supported address families; if not we gather info on
954 * the specified address family.
955 */
956 if ((family != 0) && (curp->ifa_addr->sa_family != family)) {
957 curp = curp->ifa_next;
958 continue;
959 }
960 if ((curp->ifa_addr->sa_family != AF_INET) &&
961 (curp->ifa_addr->sa_family != AF_INET6)) {
962 curp = curp->ifa_next;
963 continue;
964 }
545 965
966 if (op == KVP_OP_GET_IP_INFO) {
546 /* 967 /*
547 * We only support AF_INET and AF_INET6 968 * Gather info other than the IP address.
548 * and the list of addresses is separated by a ";". 969 * IP address info will be gathered later.
549 */ 970 */
550 struct sockaddr_in6 *addr = 971 if (curp->ifa_addr->sa_family == AF_INET) {
551 (struct sockaddr_in6 *) curp->ifa_addr; 972 ip_buffer->addr_family |= ADDR_FAMILY_IPV4;
552 973 /*
553 str = inet_ntop(family, 974 * Get subnet info.
554 &addr->sin6_addr.s6_addr, 975 */
555 tmp, 50); 976 error = kvp_process_ip_address(
556 if (str == NULL) { 977 curp->ifa_netmask,
557 strcpy(buffer, "inet_ntop failed\n"); 978 AF_INET,
558 error = 1; 979 (char *)
559 goto getaddr_done; 980 ip_buffer->sub_net,
560 } 981 length,
561 if (offset == 0) 982 &sn_offset);
562 strcpy(buffer, tmp); 983 if (error)
563 else 984 goto gather_ipaddr;
564 strcat(buffer, tmp); 985 } else {
565 strcat(buffer, ";"); 986 ip_buffer->addr_family |= ADDR_FAMILY_IPV6;
566 offset += strlen(str) + 1;
567 if ((length - offset) < (ipv6_len + 1))
568 goto getaddr_done;
569 987
988 /*
989 * Get subnet info in CIDR format.
990 */
991 weight = 0;
992 sn_str = (char *)ip_buffer->sub_net;
993 addr6 = (struct sockaddr_in6 *)
994 curp->ifa_netmask;
995 w = addr6->sin6_addr.s6_addr32;
996
997 for (i = 0; i < 4; i++)
998 weight += hweight32(&w[i]);
999
1000 sprintf(cidr_mask, "/%d", weight);
1001 if ((length - sn_offset) <
1002 (strlen(cidr_mask) + 1))
1003 goto gather_ipaddr;
1004
1005 if (sn_offset == 0)
1006 strcpy(sn_str, cidr_mask);
1007 else
1008 strcat(sn_str, cidr_mask);
1009 strcat((char *)ip_buffer->sub_net, ";");
1010 sn_offset += strlen(sn_str) + 1;
570 } 1011 }
571 1012
1013 /*
1014 * Collect other ip related configuration info.
1015 */
1016
1017 kvp_get_ipconfig_info(if_name, ip_buffer);
572 } 1018 }
1019
1020gather_ipaddr:
1021 error = kvp_process_ip_address(curp->ifa_addr,
1022 curp->ifa_addr->sa_family,
1023 buffer,
1024 length, &offset);
1025 if (error)
1026 goto getaddr_done;
1027
573 curp = curp->ifa_next; 1028 curp = curp->ifa_next;
574 } 1029 }
575 1030
@@ -579,6 +1034,315 @@ getaddr_done:
579} 1034}
580 1035
581 1036
1037static int expand_ipv6(char *addr, int type)
1038{
1039 int ret;
1040 struct in6_addr v6_addr;
1041
1042 ret = inet_pton(AF_INET6, addr, &v6_addr);
1043
1044 if (ret != 1) {
1045 if (type == NETMASK)
1046 return 1;
1047 return 0;
1048 }
1049
1050 sprintf(addr, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
1051 "%02x%02x:%02x%02x:%02x%02x",
1052 (int)v6_addr.s6_addr[0], (int)v6_addr.s6_addr[1],
1053 (int)v6_addr.s6_addr[2], (int)v6_addr.s6_addr[3],
1054 (int)v6_addr.s6_addr[4], (int)v6_addr.s6_addr[5],
1055 (int)v6_addr.s6_addr[6], (int)v6_addr.s6_addr[7],
1056 (int)v6_addr.s6_addr[8], (int)v6_addr.s6_addr[9],
1057 (int)v6_addr.s6_addr[10], (int)v6_addr.s6_addr[11],
1058 (int)v6_addr.s6_addr[12], (int)v6_addr.s6_addr[13],
1059 (int)v6_addr.s6_addr[14], (int)v6_addr.s6_addr[15]);
1060
1061 return 1;
1062
1063}
1064
1065static int is_ipv4(char *addr)
1066{
1067 int ret;
1068 struct in_addr ipv4_addr;
1069
1070 ret = inet_pton(AF_INET, addr, &ipv4_addr);
1071
1072 if (ret == 1)
1073 return 1;
1074 return 0;
1075}
1076
1077static int parse_ip_val_buffer(char *in_buf, int *offset,
1078 char *out_buf, int out_len)
1079{
1080 char *x;
1081 char *start;
1082
1083 /*
1084 * in_buf has sequence of characters that are seperated by
1085 * the character ';'. The last sequence does not have the
1086 * terminating ";" character.
1087 */
1088 start = in_buf + *offset;
1089
1090 x = strchr(start, ';');
1091 if (x)
1092 *x = 0;
1093 else
1094 x = start + strlen(start);
1095
1096 if (strlen(start) != 0) {
1097 int i = 0;
1098 /*
1099 * Get rid of leading spaces.
1100 */
1101 while (start[i] == ' ')
1102 i++;
1103
1104 if ((x - start) <= out_len) {
1105 strcpy(out_buf, (start + i));
1106 *offset += (x - start) + 1;
1107 return 1;
1108 }
1109 }
1110 return 0;
1111}
1112
1113static int kvp_write_file(FILE *f, char *s1, char *s2, char *s3)
1114{
1115 int ret;
1116
1117 ret = fprintf(f, "%s%s%s%s\n", s1, s2, "=", s3);
1118
1119 if (ret < 0)
1120 return HV_E_FAIL;
1121
1122 return 0;
1123}
1124
1125
1126static int process_ip_string(FILE *f, char *ip_string, int type)
1127{
1128 int error = 0;
1129 char addr[INET6_ADDRSTRLEN];
1130 int i = 0;
1131 int j = 0;
1132 char str[256];
1133 char sub_str[10];
1134 int offset = 0;
1135
1136 memset(addr, 0, sizeof(addr));
1137
1138 while (parse_ip_val_buffer(ip_string, &offset, addr,
1139 (MAX_IP_ADDR_SIZE * 2))) {
1140
1141 sub_str[0] = 0;
1142 if (is_ipv4(addr)) {
1143 switch (type) {
1144 case IPADDR:
1145 snprintf(str, sizeof(str), "%s", "IPADDR");
1146 break;
1147 case NETMASK:
1148 snprintf(str, sizeof(str), "%s", "NETMASK");
1149 break;
1150 case GATEWAY:
1151 snprintf(str, sizeof(str), "%s", "GATEWAY");
1152 break;
1153 case DNS:
1154 snprintf(str, sizeof(str), "%s", "DNS");
1155 break;
1156 }
1157 if (i != 0) {
1158 if (type != DNS) {
1159 snprintf(sub_str, sizeof(sub_str),
1160 "_%d", i++);
1161 } else {
1162 snprintf(sub_str, sizeof(sub_str),
1163 "%d", ++i);
1164 }
1165 } else if (type == DNS) {
1166 snprintf(sub_str, sizeof(sub_str), "%d", ++i);
1167 }
1168
1169
1170 } else if (expand_ipv6(addr, type)) {
1171 switch (type) {
1172 case IPADDR:
1173 snprintf(str, sizeof(str), "%s", "IPV6ADDR");
1174 break;
1175 case NETMASK:
1176 snprintf(str, sizeof(str), "%s", "IPV6NETMASK");
1177 break;
1178 case GATEWAY:
1179 snprintf(str, sizeof(str), "%s",
1180 "IPV6_DEFAULTGW");
1181 break;
1182 case DNS:
1183 snprintf(str, sizeof(str), "%s", "DNS");
1184 break;
1185 }
1186 if ((j != 0) || (type == DNS)) {
1187 if (type != DNS) {
1188 snprintf(sub_str, sizeof(sub_str),
1189 "_%d", j++);
1190 } else {
1191 snprintf(sub_str, sizeof(sub_str),
1192 "%d", ++i);
1193 }
1194 } else if (type == DNS) {
1195 snprintf(sub_str, sizeof(sub_str),
1196 "%d", ++i);
1197 }
1198 } else {
1199 return HV_INVALIDARG;
1200 }
1201
1202 error = kvp_write_file(f, str, sub_str, addr);
1203 if (error)
1204 return error;
1205 memset(addr, 0, sizeof(addr));
1206 }
1207
1208 return 0;
1209}
1210
1211static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
1212{
1213 int error = 0;
1214 char if_file[128];
1215 FILE *file;
1216 char cmd[512];
1217 char *mac_addr;
1218
1219 /*
1220 * Set the configuration for the specified interface with
1221 * the information provided. Since there is no standard
1222 * way to configure an interface, we will have an external
1223 * script that does the job of configuring the interface and
1224 * flushing the configuration.
1225 *
1226 * The parameters passed to this external script are:
1227 * 1. A configuration file that has the specified configuration.
1228 *
1229 * We will embed the name of the interface in the configuration
1230 * file: ifcfg-ethx (where ethx is the interface name).
1231 *
1232 * The information provided here may be more than what is needed
1233 * in a given distro to configure the interface and so are free
1234 * ignore information that may not be relevant.
1235 *
1236 * Here is the format of the ip configuration file:
1237 *
1238 * HWADDR=macaddr
1239 * IF_NAME=interface name
1240 * DHCP=yes (This is optional; if yes, DHCP is configured)
1241 *
1242 * IPADDR=ipaddr1
1243 * IPADDR_1=ipaddr2
1244 * IPADDR_x=ipaddry (where y = x + 1)
1245 *
1246 * NETMASK=netmask1
1247 * NETMASK_x=netmasky (where y = x + 1)
1248 *
1249 * GATEWAY=ipaddr1
1250 * GATEWAY_x=ipaddry (where y = x + 1)
1251 *
1252 * DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
1253 *
1254 * IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
1255 * tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
1256 * IPV6NETMASK.
1257 *
1258 * The host can specify multiple ipv4 and ipv6 addresses to be
1259 * configured for the interface. Furthermore, the configuration
1260 * needs to be persistent. A subsequent GET call on the interface
1261 * is expected to return the configuration that is set via the SET
1262 * call.
1263 */
1264
1265 snprintf(if_file, sizeof(if_file), "%s%s%s", KVP_CONFIG_LOC,
1266 "hyperv/ifcfg-", if_name);
1267
1268 file = fopen(if_file, "w");
1269
1270 if (file == NULL) {
1271 syslog(LOG_ERR, "Failed to open config file");
1272 return HV_E_FAIL;
1273 }
1274
1275 /*
1276 * First write out the MAC address.
1277 */
1278
1279 mac_addr = kvp_if_name_to_mac(if_name);
1280 if (mac_addr == NULL) {
1281 error = HV_E_FAIL;
1282 goto setval_error;
1283 }
1284
1285 error = kvp_write_file(file, "HWADDR", "", mac_addr);
1286 if (error)
1287 goto setval_error;
1288
1289 error = kvp_write_file(file, "IF_NAME", "", if_name);
1290 if (error)
1291 goto setval_error;
1292
1293 if (new_val->dhcp_enabled) {
1294 error = kvp_write_file(file, "DHCP", "", "yes");
1295 if (error)
1296 goto setval_error;
1297
1298 /*
1299 * We are done!.
1300 */
1301 goto setval_done;
1302 }
1303
1304 /*
1305 * Write the configuration for ipaddress, netmask, gateway and
1306 * name servers.
1307 */
1308
1309 error = process_ip_string(file, (char *)new_val->ip_addr, IPADDR);
1310 if (error)
1311 goto setval_error;
1312
1313 error = process_ip_string(file, (char *)new_val->sub_net, NETMASK);
1314 if (error)
1315 goto setval_error;
1316
1317 error = process_ip_string(file, (char *)new_val->gate_way, GATEWAY);
1318 if (error)
1319 goto setval_error;
1320
1321 error = process_ip_string(file, (char *)new_val->dns_addr, DNS);
1322 if (error)
1323 goto setval_error;
1324
1325setval_done:
1326 free(mac_addr);
1327 fclose(file);
1328
1329 /*
1330 * Now that we have populated the configuration file,
1331 * invoke the external script to do its magic.
1332 */
1333
1334 snprintf(cmd, sizeof(cmd), "%s %s", "hv_set_ifconfig", if_file);
1335 system(cmd);
1336 return 0;
1337
1338setval_error:
1339 syslog(LOG_ERR, "Failed to write config file");
1340 free(mac_addr);
1341 fclose(file);
1342 return error;
1343}
1344
1345
582static int 1346static int
583kvp_get_domain_name(char *buffer, int length) 1347kvp_get_domain_name(char *buffer, int length)
584{ 1348{
@@ -646,6 +1410,10 @@ int main(void)
646 char *p; 1410 char *p;
647 char *key_value; 1411 char *key_value;
648 char *key_name; 1412 char *key_name;
1413 int op;
1414 int pool;
1415 char *if_name;
1416 struct hv_kvp_ipaddr_value *kvp_ip_val;
649 1417
650 daemon(1, 0); 1418 daemon(1, 0);
651 openlog("KVP", 0, LOG_USER); 1419 openlog("KVP", 0, LOG_USER);
@@ -657,13 +1425,13 @@ int main(void)
657 1425
658 if (kvp_file_init()) { 1426 if (kvp_file_init()) {
659 syslog(LOG_ERR, "Failed to initialize the pools"); 1427 syslog(LOG_ERR, "Failed to initialize the pools");
660 exit(-1); 1428 exit(EXIT_FAILURE);
661 } 1429 }
662 1430
663 fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); 1431 fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
664 if (fd < 0) { 1432 if (fd < 0) {
665 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd); 1433 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
666 exit(-1); 1434 exit(EXIT_FAILURE);
667 } 1435 }
668 addr.nl_family = AF_NETLINK; 1436 addr.nl_family = AF_NETLINK;
669 addr.nl_pad = 0; 1437 addr.nl_pad = 0;
@@ -675,7 +1443,7 @@ int main(void)
675 if (error < 0) { 1443 if (error < 0) {
676 syslog(LOG_ERR, "bind failed; error:%d", error); 1444 syslog(LOG_ERR, "bind failed; error:%d", error);
677 close(fd); 1445 close(fd);
678 exit(-1); 1446 exit(EXIT_FAILURE);
679 } 1447 }
680 sock_opt = addr.nl_groups; 1448 sock_opt = addr.nl_groups;
681 setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt)); 1449 setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
@@ -687,7 +1455,7 @@ int main(void)
687 message->id.val = CN_KVP_VAL; 1455 message->id.val = CN_KVP_VAL;
688 1456
689 hv_msg = (struct hv_kvp_msg *)message->data; 1457 hv_msg = (struct hv_kvp_msg *)message->data;
690 hv_msg->kvp_hdr.operation = KVP_OP_REGISTER; 1458 hv_msg->kvp_hdr.operation = KVP_OP_REGISTER1;
691 message->ack = 0; 1459 message->ack = 0;
692 message->len = sizeof(struct hv_kvp_msg); 1460 message->len = sizeof(struct hv_kvp_msg);
693 1461
@@ -695,7 +1463,7 @@ int main(void)
695 if (len < 0) { 1463 if (len < 0) {
696 syslog(LOG_ERR, "netlink_send failed; error:%d", len); 1464 syslog(LOG_ERR, "netlink_send failed; error:%d", len);
697 close(fd); 1465 close(fd);
698 exit(-1); 1466 exit(EXIT_FAILURE);
699 } 1467 }
700 1468
701 pfd.fd = fd; 1469 pfd.fd = fd;
@@ -721,12 +1489,21 @@ int main(void)
721 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg); 1489 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
722 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data; 1490 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
723 1491
724 switch (hv_msg->kvp_hdr.operation) { 1492 /*
725 case KVP_OP_REGISTER: 1493 * We will use the KVP header information to pass back
1494 * the error from this daemon. So, first copy the state
1495 * and set the error code to success.
1496 */
1497 op = hv_msg->kvp_hdr.operation;
1498 pool = hv_msg->kvp_hdr.pool;
1499 hv_msg->error = HV_S_OK;
1500
1501 if ((in_hand_shake) && (op == KVP_OP_REGISTER1)) {
726 /* 1502 /*
727 * Driver is registering with us; stash away the version 1503 * Driver is registering with us; stash away the version
728 * information. 1504 * information.
729 */ 1505 */
1506 in_hand_shake = 0;
730 p = (char *)hv_msg->body.kvp_register.version; 1507 p = (char *)hv_msg->body.kvp_register.version;
731 lic_version = malloc(strlen(p) + 1); 1508 lic_version = malloc(strlen(p) + 1);
732 if (lic_version) { 1509 if (lic_version) {
@@ -737,44 +1514,82 @@ int main(void)
737 syslog(LOG_ERR, "malloc failed"); 1514 syslog(LOG_ERR, "malloc failed");
738 } 1515 }
739 continue; 1516 continue;
1517 }
740 1518
741 /* 1519 switch (op) {
742 * The current protocol with the kernel component uses a 1520 case KVP_OP_GET_IP_INFO:
743 * NULL key name to pass an error condition. 1521 kvp_ip_val = &hv_msg->body.kvp_ip_val;
744 * For the SET, GET and DELETE operations, 1522 if_name =
745 * use the existing protocol to pass back error. 1523 kvp_mac_to_if_name((char *)kvp_ip_val->adapter_id);
746 */ 1524
1525 if (if_name == NULL) {
1526 /*
1527 * We could not map the mac address to an
1528 * interface name; return error.
1529 */
1530 hv_msg->error = HV_E_FAIL;
1531 break;
1532 }
1533 error = kvp_get_ip_info(
1534 0, if_name, KVP_OP_GET_IP_INFO,
1535 kvp_ip_val,
1536 (MAX_IP_ADDR_SIZE * 2));
1537
1538 if (error)
1539 hv_msg->error = error;
1540
1541 free(if_name);
1542 break;
1543
1544 case KVP_OP_SET_IP_INFO:
1545 kvp_ip_val = &hv_msg->body.kvp_ip_val;
1546 if_name = kvp_get_if_name(
1547 (char *)kvp_ip_val->adapter_id);
1548 if (if_name == NULL) {
1549 /*
1550 * We could not map the guid to an
1551 * interface name; return error.
1552 */
1553 hv_msg->error = HV_GUID_NOTFOUND;
1554 break;
1555 }
1556 error = kvp_set_ip_info(if_name, kvp_ip_val);
1557 if (error)
1558 hv_msg->error = error;
1559
1560 free(if_name);
1561 break;
747 1562
748 case KVP_OP_SET: 1563 case KVP_OP_SET:
749 if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool, 1564 if (kvp_key_add_or_modify(pool,
750 hv_msg->body.kvp_set.data.key, 1565 hv_msg->body.kvp_set.data.key,
751 hv_msg->body.kvp_set.data.key_size, 1566 hv_msg->body.kvp_set.data.key_size,
752 hv_msg->body.kvp_set.data.value, 1567 hv_msg->body.kvp_set.data.value,
753 hv_msg->body.kvp_set.data.value_size)) 1568 hv_msg->body.kvp_set.data.value_size))
754 strcpy(hv_msg->body.kvp_set.data.key, ""); 1569 hv_msg->error = HV_S_CONT;
755 break; 1570 break;
756 1571
757 case KVP_OP_GET: 1572 case KVP_OP_GET:
758 if (kvp_get_value(hv_msg->kvp_hdr.pool, 1573 if (kvp_get_value(pool,
759 hv_msg->body.kvp_set.data.key, 1574 hv_msg->body.kvp_set.data.key,
760 hv_msg->body.kvp_set.data.key_size, 1575 hv_msg->body.kvp_set.data.key_size,
761 hv_msg->body.kvp_set.data.value, 1576 hv_msg->body.kvp_set.data.value,
762 hv_msg->body.kvp_set.data.value_size)) 1577 hv_msg->body.kvp_set.data.value_size))
763 strcpy(hv_msg->body.kvp_set.data.key, ""); 1578 hv_msg->error = HV_S_CONT;
764 break; 1579 break;
765 1580
766 case KVP_OP_DELETE: 1581 case KVP_OP_DELETE:
767 if (kvp_key_delete(hv_msg->kvp_hdr.pool, 1582 if (kvp_key_delete(pool,
768 hv_msg->body.kvp_delete.key, 1583 hv_msg->body.kvp_delete.key,
769 hv_msg->body.kvp_delete.key_size)) 1584 hv_msg->body.kvp_delete.key_size))
770 strcpy(hv_msg->body.kvp_delete.key, ""); 1585 hv_msg->error = HV_S_CONT;
771 break; 1586 break;
772 1587
773 default: 1588 default:
774 break; 1589 break;
775 } 1590 }
776 1591
777 if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE) 1592 if (op != KVP_OP_ENUMERATE)
778 goto kvp_done; 1593 goto kvp_done;
779 1594
780 /* 1595 /*
@@ -782,13 +1597,14 @@ int main(void)
782 * both the key and the value; if not read from the 1597 * both the key and the value; if not read from the
783 * appropriate pool. 1598 * appropriate pool.
784 */ 1599 */
785 if (hv_msg->kvp_hdr.pool != KVP_POOL_AUTO) { 1600 if (pool != KVP_POOL_AUTO) {
786 kvp_pool_enumerate(hv_msg->kvp_hdr.pool, 1601 if (kvp_pool_enumerate(pool,
787 hv_msg->body.kvp_enum_data.index, 1602 hv_msg->body.kvp_enum_data.index,
788 hv_msg->body.kvp_enum_data.data.key, 1603 hv_msg->body.kvp_enum_data.data.key,
789 HV_KVP_EXCHANGE_MAX_KEY_SIZE, 1604 HV_KVP_EXCHANGE_MAX_KEY_SIZE,
790 hv_msg->body.kvp_enum_data.data.value, 1605 hv_msg->body.kvp_enum_data.data.value,
791 HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1606 HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
1607 hv_msg->error = HV_S_CONT;
792 goto kvp_done; 1608 goto kvp_done;
793 } 1609 }
794 1610
@@ -807,13 +1623,13 @@ int main(void)
807 strcpy(key_value, lic_version); 1623 strcpy(key_value, lic_version);
808 break; 1624 break;
809 case NetworkAddressIPv4: 1625 case NetworkAddressIPv4:
810 kvp_get_ip_address(AF_INET, key_value, 1626 kvp_get_ip_info(AF_INET, NULL, KVP_OP_ENUMERATE,
811 HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1627 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
812 strcpy(key_name, "NetworkAddressIPv4"); 1628 strcpy(key_name, "NetworkAddressIPv4");
813 break; 1629 break;
814 case NetworkAddressIPv6: 1630 case NetworkAddressIPv6:
815 kvp_get_ip_address(AF_INET6, key_value, 1631 kvp_get_ip_info(AF_INET6, NULL, KVP_OP_ENUMERATE,
816 HV_KVP_EXCHANGE_MAX_VALUE_SIZE); 1632 key_value, HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
817 strcpy(key_name, "NetworkAddressIPv6"); 1633 strcpy(key_name, "NetworkAddressIPv6");
818 break; 1634 break;
819 case OSBuildNumber: 1635 case OSBuildNumber:
@@ -841,11 +1657,7 @@ int main(void)
841 strcpy(key_name, "ProcessorArchitecture"); 1657 strcpy(key_name, "ProcessorArchitecture");
842 break; 1658 break;
843 default: 1659 default:
844 strcpy(key_value, "Unknown Key"); 1660 hv_msg->error = HV_S_CONT;
845 /*
846 * We use a null key name to terminate enumeration.
847 */
848 strcpy(key_name, "");
849 break; 1661 break;
850 } 1662 }
851 /* 1663 /*
@@ -863,7 +1675,7 @@ kvp_done:
863 len = netlink_send(fd, incoming_cn_msg); 1675 len = netlink_send(fd, incoming_cn_msg);
864 if (len < 0) { 1676 if (len < 0) {
865 syslog(LOG_ERR, "net_link send failed; error:%d", len); 1677 syslog(LOG_ERR, "net_link send failed; error:%d", len);
866 exit(-1); 1678 exit(EXIT_FAILURE);
867 } 1679 }
868 } 1680 }
869 1681
diff --git a/tools/hv/hv_set_ifconfig.sh b/tools/hv/hv_set_ifconfig.sh
new file mode 100755
index 00000000000..3e9427e08d8
--- /dev/null
+++ b/tools/hv/hv_set_ifconfig.sh
@@ -0,0 +1,68 @@
1#!/bin/bash
2
3# This example script activates an interface based on the specified
4# configuration.
5#
6# In the interest of keeping the KVP daemon code free of distro specific
7# information; the kvp daemon code invokes this external script to configure
8# the interface.
9#
10# The only argument to this script is the configuration file that is to
11# be used to configure the interface.
12#
13# Each Distro is expected to implement this script in a distro specific
14# fashion. For instance on Distros that ship with Network Manager enabled,
15# this script can be based on the Network Manager APIs for configuring the
16# interface.
17#
18# This example script is based on a RHEL environment.
19#
20# Here is the format of the ip configuration file:
21#
22# HWADDR=macaddr
23# IF_NAME=interface name
24# DHCP=yes (This is optional; if yes, DHCP is configured)
25#
26# IPADDR=ipaddr1
27# IPADDR_1=ipaddr2
28# IPADDR_x=ipaddry (where y = x + 1)
29#
30# NETMASK=netmask1
31# NETMASK_x=netmasky (where y = x + 1)
32#
33# GATEWAY=ipaddr1
34# GATEWAY_x=ipaddry (where y = x + 1)
35#
36# DNSx=ipaddrx (where first DNS address is tagged as DNS1 etc)
37#
38# IPV6 addresses will be tagged as IPV6ADDR, IPV6 gateway will be
39# tagged as IPV6_DEFAULTGW and IPV6 NETMASK will be tagged as
40# IPV6NETMASK.
41#
42# The host can specify multiple ipv4 and ipv6 addresses to be
43# configured for the interface. Furthermore, the configuration
44# needs to be persistent. A subsequent GET call on the interface
45# is expected to return the configuration that is set via the SET
46# call.
47#
48
49
50
51echo "IPV6INIT=yes" >> $1
52echo "NM_CONTROLLED=no" >> $1
53echo "PEERDNS=yes" >> $1
54echo "ONBOOT=yes" >> $1
55
56dhcp=$(grep "DHCP" $1 2>/dev/null)
57if [ "$dhcp" != "" ];
58then
59echo "BOOTPROTO=dhcp" >> $1;
60fi
61
62cp $1 /etc/sysconfig/network-scripts/
63
64
65interface=$(echo $1 | awk -F - '{ print $2 }')
66
67/sbin/ifdown $interface 2>/dev/null
68/sbin/ifup $interfac 2>/dev/null