Tools: hv: Fully support the new KVP verbs in the user level
[linux-flexiantxendom0-3.2.10.git] / tools / hv / hv_kvp_daemon.c
1 /*
2  * An implementation of key value pair (KVP) functionality for Linux.
3  *
4  *
5  * Copyright (C) 2010, Novell, Inc.
6  * Author : K. Y. Srinivasan <ksrinivasan@novell.com>
7  *
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.
11  *
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
16  * details.
17  *
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.
21  *
22  */
23
24
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/poll.h>
28 #include <sys/utsname.h>
29 #include <linux/types.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <arpa/inet.h>
36 #include <linux/connector.h>
37 #include <linux/hyperv.h>
38 #include <linux/netlink.h>
39 #include <ifaddrs.h>
40 #include <netdb.h>
41 #include <syslog.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44
45 /*
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.
51  *
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.
54  *
55  */
56
57
58 enum key_index {
59         FullyQualifiedDomainName = 0,
60         IntegrationServicesVersion, /*This key is serviced in the kernel*/
61         NetworkAddressIPv4,
62         NetworkAddressIPv6,
63         OSBuildNumber,
64         OSName,
65         OSMajorVersion,
66         OSMinorVersion,
67         OSVersion,
68         ProcessorArchitecture
69 };
70
71 static char kvp_send_buffer[4096];
72 static char kvp_recv_buffer[4096];
73 static struct sockaddr_nl addr;
74
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;
82
83
84 #define MAX_FILE_NAME 100
85 #define ENTRIES_PER_BLOCK 50
86
87 struct kvp_record {
88         __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
89         __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
90 };
91
92 struct kvp_file_state {
93         int fd;
94         int num_blocks;
95         struct kvp_record *records;
96         int num_records;
97         __u8 fname[MAX_FILE_NAME];
98 };
99
100 static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
101
102 static void kvp_acquire_lock(int pool)
103 {
104         struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
105         fl.l_pid = getpid();
106
107         if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
108                 syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
109                 exit(-1);
110         }
111 }
112
113 static void kvp_release_lock(int pool)
114 {
115         struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
116         fl.l_pid = getpid();
117
118         if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
119                 perror("fcntl");
120                 syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
121                 exit(-1);
122         }
123 }
124
125 static void kvp_update_file(int pool)
126 {
127         FILE *filep;
128         size_t bytes_written;
129
130         /*
131          * We are going to write our in-memory registry out to
132          * disk; acquire the lock first.
133          */
134         kvp_acquire_lock(pool);
135
136         filep = fopen(kvp_file_info[pool].fname, "w");
137         if (!filep) {
138                 kvp_release_lock(pool);
139                 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
140                 exit(-1);
141         }
142
143         bytes_written = fwrite(kvp_file_info[pool].records,
144                                 sizeof(struct kvp_record),
145                                 kvp_file_info[pool].num_records, filep);
146
147         fflush(filep);
148         kvp_release_lock(pool);
149 }
150
151 static int kvp_file_init(void)
152 {
153         int ret, fd;
154         FILE *filep;
155         size_t records_read;
156         __u8 *fname;
157         struct kvp_record *record;
158         struct kvp_record *readp;
159         int num_blocks;
160         int i;
161         int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
162
163         if (access("/var/opt/hyperv", F_OK)) {
164                 if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
165                         syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
166                         exit(-1);
167                 }
168         }
169
170         for (i = 0; i < KVP_POOL_COUNT; i++) {
171                 fname = kvp_file_info[i].fname;
172                 records_read = 0;
173                 num_blocks = 1;
174                 sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i);
175                 fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
176
177                 if (fd == -1)
178                         return 1;
179
180
181                 filep = fopen(fname, "r");
182                 if (!filep)
183                         return 1;
184
185                 record = malloc(alloc_unit * num_blocks);
186                 if (record == NULL) {
187                         fclose(filep);
188                         return 1;
189                 }
190                 while (!feof(filep)) {
191                         readp = &record[records_read];
192                         records_read += fread(readp, sizeof(struct kvp_record),
193                                         ENTRIES_PER_BLOCK,
194                                         filep);
195
196                         if (!feof(filep)) {
197                                 /*
198                                  * We have more data to read.
199                                  */
200                                 num_blocks++;
201                                 record = realloc(record, alloc_unit *
202                                                 num_blocks);
203                                 if (record == NULL) {
204                                         fclose(filep);
205                                         return 1;
206                                 }
207                                 continue;
208                         }
209                         break;
210                 }
211                 kvp_file_info[i].fd = fd;
212                 kvp_file_info[i].num_blocks = num_blocks;
213                 kvp_file_info[i].records = record;
214                 kvp_file_info[i].num_records = records_read;
215                 fclose(filep);
216
217         }
218
219         return 0;
220 }
221
222 static int kvp_key_delete(int pool, __u8 *key, int key_size)
223 {
224         int i;
225         int j, k;
226         int num_records = kvp_file_info[pool].num_records;
227         struct kvp_record *record = kvp_file_info[pool].records;
228
229         for (i = 0; i < num_records; i++) {
230                 if (memcmp(key, record[i].key, key_size))
231                         continue;
232                 /*
233                  * Found a match; just move the remaining
234                  * entries up.
235                  */
236                 if (i == num_records) {
237                         kvp_file_info[pool].num_records--;
238                         kvp_update_file(pool);
239                         return 0;
240                 }
241
242                 j = i;
243                 k = j + 1;
244                 for (; k < num_records; k++) {
245                         strcpy(record[j].key, record[k].key);
246                         strcpy(record[j].value, record[k].value);
247                         j++;
248                 }
249
250                 kvp_file_info[pool].num_records--;
251                 kvp_update_file(pool);
252                 return 0;
253         }
254         return 1;
255 }
256
257 static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
258                         int value_size)
259 {
260         int i;
261         int j, k;
262         int num_records = kvp_file_info[pool].num_records;
263         struct kvp_record *record = kvp_file_info[pool].records;
264         int num_blocks = kvp_file_info[pool].num_blocks;
265
266         if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
267                 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
268                 return 1;
269
270         for (i = 0; i < num_records; i++) {
271                 if (memcmp(key, record[i].key, key_size))
272                         continue;
273                 /*
274                  * Found a match; just update the value -
275                  * this is the modify case.
276                  */
277                 memcpy(record[i].value, value, value_size);
278                 kvp_update_file(pool);
279                 return 0;
280         }
281
282         /*
283          * Need to add a new entry;
284          */
285         if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
286                 /* Need to allocate a larger array for reg entries. */
287                 record = realloc(record, sizeof(struct kvp_record) *
288                          ENTRIES_PER_BLOCK * (num_blocks + 1));
289
290                 if (record == NULL)
291                         return 1;
292                 kvp_file_info[pool].num_blocks++;
293
294         }
295         memcpy(record[i].value, value, value_size);
296         memcpy(record[i].key, key, key_size);
297         kvp_file_info[pool].records = record;
298         kvp_file_info[pool].num_records++;
299         kvp_update_file(pool);
300         return 0;
301 }
302
303 static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
304                         int value_size)
305 {
306         int i;
307         int num_records = kvp_file_info[pool].num_records;
308         struct kvp_record *record = kvp_file_info[pool].records;
309
310         if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
311                 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
312                 return 1;
313
314         for (i = 0; i < num_records; i++) {
315                 if (memcmp(key, record[i].key, key_size))
316                         continue;
317                 /*
318                  * Found a match; just copy the value out.
319                  */
320                 memcpy(value, record[i].value, value_size);
321                 return 0;
322         }
323
324         return 1;
325 }
326
327 void kvp_get_os_info(void)
328 {
329         FILE    *file;
330         char    *p, buf[512];
331
332         uname(&uts_buf);
333         os_build = uts_buf.release;
334         processor_arch = uts_buf.machine;
335
336         /*
337          * The current windows host (win7) expects the build
338          * string to be of the form: x.y.z
339          * Strip additional information we may have.
340          */
341         p = strchr(os_build, '-');
342         if (p)
343                 *p = '\0';
344
345         file = fopen("/etc/SuSE-release", "r");
346         if (file != NULL)
347                 goto kvp_osinfo_found;
348         file  = fopen("/etc/redhat-release", "r");
349         if (file != NULL)
350                 goto kvp_osinfo_found;
351         /*
352          * Add code for other supported platforms.
353          */
354
355         /*
356          * We don't have information about the os.
357          */
358         os_name = uts_buf.sysname;
359         return;
360
361 kvp_osinfo_found:
362         /* up to three lines */
363         p = fgets(buf, sizeof(buf), file);
364         if (p) {
365                 p = strchr(buf, '\n');
366                 if (p)
367                         *p = '\0';
368                 p = strdup(buf);
369                 if (!p)
370                         goto done;
371                 os_name = p;
372
373                 /* second line */
374                 p = fgets(buf, sizeof(buf), file);
375                 if (p) {
376                         p = strchr(buf, '\n');
377                         if (p)
378                                 *p = '\0';
379                         p = strdup(buf);
380                         if (!p)
381                                 goto done;
382                         os_major = p;
383
384                         /* third line */
385                         p = fgets(buf, sizeof(buf), file);
386                         if (p)  {
387                                 p = strchr(buf, '\n');
388                                 if (p)
389                                         *p = '\0';
390                                 p = strdup(buf);
391                                 if (p)
392                                         os_minor = p;
393                         }
394                 }
395         }
396
397 done:
398         fclose(file);
399         return;
400 }
401
402 static int
403 kvp_get_ip_address(int family, char *buffer, int length)
404 {
405         struct ifaddrs *ifap;
406         struct ifaddrs *curp;
407         int ipv4_len = strlen("255.255.255.255") + 1;
408         int ipv6_len = strlen("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")+1;
409         int offset = 0;
410         const char *str;
411         char tmp[50];
412         int error = 0;
413
414         /*
415          * On entry into this function, the buffer is capable of holding the
416          * maximum key value (2048 bytes).
417          */
418
419         if (getifaddrs(&ifap)) {
420                 strcpy(buffer, "getifaddrs failed\n");
421                 return 1;
422         }
423
424         curp = ifap;
425         while (curp != NULL) {
426                 if ((curp->ifa_addr != NULL) &&
427                    (curp->ifa_addr->sa_family == family)) {
428                         if (family == AF_INET) {
429                                 struct sockaddr_in *addr =
430                                 (struct sockaddr_in *) curp->ifa_addr;
431
432                                 str = inet_ntop(family, &addr->sin_addr,
433                                                 tmp, 50);
434                                 if (str == NULL) {
435                                         strcpy(buffer, "inet_ntop failed\n");
436                                         error = 1;
437                                         goto getaddr_done;
438                                 }
439                                 if (offset == 0)
440                                         strcpy(buffer, tmp);
441                                 else
442                                         strcat(buffer, tmp);
443                                 strcat(buffer, ";");
444
445                                 offset += strlen(str) + 1;
446                                 if ((length - offset) < (ipv4_len + 1))
447                                         goto getaddr_done;
448
449                         } else {
450
451                         /*
452                          * We only support AF_INET and AF_INET6
453                          * and the list of addresses is separated by a ";".
454                          */
455                                 struct sockaddr_in6 *addr =
456                                 (struct sockaddr_in6 *) curp->ifa_addr;
457
458                                 str = inet_ntop(family,
459                                         &addr->sin6_addr.s6_addr,
460                                         tmp, 50);
461                                 if (str == NULL) {
462                                         strcpy(buffer, "inet_ntop failed\n");
463                                         error = 1;
464                                         goto getaddr_done;
465                                 }
466                                 if (offset == 0)
467                                         strcpy(buffer, tmp);
468                                 else
469                                         strcat(buffer, tmp);
470                                 strcat(buffer, ";");
471                                 offset += strlen(str) + 1;
472                                 if ((length - offset) < (ipv6_len + 1))
473                                         goto getaddr_done;
474
475                         }
476
477                 }
478                 curp = curp->ifa_next;
479         }
480
481 getaddr_done:
482         freeifaddrs(ifap);
483         return error;
484 }
485
486
487 static int
488 kvp_get_domain_name(char *buffer, int length)
489 {
490         struct addrinfo hints, *info ;
491         int error = 0;
492
493         gethostname(buffer, length);
494         memset(&hints, 0, sizeof(hints));
495         hints.ai_family = AF_INET; /*Get only ipv4 addrinfo. */
496         hints.ai_socktype = SOCK_STREAM;
497         hints.ai_flags = AI_CANONNAME;
498
499         error = getaddrinfo(buffer, NULL, &hints, &info);
500         if (error != 0) {
501                 strcpy(buffer, "getaddrinfo failed\n");
502                 return error;
503         }
504         strcpy(buffer, info->ai_canonname);
505         freeaddrinfo(info);
506         return error;
507 }
508
509 static int
510 netlink_send(int fd, struct cn_msg *msg)
511 {
512         struct nlmsghdr *nlh;
513         unsigned int size;
514         struct msghdr message;
515         char buffer[64];
516         struct iovec iov[2];
517
518         size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
519
520         nlh = (struct nlmsghdr *)buffer;
521         nlh->nlmsg_seq = 0;
522         nlh->nlmsg_pid = getpid();
523         nlh->nlmsg_type = NLMSG_DONE;
524         nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
525         nlh->nlmsg_flags = 0;
526
527         iov[0].iov_base = nlh;
528         iov[0].iov_len = sizeof(*nlh);
529
530         iov[1].iov_base = msg;
531         iov[1].iov_len = size;
532
533         memset(&message, 0, sizeof(message));
534         message.msg_name = &addr;
535         message.msg_namelen = sizeof(addr);
536         message.msg_iov = iov;
537         message.msg_iovlen = 2;
538
539         return sendmsg(fd, &message, 0);
540 }
541
542 int main(void)
543 {
544         int fd, len, sock_opt;
545         int error;
546         struct cn_msg *message;
547         struct pollfd pfd;
548         struct nlmsghdr *incoming_msg;
549         struct cn_msg   *incoming_cn_msg;
550         struct hv_kvp_msg *hv_msg;
551         char    *p;
552         char    *key_value;
553         char    *key_name;
554
555         daemon(1, 0);
556         openlog("KVP", 0, LOG_USER);
557         syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
558         /*
559          * Retrieve OS release information.
560          */
561         kvp_get_os_info();
562
563         if (kvp_file_init()) {
564                 syslog(LOG_ERR, "Failed to initialize the pools");
565                 exit(-1);
566         }
567
568         fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
569         if (fd < 0) {
570                 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
571                 exit(-1);
572         }
573         addr.nl_family = AF_NETLINK;
574         addr.nl_pad = 0;
575         addr.nl_pid = 0;
576         addr.nl_groups = CN_KVP_IDX;
577
578
579         error = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
580         if (error < 0) {
581                 syslog(LOG_ERR, "bind failed; error:%d", error);
582                 close(fd);
583                 exit(-1);
584         }
585         sock_opt = addr.nl_groups;
586         setsockopt(fd, 270, 1, &sock_opt, sizeof(sock_opt));
587         /*
588          * Register ourselves with the kernel.
589          */
590         message = (struct cn_msg *)kvp_send_buffer;
591         message->id.idx = CN_KVP_IDX;
592         message->id.val = CN_KVP_VAL;
593
594         hv_msg = (struct hv_kvp_msg *)message->data;
595         hv_msg->kvp_hdr.operation = KVP_OP_REGISTER;
596         message->ack = 0;
597         message->len = sizeof(struct hv_kvp_msg);
598
599         len = netlink_send(fd, message);
600         if (len < 0) {
601                 syslog(LOG_ERR, "netlink_send failed; error:%d", len);
602                 close(fd);
603                 exit(-1);
604         }
605
606         pfd.fd = fd;
607
608         while (1) {
609                 pfd.events = POLLIN;
610                 pfd.revents = 0;
611                 poll(&pfd, 1, -1);
612
613                 len = recv(fd, kvp_recv_buffer, sizeof(kvp_recv_buffer), 0);
614
615                 if (len < 0) {
616                         syslog(LOG_ERR, "recv failed; error:%d", len);
617                         close(fd);
618                         return -1;
619                 }
620
621                 incoming_msg = (struct nlmsghdr *)kvp_recv_buffer;
622                 incoming_cn_msg = (struct cn_msg *)NLMSG_DATA(incoming_msg);
623                 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
624
625                 switch (hv_msg->kvp_hdr.operation) {
626                 case KVP_OP_REGISTER:
627                         /*
628                          * Driver is registering with us; stash away the version
629                          * information.
630                          */
631                         p = (char *)hv_msg->body.kvp_register.version;
632                         lic_version = malloc(strlen(p) + 1);
633                         if (lic_version) {
634                                 strcpy(lic_version, p);
635                                 syslog(LOG_INFO, "KVP LIC Version: %s",
636                                         lic_version);
637                         } else {
638                                 syslog(LOG_ERR, "malloc failed");
639                         }
640                         continue;
641
642                 /*
643                  * The current protocol with the kernel component uses a
644                  * NULL key name to pass an error condition.
645                  * For the SET, GET and DELETE operations,
646                  * use the existing protocol to pass back error.
647                  */
648
649                 case KVP_OP_SET:
650                         if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool,
651                                         hv_msg->body.kvp_set.data.key,
652                                         hv_msg->body.kvp_set.data.key_size,
653                                         hv_msg->body.kvp_set.data.value,
654                                         hv_msg->body.kvp_set.data.value_size))
655                                 strcpy(hv_msg->body.kvp_set.data.key, "");
656                         break;
657
658                 case KVP_OP_GET:
659                         if (kvp_get_value(hv_msg->kvp_hdr.pool,
660                                         hv_msg->body.kvp_set.data.key,
661                                         hv_msg->body.kvp_set.data.key_size,
662                                         hv_msg->body.kvp_set.data.value,
663                                         hv_msg->body.kvp_set.data.value_size))
664                                 strcpy(hv_msg->body.kvp_set.data.key, "");
665                         break;
666
667                 case KVP_OP_DELETE:
668                         if (kvp_key_delete(hv_msg->kvp_hdr.pool,
669                                         hv_msg->body.kvp_delete.key,
670                                         hv_msg->body.kvp_delete.key_size))
671                                 strcpy(hv_msg->body.kvp_delete.key, "");
672                         break;
673
674                 default:
675                         break;
676                 }
677
678                 if (hv_msg->kvp_hdr.operation != KVP_OP_ENUMERATE)
679                         goto kvp_done;
680
681                 hv_msg = (struct hv_kvp_msg *)incoming_cn_msg->data;
682                 key_name = (char *)hv_msg->body.kvp_enum_data.data.key;
683                 key_value = (char *)hv_msg->body.kvp_enum_data.data.value;
684
685                 switch (hv_msg->body.kvp_enum_data.index) {
686                 case FullyQualifiedDomainName:
687                         kvp_get_domain_name(key_value,
688                                         HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
689                         strcpy(key_name, "FullyQualifiedDomainName");
690                         break;
691                 case IntegrationServicesVersion:
692                         strcpy(key_name, "IntegrationServicesVersion");
693                         strcpy(key_value, lic_version);
694                         break;
695                 case NetworkAddressIPv4:
696                         kvp_get_ip_address(AF_INET, key_value,
697                                         HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
698                         strcpy(key_name, "NetworkAddressIPv4");
699                         break;
700                 case NetworkAddressIPv6:
701                         kvp_get_ip_address(AF_INET6, key_value,
702                                         HV_KVP_EXCHANGE_MAX_VALUE_SIZE);
703                         strcpy(key_name, "NetworkAddressIPv6");
704                         break;
705                 case OSBuildNumber:
706                         strcpy(key_value, os_build);
707                         strcpy(key_name, "OSBuildNumber");
708                         break;
709                 case OSName:
710                         strcpy(key_value, os_name);
711                         strcpy(key_name, "OSName");
712                         break;
713                 case OSMajorVersion:
714                         strcpy(key_value, os_major);
715                         strcpy(key_name, "OSMajorVersion");
716                         break;
717                 case OSMinorVersion:
718                         strcpy(key_value, os_minor);
719                         strcpy(key_name, "OSMinorVersion");
720                         break;
721                 case OSVersion:
722                         strcpy(key_value, os_build);
723                         strcpy(key_name, "OSVersion");
724                         break;
725                 case ProcessorArchitecture:
726                         strcpy(key_value, processor_arch);
727                         strcpy(key_name, "ProcessorArchitecture");
728                         break;
729                 default:
730                         strcpy(key_value, "Unknown Key");
731                         /*
732                          * We use a null key name to terminate enumeration.
733                          */
734                         strcpy(key_name, "");
735                         break;
736                 }
737                 /*
738                  * Send the value back to the kernel. The response is
739                  * already in the receive buffer. Update the cn_msg header to
740                  * reflect the key value that has been added to the message
741                  */
742 kvp_done:
743
744                 incoming_cn_msg->id.idx = CN_KVP_IDX;
745                 incoming_cn_msg->id.val = CN_KVP_VAL;
746                 incoming_cn_msg->ack = 0;
747                 incoming_cn_msg->len = sizeof(struct hv_kvp_msg);
748
749                 len = netlink_send(fd, incoming_cn_msg);
750                 if (len < 0) {
751                         syslog(LOG_ERR, "net_link send failed; error:%d", len);
752                         exit(-1);
753                 }
754         }
755
756 }