1 /* $OpenBSD: ldomd.c,v 1.7 2016/08/28 00:51:48 guenther Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Mark Kettenis 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/ioctl.h> 21 #include <assert.h> 22 #include <err.h> 23 #include <errno.h> 24 #include <fcntl.h> 25 #include <stdarg.h> 26 #include <stdlib.h> 27 #include <stdio.h> 28 #include <string.h> 29 #include <syslog.h> 30 #include <time.h> 31 #include <unistd.h> 32 33 #include "ds.h" 34 #include "hvctl.h" 35 #include "mdesc.h" 36 #include "util.h" 37 #include "ldomd.h" 38 39 TAILQ_HEAD(guest_head, guest) guests; 40 41 void add_guest(struct md_node *); 42 void map_domain_services(struct md *); 43 44 void frag_init(void); 45 void add_frag_mblock(struct md_node *); 46 void add_frag(uint64_t); 47 void delete_frag(uint64_t); 48 uint64_t alloc_frag(void); 49 50 void hv_update_md(struct guest *guest); 51 void hv_open(void); 52 void hv_close(void); 53 void hv_read(uint64_t, void *, size_t); 54 void hv_write(uint64_t, void *, size_t); 55 56 int hvctl_seq = 1; 57 int hvctl_fd; 58 59 void *hvmd_buf; 60 size_t hvmd_len; 61 struct md *hvmd; 62 uint64_t hv_mdpa; 63 64 __dead void usage(void); 65 void logit(int, const char *, ...); 66 void vlog(int, const char *, va_list); 67 68 void 69 log_init(int n_debug) 70 { 71 extern char *__progname; 72 73 debug = n_debug; 74 75 if (!debug) 76 openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON); 77 78 tzset(); 79 } 80 81 void 82 fatal(const char *emsg) 83 { 84 if (errno) 85 logit(LOG_CRIT, "fatal: %s: %s\n", emsg, strerror(errno)); 86 else 87 logit(LOG_CRIT, "fatal: %s\n", emsg); 88 89 exit(EXIT_FAILURE); 90 } 91 92 void 93 logit(int pri, const char *fmt, ...) 94 { 95 va_list ap; 96 97 va_start(ap, fmt); 98 vlog(pri, fmt, ap); 99 va_end(ap); 100 } 101 102 void 103 vlog(int pri, const char *fmt, va_list ap) 104 { 105 char *nfmt; 106 107 if (debug) { 108 /* best effort in out of mem situations */ 109 if (asprintf(&nfmt, "%s\n", fmt) == -1) { 110 vfprintf(stderr, fmt, ap); 111 fprintf(stderr, "\n"); 112 } else { 113 vfprintf(stderr, nfmt, ap); 114 free(nfmt); 115 } 116 fflush(stderr); 117 } else 118 vsyslog(pri, fmt, ap); 119 } 120 121 int 122 main(int argc, char **argv) 123 { 124 struct hvctl_msg msg; 125 ssize_t nbytes; 126 struct md_header hdr; 127 struct md_node *node; 128 struct md_prop *prop; 129 struct guest *guest; 130 int debug = 0; 131 int ch; 132 int i; 133 134 log_init(1); 135 136 while ((ch = getopt(argc, argv, "d")) != -1) { 137 switch (ch) { 138 case 'd': 139 debug = 1; 140 break; 141 default: 142 usage(); 143 /* NOTREACHED */ 144 } 145 } 146 147 argc -= optind; 148 argv += optind; 149 if (argc > 0) 150 usage(); 151 152 if (!debug) 153 if (daemon(0, 0)) 154 fatal("daemon"); 155 156 log_init(debug); 157 158 hv_open(); 159 160 /* 161 * Request config. 162 */ 163 bzero(&msg, sizeof(msg)); 164 msg.hdr.op = HVCTL_OP_GET_HVCONFIG; 165 msg.hdr.seq = hvctl_seq++; 166 nbytes = write(hvctl_fd, &msg, sizeof(msg)); 167 if (nbytes != sizeof(msg)) 168 fatal("write"); 169 170 bzero(&msg, sizeof(msg)); 171 nbytes = read(hvctl_fd, &msg, sizeof(msg)); 172 if (nbytes != sizeof(msg)) 173 fatal("read"); 174 175 hv_mdpa = msg.msg.hvcnf.hvmdp; 176 hv_read(hv_mdpa, &hdr, sizeof(hdr)); 177 hvmd_len = sizeof(hdr) + hdr.node_blk_sz + hdr.name_blk_sz + 178 hdr.data_blk_sz; 179 hvmd_buf = xmalloc(hvmd_len); 180 hv_read(hv_mdpa, hvmd_buf, hvmd_len); 181 182 hvmd = md_ingest(hvmd_buf, hvmd_len); 183 node = md_find_node(hvmd, "guests"); 184 TAILQ_INIT(&guests); 185 TAILQ_FOREACH(prop, &node->prop_list, link) { 186 if (prop->tag == MD_PROP_ARC && 187 strcmp(prop->name->str, "fwd") == 0) 188 add_guest(prop->d.arc.node); 189 } 190 191 frag_init(); 192 193 TAILQ_FOREACH(guest, &guests, link) { 194 struct ds_conn *dc; 195 char path[64]; 196 197 if (strcmp(guest->name, "primary") == 0) 198 continue; 199 200 snprintf(path, sizeof(path), "/dev/ldom-%s", guest->name); 201 dc = ds_conn_open(path, guest); 202 ds_conn_register_service(dc, &var_config_service); 203 } 204 205 hv_close(); 206 207 /* 208 * Open all virtual disk server port device files. As long as 209 * we keep these device files open, the corresponding virtual 210 * disks will be available to the guest domains. For now we 211 * just keep them open until we exit, so there is not reason 212 * to keep track of the file descriptors. 213 */ 214 for (i = 0; i < 256; i++) { 215 char path[64]; 216 217 snprintf(path, sizeof(path), "/dev/vdsp%d", i); 218 if (open(path, O_RDWR, 0) == -1) 219 break; 220 } 221 222 ds_conn_serve(); 223 224 exit(EXIT_SUCCESS); 225 } 226 227 void 228 usage(void) 229 { 230 extern char *__progname; 231 232 fprintf(stderr, "usage: %s [-d]\n", __progname); 233 exit(EXIT_FAILURE); 234 } 235 236 void 237 add_guest(struct md_node *node) 238 { 239 struct guest *guest; 240 struct md_header hdr; 241 void *buf; 242 size_t len; 243 244 guest = xmalloc(sizeof(*guest)); 245 246 if (!md_get_prop_str(hvmd, node, "name", &guest->name)) 247 goto free; 248 if (!md_get_prop_val(hvmd, node, "gid", &guest->gid)) 249 goto free; 250 if (!md_get_prop_val(hvmd, node, "mdpa", &guest->mdpa)) 251 goto free; 252 253 hv_read(guest->mdpa, &hdr, sizeof(hdr)); 254 len = sizeof(hdr) + hdr.node_blk_sz + hdr.name_blk_sz + 255 hdr.data_blk_sz; 256 buf = xmalloc(len); 257 hv_read(guest->mdpa, buf, len); 258 259 guest->node = node; 260 guest->md = md_ingest(buf, len); 261 if (strcmp(guest->name, "primary") == 0) 262 map_domain_services(guest->md); 263 264 TAILQ_INSERT_TAIL(&guests, guest, link); 265 return; 266 267 free: 268 free(guest); 269 } 270 271 void 272 map_domain_services(struct md *md) 273 { 274 struct md_node *node; 275 const char *name; 276 char source[64]; 277 char target[64]; 278 int unit = 0; 279 280 TAILQ_FOREACH(node, &md->node_list, link) { 281 if (strcmp(node->name->str, "virtual-device-port") != 0) 282 continue; 283 284 if (!md_get_prop_str(md, node, "vldc-svc-name", &name)) 285 continue; 286 287 if (strncmp(name, "ldom-", 5) != 0 || 288 strcmp(name, "ldom-primary") == 0) 289 continue; 290 291 snprintf(source, sizeof(source), "/dev/ldom%d", unit++); 292 snprintf(target, sizeof(target), "/dev/%s", name); 293 unlink(target); 294 symlink(source, target); 295 } 296 } 297 298 struct frag { 299 TAILQ_ENTRY(frag) link; 300 uint64_t base; 301 }; 302 303 TAILQ_HEAD(frag_head, frag) free_frags; 304 305 uint64_t fragsize; 306 307 void 308 frag_init(void) 309 { 310 struct md_node *node; 311 struct md_prop *prop; 312 313 node = md_find_node(hvmd, "frag_space"); 314 md_get_prop_val(hvmd, node, "fragsize", &fragsize); 315 TAILQ_INIT(&free_frags); 316 TAILQ_FOREACH(prop, &node->prop_list, link) { 317 if (prop->tag == MD_PROP_ARC && 318 strcmp(prop->name->str, "fwd") == 0) 319 add_frag_mblock(prop->d.arc.node); 320 } 321 } 322 323 void 324 add_frag_mblock(struct md_node *node) 325 { 326 uint64_t base, size; 327 struct guest *guest; 328 329 md_get_prop_val(hvmd, node, "base", &base); 330 md_get_prop_val(hvmd, node, "size", &size); 331 while (size > fragsize) { 332 add_frag(base); 333 size -= fragsize; 334 base += fragsize; 335 } 336 337 delete_frag(hv_mdpa); 338 TAILQ_FOREACH(guest, &guests, link) 339 delete_frag(guest->mdpa); 340 } 341 342 void 343 add_frag(uint64_t base) 344 { 345 struct frag *frag; 346 347 frag = xmalloc(sizeof(*frag)); 348 frag->base = base; 349 TAILQ_INSERT_TAIL(&free_frags, frag, link); 350 } 351 352 void 353 delete_frag(uint64_t base) 354 { 355 struct frag *frag; 356 struct frag *tmp; 357 358 TAILQ_FOREACH_SAFE(frag, &free_frags, link, tmp) { 359 if (frag->base == base) { 360 TAILQ_REMOVE(&free_frags, frag, link); 361 free(frag); 362 } 363 } 364 } 365 366 uint64_t 367 alloc_frag(void) 368 { 369 struct frag *frag; 370 uint64_t base; 371 372 frag = TAILQ_FIRST(&free_frags); 373 if (frag == NULL) 374 return -1; 375 376 TAILQ_REMOVE(&free_frags, frag, link); 377 base = frag->base; 378 free(frag); 379 380 return base; 381 } 382 383 void 384 hv_update_md(struct guest *guest) 385 { 386 struct hvctl_msg msg; 387 size_t nbytes; 388 void *buf; 389 size_t size; 390 uint64_t mdpa; 391 392 hv_open(); 393 394 mdpa = alloc_frag(); 395 size = md_exhume(guest->md, &buf); 396 hv_write(mdpa, buf, size); 397 add_frag(guest->mdpa); 398 guest->mdpa = mdpa; 399 free(buf); 400 401 md_set_prop_val(hvmd, guest->node, "mdpa", guest->mdpa); 402 403 mdpa = alloc_frag(); 404 size = md_exhume(hvmd, &buf); 405 hv_write(mdpa, buf, size); 406 add_frag(hv_mdpa); 407 hv_mdpa = mdpa; 408 free(buf); 409 410 /* Update config. */ 411 bzero(&msg, sizeof(msg)); 412 msg.hdr.op = HVCTL_OP_RECONFIGURE; 413 msg.hdr.seq = hvctl_seq++; 414 msg.msg.reconfig.guestid = -1; 415 msg.msg.reconfig.hvmdp = hv_mdpa; 416 nbytes = write(hvctl_fd, &msg, sizeof(msg)); 417 if (nbytes != sizeof(msg)) 418 fatal("write"); 419 420 bzero(&msg, sizeof(msg)); 421 nbytes = read(hvctl_fd, &msg, sizeof(msg)); 422 if (nbytes != sizeof(msg)) 423 fatal("read"); 424 425 hv_close(); 426 427 if (msg.hdr.status != HVCTL_ST_OK) 428 logit(LOG_CRIT, "reconfigure failed: %d", msg.hdr.status); 429 } 430 431 void 432 hv_open(void) 433 { 434 struct hvctl_msg msg; 435 ssize_t nbytes; 436 uint64_t code; 437 438 hvctl_fd = open("/dev/hvctl", O_RDWR, 0); 439 if (hvctl_fd == -1) 440 fatal("cannot open /dev/hvctl"); 441 442 /* 443 * Say "Hello". 444 */ 445 bzero(&msg, sizeof(msg)); 446 msg.hdr.op = HVCTL_OP_HELLO; 447 msg.hdr.seq = hvctl_seq++; 448 msg.msg.hello.major = 1; 449 nbytes = write(hvctl_fd, &msg, sizeof(msg)); 450 if (nbytes != sizeof(msg)) 451 fatal("write"); 452 453 bzero(&msg, sizeof(msg)); 454 nbytes = read(hvctl_fd, &msg, sizeof(msg)); 455 if (nbytes != sizeof(msg)) 456 fatal("read"); 457 458 code = msg.msg.clnge.code ^ 0xbadbeef20; 459 460 /* 461 * Respond to challenge. 462 */ 463 bzero(&msg, sizeof(msg)); 464 msg.hdr.op = HVCTL_OP_RESPONSE; 465 msg.hdr.seq = hvctl_seq++; 466 msg.msg.clnge.code = code ^ 0x12cafe42a; 467 nbytes = write(hvctl_fd, &msg, sizeof(msg)); 468 if (nbytes != sizeof(msg)) 469 fatal("write"); 470 471 bzero(&msg, sizeof(msg)); 472 nbytes = read(hvctl_fd, &msg, sizeof(msg)); 473 if (nbytes != sizeof(msg)) 474 fatal("read"); 475 } 476 477 void 478 hv_close(void) 479 { 480 close(hvctl_fd); 481 hvctl_fd = -1; 482 } 483 484 void 485 hv_read(uint64_t addr, void *buf, size_t len) 486 { 487 struct hv_io hi; 488 489 hi.hi_cookie = addr; 490 hi.hi_addr = buf; 491 hi.hi_len = len; 492 493 if (ioctl(hvctl_fd, HVIOCREAD, &hi) == -1) 494 fatal("ioctl"); 495 } 496 497 void 498 hv_write(uint64_t addr, void *buf, size_t len) 499 { 500 struct hv_io hi; 501 502 hi.hi_cookie = addr; 503 hi.hi_addr = buf; 504 hi.hi_len = len; 505 506 if (ioctl(hvctl_fd, HVIOCWRITE, &hi) == -1) 507 fatal("ioctl"); 508 } 509