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