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
log_init(int n_debug)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
fatal(const char * emsg)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
logit(int pri,const char * fmt,...)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
vlog(int pri,const char * fmt,va_list ap)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
main(int argc,char ** argv)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
usage(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
add_guest(struct md_node * node)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
map_domain_services(struct md * md)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
frag_init(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
add_frag_mblock(struct md_node * node)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
add_frag(uint64_t base)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
delete_frag(uint64_t base)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
alloc_frag(void)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
hv_update_md(struct guest * guest)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
hv_open(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
hv_close(void)479 hv_close(void)
480 {
481 close(hvctl_fd);
482 hvctl_fd = -1;
483 }
484
485 void
hv_read(uint64_t addr,void * buf,size_t len)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
hv_write(uint64_t addr,void * buf,size_t len)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