xref: /openbsd-src/usr.sbin/ldomd/ldomd.c (revision b7041c0781c8668129da8084451ded41b0c43954)
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