2 * An implementation of key value pair (KVP) functionality for Linux.
5 * Copyright (C) 2010, Novell, Inc.
6 * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
15 * NON INFRINGEMENT. See the GNU General Public License for more
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include <sys/types.h>
26 #include <sys/socket.h>
28 #include <sys/utsname.h>
29 #include <linux/types.h>
35 #include <arpa/inet.h>
36 #include <linux/connector.h>
37 #include <linux/hyperv.h>
38 #include <linux/netlink.h>
46 * KVP protocol: The user mode component first registers with the
47 * the kernel component. Subsequently, the kernel component requests, data
48 * for the specified keys. In response to this message the user mode component
49 * fills in the value corresponding to the specified key. We overload the
50 * sequence field in the cn_msg header to define our KVP message types.
52 * We use this infrastructure for also supporting queries from user mode
53 * application for state that may be maintained in the KVP kernel component.
59 FullyQualifiedDomainName = 0,
60 IntegrationServicesVersion, /*This key is serviced in the kernel*/
71 static char kvp_send_buffer[4096];
72 static char kvp_recv_buffer[4096];
73 static struct sockaddr_nl addr;
75 static char *os_name = "";
76 static char *os_major = "";
77 static char *os_minor = "";
78 static char *processor_arch;
79 static char *os_build;
80 static char *lic_version;
81 static struct utsname uts_buf;
84 #define MAX_FILE_NAME 100
85 #define ENTRIES_PER_BLOCK 50
88 __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
89 __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
92 struct kvp_file_state {
95 struct kvp_record *records;
97 __u8 fname[MAX_FILE_NAME];
100 static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
102 static void kvp_acquire_lock(int pool)
104 struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
107 if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
108 syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
113 static void kvp_release_lock(int pool)
115 struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
118 if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
120 syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
125 static void kvp_update_file(int pool)
128 size_t bytes_written;
131 * We are going to write our in-memory registry out to
132 * disk; acquire the lock first.
134 kvp_acquire_lock(pool);
136 filep = fopen(kvp_file_info[pool].fname, "w");
138 kvp_release_lock(pool);
139 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
143 bytes_written = fwrite(kvp_file_info[pool].records,
144 sizeof(struct kvp_record),
145 kvp_file_info[pool].num_records, filep);
148 kvp_release_lock(pool);
151 static void kvp_update_mem_state(int pool)
154 size_t records_read = 0;
155 struct kvp_record *record = kvp_file_info[pool].records;
156 struct kvp_record *readp;
157 int num_blocks = kvp_file_info[pool].num_blocks;
158 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
160 kvp_acquire_lock(pool);
162 filep = fopen(kvp_file_info[pool].fname, "r");
164 kvp_release_lock(pool);
165 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
168 while (!feof(filep)) {
169 readp = &record[records_read];
170 records_read += fread(readp, sizeof(struct kvp_record),
171 ENTRIES_PER_BLOCK * num_blocks,
176 * We have more data to read.
179 record = realloc(record, alloc_unit * num_blocks);
181 if (record == NULL) {
182 syslog(LOG_ERR, "malloc failed");
190 kvp_file_info[pool].num_blocks = num_blocks;
191 kvp_file_info[pool].records = record;
192 kvp_file_info[pool].num_records = records_read;
194 kvp_release_lock(pool);
196 static int kvp_file_init(void)
202 struct kvp_record *record;
203 struct kvp_record *readp;
206 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
208 if (access("/var/opt/hyperv", F_OK)) {
209 if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
210 syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
215 for (i = 0; i < KVP_POOL_COUNT; i++) {
216 fname = kvp_file_info[i].fname;
219 sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i);
220 fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
226 filep = fopen(fname, "r");
230 record = malloc(alloc_unit * num_blocks);
231 if (record == NULL) {
235 while (!feof(filep)) {
236 readp = &record[records_read];
237 records_read += fread(readp, sizeof(struct kvp_record),
243 * We have more data to read.
246 record = realloc(record, alloc_unit *
248 if (record == NULL) {
256 kvp_file_info[i].fd = fd;
257 kvp_file_info[i].num_blocks = num_blocks;
258 kvp_file_info[i].records = record;
259 kvp_file_info[i].num_records = records_read;
267 static int kvp_key_delete(int pool, __u8 *key, int key_size)
272 struct kvp_record *record;
275 * First update the in-memory state.
277 kvp_update_mem_state(pool);
279 num_records = kvp_file_info[pool].num_records;
280 record = kvp_file_info[pool].records;
282 for (i = 0; i < num_records; i++) {
283 if (memcmp(key, record[i].key, key_size))
286 * Found a match; just move the remaining
289 if (i == num_records) {
290 kvp_file_info[pool].num_records--;
291 kvp_update_file(pool);
297 for (; k < num_records; k++) {
298 strcpy(record[j].key, record[k].key);
299 strcpy(record[j].value, record[k].value);
303 kvp_file_info[pool].num_records--;
304 kvp_update_file(pool);
310 static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
316 struct kvp_record *record;
319 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
320 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
324 * First update the in-memory state.
326 kvp_update_mem_state(pool);
328 num_records = kvp_file_info[pool].num_records;
329 record = kvp_file_info[pool].records;
330 num_blocks = kvp_file_info[pool].num_blocks;
332 for (i = 0; i < num_records; i++) {
333 if (memcmp(key, record[i].key, key_size))
336 * Found a match; just update the value -
337 * this is the modify case.
339 memcpy(record[i].value, value, value_size);
340 kvp_update_file(pool);
345 * Need to add a new entry;
347 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
348 /* Need to allocate a larger array for reg entries. */
349 record = realloc(record, sizeof(struct kvp_record) *
350 ENTRIES_PER_BLOCK * (num_blocks + 1));
354 kvp_file_info[pool].num_blocks++;
357 memcpy(record[i].value, value, value_size);
358 memcpy(record[i].key, key, key_size);
359 kvp_file_info[pool].records = record;
360 kvp_file_info[pool].num_records++;
361 kvp_update_file(pool);
365 static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
370 struct kvp_record *record;
372 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
373 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
377 * First update the in-memory state.
379 kvp_update_mem_state(pool);
381 num_records = kvp_file_info[pool].num_records;
382 record = kvp_file_info[pool].records;
384 for (i = 0; i < num_records; i++) {
385 if (memcmp(key, record[i].key, key_size))
388 * Found a match; just copy the value out.
390 memcpy(value, record[i].value, value_size);
397 static void kvp_pool_enumerate(int pool, int index, __u8 *key, int key_size,
398 __u8 *value, int value_size)
400 struct kvp_record *record;
403 * First update our in-memory database.
405 kvp_update_mem_state(pool);
406 record = kvp_file_info[pool].records;
408 if (index >= kvp_file_info[pool].num_records) {
410 * This is an invalid index; terminate enumeration;
411 * - a NULL value will do the trick.
417 memcpy(key, record[index].key, key_size);
418 memcpy(value, record[index].value, value_size);
422 void kvp_get_os_info(void)
428 os_build = uts_buf.release;
429 processor_arch = uts_buf.machine;
432 * The current windows host (win7) expects the build
433 * string to be of the form: x.y.z
434 * Strip additional information we may have.
436 p = strchr(os_build, '-');
440 file = fopen("/etc/SuSE-release", "r");
442 goto kvp_osinfo_found;
443 file = fopen("/etc/redhat-release", "r");
445 goto kvp_osinfo_found;
447 * Add code for other supported platforms.
451 * We don't have information about the os.
453 os_name = uts_buf.sysname;
457 /* up to three lines */
458 p = fgets(buf, sizeof(buf), file);
460 p = strchr(buf, '\n');
469 p = fgets(buf, sizeof(buf), file);
471 p = strchr(buf, '\n');
480 p = fgets(buf, sizeof(buf), file);
482 p = strchr(buf, '\n');
498 kvp_get_ip_address(int family, char *buffer, int length)
500 struct ifaddrs *ifap;
501 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;
510 * On entry into this function, the buffer is capable of holding the
511 * maximum key value (2048 bytes).
514 if (getifaddrs(&ifap)) {
515 strcpy(buffer, "getifaddrs failed\n");
520 while (curp != NULL) {
521 if ((curp->ifa_addr != NULL) &&
522 (curp->ifa_addr->sa_family == family)) {
523 if (family == AF_INET) {
524 struct sockaddr_in *addr =
525 (struct sockaddr_in *) curp->ifa_addr;
527 str = inet_ntop(family, &addr->sin_addr,
530 strcpy(buffer, "inet_ntop failed\n");
540 offset += strlen(str) + 1;
541 if ((length - offset) < (ipv4_len + 1))
547 * We only support AF_INET and AF_INET6
548 * and the list of addresses is separated by a ";".
550 struct sockaddr_in6 *addr =
551 (struct sockaddr_in6 *) curp->ifa_addr;
553 str = inet_ntop(family,
554 &addr->sin6_addr.s6_addr,
557 strcpy(buffer, "inet_ntop failed\n");
566 offset += strlen(str) + 1;
567 if ((length - offset) < (ipv6_len + 1))
573 curp = curp->ifa_next;
583 kvp_get_domain_name(char *buffer, int length)
585 struct addrinfo hints, *info ;
588 gethostname(buffer, length);
589 memset(&hints, 0, sizeof(hints));
590 hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
591 hints.ai_socktype = SOCK_STREAM;
592 hints.ai_flags = AI_CANONNAME;
594 error = getaddrinfo(buffer, NULL, &hints, &info);
596 strcpy(buffer, "getaddrinfo failed\n");
599 strcpy(buffer, info->ai_canonname);
605 netlink_send(int fd, struct cn_msg *msg)
607 struct nlmsghdr *nlh;
609 struct msghdr message;
613 size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
615 nlh = (struct nlmsghdr *)buffer;
617 nlh->nlmsg_pid = getpid();
618 nlh->nlmsg_type = NLMSG_DONE;
619 nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
620 nlh->nlmsg_flags = 0;
622 iov[0].iov_base = nlh;
623 iov[0].iov_len = sizeof(*nlh);
625 iov[1].iov_base = msg;
626 iov[1].iov_len = size;
628 memset(&message, 0, sizeof(message));
629 message.msg_name = &addr;
630 message.msg_namelen = sizeof(addr);
631 message.msg_iov = iov;
632 message.msg_iovlen = 2;
634 return sendmsg(fd, &message, 0);
639 int fd, len, sock_opt;
641 struct cn_msg *message;
643 struct nlmsghdr *incoming_msg;
644 struct cn_msg *incoming_cn_msg;
645 struct hv_kvp_msg *hv_msg;
651 openlog("KVP", 0, LOG_USER);
652 syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
654 * Retrieve OS release information.
658 if (kvp_file_init()) {
659 syslog(LOG_ERR, "Failed to initialize the pools");
663 fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
665 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
668 addr.nl_family = AF_NETLINK;
671 addr.nl_groups = CN_KVP_IDX;
674 error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
676 syslog(LOG_ERR, "bind failed; error:%d", error);
680 sock_opt = addr.nl_groups;
681 setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
683 * Register ourselves with the kernel.
685 message = (struct cn_msg *)kvp_send_buffer;
686 message->id.idx = CN_KVP_IDX;
687 message->id.val = CN_KVP_VAL;
689 hv_msg = (struct hv_kvp_msg *)message->data;
690 hv_msg->kvp_hdr.operation = KVP_OP_REGISTER;
692 message->len = sizeof(struct hv_kvp_msg);
694 len = netlink_send(fd, message);
696 syslog(LOG_ERR, "netlink_send failed; error:%d", len);
708 len = recv(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0);
711 syslog(LOG_ERR, "recv failed; error:%d", len);
716 incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
717 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
718 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
720 switch (hv_msg->kvp_hdr.operation) {
721 case KVP_OP_REGISTER:
723 * Driver is registering with us; stash away the version
726 p = (char *)hv_msg->body.kvp_register.version;
727 lic_version = malloc(strlen(p) + 1);
729 strcpy(lic_version, p);
730 syslog(LOG_INFO, "KVP LIC Version: %s",
733 syslog(LOG_ERR, "malloc failed");
738 * The current protocol with the kernel component uses a
739 * NULL key name to pass an error condition.
740 * For the SET, GET and DELETE operations,
741 * use the existing protocol to pass back error.
745 if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool,
746 hv_msg->body.kvp_set.data.key,
747 hv_msg->body.kvp_set.data.key_size,
748 hv_msg->body.kvp_set.data.value,
749 hv_msg->body.kvp_set.data.value_size))
750 strcpy(hv_msg->body.kvp_set.data.key, "");
754 if (kvp_get_value(hv_msg->kvp_hdr.pool,
755 hv_msg->body.kvp_set.data.key,
756 hv_msg->body.kvp_set.data.key_size,
757 hv_msg->body.kvp_set.data.value,
758 hv_msg->body.kvp_set.data.value_size))
759 strcpy(hv_msg->body.kvp_set.data.key, "");
763 if (kvp_key_delete(hv_msg->kvp_hdr.pool,
764 hv_msg->body.kvp_delete.key,
765 hv_msg->body.kvp_delete.key_size))
766 strcpy(hv_msg->body.kvp_delete.key, "");
773 if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE)
777 * If the pool is KVP_POOL_AUTO, dynamically generate
778 * both the key and the value; if not read from the
781 if (hv_msg->kvp_hdr.pool != KVP_POOL_AUTO) {
782 kvp_pool_enumerate(hv_msg->kvp_hdr.pool,
783 hv_msg->body.kvp_enum_data.index,
784 hv_msg->body.kvp_enum_data.data.key,
785 HV_KVP_EXCHANGE_MAX_KEY_SIZE,
786 hv_msg->body.kvp_enum_data.data.value,
787 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
791 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
792 key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
793 key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
795 switch (hv_msg->body.kvp_enum_data.index) {
796 case FullyQualifiedDomainName:
797 kvp_get_domain_name(key_value,
798 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
799 strcpy(key_name, "FullyQualifiedDomainName");
801 case IntegrationServicesVersion:
802 strcpy(key_name, "IntegrationServicesVersion");
803 strcpy(key_value, lic_version);
805 case NetworkAddressIPv4:
806 kvp_get_ip_address(AF_INET, key_value,
807 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
808 strcpy(key_name, "NetworkAddressIPv4");
810 case NetworkAddressIPv6:
811 kvp_get_ip_address(AF_INET6, key_value,
812 HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
813 strcpy(key_name, "NetworkAddressIPv6");
816 strcpy(key_value, os_build);
817 strcpy(key_name, "OSBuildNumber");
820 strcpy(key_value, os_name);
821 strcpy(key_name, "OSName");
824 strcpy(key_value, os_major);
825 strcpy(key_name, "OSMajorVersion");
828 strcpy(key_value, os_minor);
829 strcpy(key_name, "OSMinorVersion");
832 strcpy(key_value, os_build);
833 strcpy(key_name, "OSVersion");
835 case ProcessorArchitecture:
836 strcpy(key_value, processor_arch);
837 strcpy(key_name, "ProcessorArchitecture");
840 strcpy(key_value, "Unknown Key");
842 * We use a null key name to terminate enumeration.
844 strcpy(key_name, "");
848 * Send the value back to the kernel. The response is
849 * already in the receive buffer. Update the cn_msg header to
850 * reflect the key value that has been added to the message
854 incoming_cn_msg->id.idx = CN_KVP_IDX;
855 incoming_cn_msg->id.val = CN_KVP_VAL;
856 incoming_cn_msg->ack = 0;
857 incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
859 len = netlink_send(fd, incoming_cn_msg);
861 syslog(LOG_ERR, "net_link send failed; error:%d", len);