diff options
Diffstat (limited to 'tools/hv')
-rwxr-xr-x | tools/hv/hv_get_dhcp_info.sh | 28 | ||||
-rwxr-xr-x | tools/hv/hv_get_dns_info.sh | 13 | ||||
-rw-r--r-- | tools/hv/hv_kvp_daemon.c | 1036 | ||||
-rwxr-xr-x | tools/hv/hv_set_ifconfig.sh | 68 |
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 | |||
19 | if_file="/etc/sysconfig/network-scripts/ifcfg-"$1 | ||
20 | |||
21 | dhcp=$(grep "dhcp" $if_file 2>/dev/null) | ||
22 | |||
23 | if [ "$dhcp" != "" ]; | ||
24 | then | ||
25 | echo "Enabled" | ||
26 | else | ||
27 | echo "Disabled" | ||
28 | fi | ||
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 | |||
13 | cat /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 | |||
74 | enum { | ||
75 | IPADDR = 0, | ||
76 | NETMASK, | ||
77 | GATEWAY, | ||
78 | DNS | ||
79 | }; | ||
80 | |||
71 | static char kvp_send_buffer[4096]; | 81 | static char kvp_send_buffer[4096]; |
72 | static char kvp_recv_buffer[4096]; | 82 | static char kvp_recv_buffer[4096 * 2]; |
73 | static struct sockaddr_nl addr; | 83 | static struct sockaddr_nl addr; |
84 | static int in_hand_shake = 1; | ||
74 | 85 | ||
75 | static char *os_name = ""; | 86 | static char *os_name = ""; |
76 | static char *os_major = ""; | 87 | static char *os_major = ""; |
77 | static char *os_minor = ""; | 88 | static char *os_minor = ""; |
78 | static char *processor_arch; | 89 | static char *processor_arch; |
79 | static char *os_build; | 90 | static char *os_build; |
80 | static char *lic_version; | 91 | static char *lic_version = "Unknown version"; |
81 | static struct utsname uts_buf; | 92 | static 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 | ||
87 | struct kvp_record { | 103 | struct 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 | ||
92 | struct kvp_file_state { | 108 | struct 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 | ||
100 | static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT]; | 116 | static 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 | } |
196 | static int kvp_file_init(void) | 223 | static 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 | ||
397 | static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size, | 429 | static 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 | ||
456 | kvp_osinfo_found: | 535 | kvp_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 | |||
586 | static 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 | |||
643 | static 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 | |||
678 | static 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 | |||
737 | static 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 | |||
767 | static 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 | |||
853 | static 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 | |||
862 | static 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 | |||
497 | static int | 898 | static int |
498 | kvp_get_ip_address(int family, char *buffer, int length) | 899 | kvp_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 | |||
1020 | gather_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 | ||
1037 | static 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 | |||
1065 | static 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 | |||
1077 | static 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 | |||
1113 | static 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 | |||
1126 | static 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 | |||
1211 | static 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 | |||
1325 | setval_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 | |||
1338 | setval_error: | ||
1339 | syslog(LOG_ERR, "Failed to write config file"); | ||
1340 | free(mac_addr); | ||
1341 | fclose(file); | ||
1342 | return error; | ||
1343 | } | ||
1344 | |||
1345 | |||
582 | static int | 1346 | static int |
583 | kvp_get_domain_name(char *buffer, int length) | 1347 | kvp_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 | |||
51 | echo "IPV6INIT=yes" >> $1 | ||
52 | echo "NM_CONTROLLED=no" >> $1 | ||
53 | echo "PEERDNS=yes" >> $1 | ||
54 | echo "ONBOOT=yes" >> $1 | ||
55 | |||
56 | dhcp=$(grep "DHCP" $1 2>/dev/null) | ||
57 | if [ "$dhcp" != "" ]; | ||
58 | then | ||
59 | echo "BOOTPROTO=dhcp" >> $1; | ||
60 | fi | ||
61 | |||
62 | cp $1 /etc/sysconfig/network-scripts/ | ||
63 | |||
64 | |||
65 | interface=$(echo $1 | awk -F - '{ print $2 }') | ||
66 | |||
67 | /sbin/ifdown $interface 2>/dev/null | ||
68 | /sbin/ifup $interfac 2>/dev/null | ||