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