xref: /illumos-gate/usr/src/cmd/ldmad/ldmad.c (revision 826ac02a0def83e0a41b29321470d299c7389aab)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * Logical Domains (LDoms) Agents Daemon
28  *
29  * The LDoms agents daemon (ldmad) runs on LDoms domains and provides
30  * information to the control domain. It is composed of a set of agents
31  * which can send and receive messages to and from the control domain.
32  * Each agent is registered as a domain service using the libds library,
33  * and is able to handle requests coming from the control domain.
34  *
35  * The control domain sends requests to an agent as messages on the
36  * corresponding domain service (identified by the agent name). All requests
37  * are received by the ldmad daemon which dispatches them to the appropriate
38  * handler function of the agent depending on the type of the message.
39  *
40  * After the request has been processed by the handler, the ldmad daemon sent
41  * a reply message back to the control domain. The reply is either a result
42  * message if the request was successfully completed, or an error message
43  * describing the failure.
44  */
45 
46 #include <dirent.h>
47 #include <errno.h>
48 #include <fcntl.h>
49 #include <libds.h>
50 #include <libgen.h>
51 #include <signal.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <strings.h>
55 #include <synch.h>
56 #include <syslog.h>
57 #include <thread.h>
58 #include <unistd.h>
59 #include <sys/debug.h>
60 #include <sys/ldoms.h>
61 #include <sys/types.h>
62 #include <sys/stat.h>
63 #include <sys/wait.h>
64 
65 #include "ldma.h"
66 
67 #define	LDMA_MODULE	"ldm-agent-daemon"
68 
69 #define	LDMA_CONTROL_DOMAIN_DHDL	0	/* id of the control domain */
70 
71 typedef struct ldma_connexion_t {
72 	ds_hdl_t		hdl;		/* connexion handle */
73 	ds_domain_hdl_t		dhdl;		/* connexion domain handle */
74 	ds_ver_t		ver;		/* connexion version */
75 } ldma_connexion_t;
76 
77 typedef struct ldma_agent {
78 	ldma_agent_info_t	*info;		/* agent information */
79 	mutex_t			conn_lock;	/* connexion table lock */
80 	ldma_connexion_t	conn[LDOMS_MAX_DOMAINS]; /* connexions */
81 } ldma_agent_t;
82 
83 /* information about existing agents */
84 extern ldma_agent_info_t ldma_device_info;
85 extern ldma_agent_info_t ldma_system_info;
86 extern ldma_agent_info_t ldma_dio_info;
87 
88 boolean_t ldma_debug = B_FALSE;
89 boolean_t ldma_daemon = B_FALSE;
90 
91 static ldma_agent_info_t *ldma_agent_infos[] = {
92 	&ldma_device_info,
93 	&ldma_system_info,
94 	&ldma_dio_info,
95 	NULL
96 };
97 
98 static char *cmdname;
99 static pid_t daemon_pid = 0;
100 
101 /*
102  * Lookup connexion in agent connexion table.
103  */
104 static ldma_connexion_t *
105 ldma_connexion_lookup(ldma_agent_t *agent, ds_hdl_t hdl)
106 {
107 	ldma_connexion_t *connp;
108 	int i;
109 
110 	ASSERT(MUTEX_HELD(&agent->conn_lock));
111 	for (connp = agent->conn, i = 0; i < LDOMS_MAX_DOMAINS; i++, connp++) {
112 		if (connp->hdl == hdl)
113 			return (connp);
114 	}
115 	return (NULL);
116 }
117 
118 /*
119  * Add connextion to agent connexion table.
120  */
121 static int
122 ldma_connexion_add(ldma_agent_t *agent, ds_hdl_t hdl, ds_domain_hdl_t dhdl,
123     ds_ver_t *verp)
124 {
125 	ldma_connexion_t *connp;
126 	ldma_connexion_t *availp = NULL;
127 	int i;
128 
129 	(void) mutex_lock(&agent->conn_lock);
130 	for (connp = agent->conn, i = 0; i < LDOMS_MAX_DOMAINS; i++, connp++) {
131 		if (connp->hdl == hdl)
132 			break;
133 		if (availp == NULL && connp->hdl == DS_INVALID_HDL)
134 			availp = connp;
135 	}
136 
137 	if (i < LDOMS_MAX_DOMAINS) {
138 		(void) mutex_unlock(&agent->conn_lock);
139 		LDMA_INFO("agent %s hdl %llx already exists", agent->info->name,
140 		    hdl);
141 		return (0);
142 	}
143 
144 	if (!availp) {
145 		(void) mutex_unlock(&agent->conn_lock);
146 		LDMA_INFO("agent %s too many connections", agent->info->name);
147 		return (0);
148 	}
149 
150 	LDMA_DBG("agent %s adding connection (%x) %llx, %llx, %d.%d",
151 	    agent->info->name, availp, hdl, dhdl, verp->major, verp->minor);
152 
153 	availp->hdl = hdl;
154 	availp->dhdl = dhdl;
155 	availp->ver = *verp;
156 	(void) mutex_unlock(&agent->conn_lock);
157 	return (1);
158 }
159 
160 /*
161  * Delete connexion from agent connexion table.
162  */
163 static int
164 ldma_connexion_delete(ldma_agent_t *agent, ds_hdl_t hdl)
165 {
166 	ldma_connexion_t *connp;
167 
168 	(void) mutex_lock(&agent->conn_lock);
169 	if ((connp = ldma_connexion_lookup(agent, hdl)) == NULL) {
170 		(void) mutex_unlock(&agent->conn_lock);
171 		LDMA_INFO("agent %s connection delete failed to find %llx",
172 		    agent->info->name, hdl);
173 		return (0);
174 	}
175 
176 	LDMA_DBG("agent %s deleting connection (%x) %llx", agent->info->name,
177 	    connp, hdl);
178 
179 	connp->hdl = DS_INVALID_HDL;
180 	connp->dhdl = 0;
181 	connp->ver.major = 0;
182 	connp->ver.minor = 0;
183 	(void) mutex_unlock(&agent->conn_lock);
184 	return (1);
185 }
186 
187 /*
188  * Initialize connexion table.
189  */
190 static void
191 ldma_connexion_init(ldma_agent_t *agent)
192 {
193 	ldma_connexion_t *connp;
194 	int i;
195 
196 	for (connp = agent->conn, i = 0; i < LDOMS_MAX_DOMAINS; i++, connp++) {
197 		connp->hdl = DS_INVALID_HDL;
198 	}
199 }
200 
201 /*
202  * Allocate a new message with the specified message number (msg_num),
203  * message type (msg_type) and message data length (msg_dlen). Return
204  * NULL if the allocation has failed.
205  */
206 static ldma_message_header_t *
207 ldma_alloc_msg(uint64_t msg_num, uint32_t msg_type, size_t msg_dlen)
208 {
209 	ldma_message_header_t *msg;
210 	size_t msg_len;
211 
212 	msg_len = LDMA_MESSAGE_SIZE(msg_dlen);
213 	msg = malloc(msg_len);
214 	if (msg == NULL)
215 		return (NULL);
216 
217 	msg->msg_num = msg_num;
218 	msg->msg_type = msg_type;
219 	msg->msg_info = 0;
220 
221 	return (msg);
222 }
223 
224 /*
225  * Allocate a result message (LDMA_MSG_REQ_RESULT) with the specified message
226  * data length (msg_dlen). If the request argument is not NULL then the message
227  * is created with the same message number as the request, otherwise the message
228  * number is set to 0. Return NULL if the allocation has failed.
229  */
230 ldma_message_header_t *
231 ldma_alloc_result_msg(ldma_message_header_t *request, size_t msg_dlen)
232 {
233 	uint64_t msg_num;
234 
235 	msg_num = (request == NULL)? 0 : request->msg_num;
236 
237 	return (ldma_alloc_msg(msg_num, LDMA_MSG_RESULT, msg_dlen));
238 }
239 
240 /*
241  * Agent register callback. This callback is invoked when a client is registered
242  * for using the service provided by an agent. An agent will only have one
243  * consumer which is coming from the control domain.
244  */
245 static void
246 ldma_reg_cb(ds_hdl_t hdl, ds_cb_arg_t arg, ds_ver_t *ver,
247     ds_domain_hdl_t dhdl)
248 {
249 	ldma_agent_t *agent = (ldma_agent_t *)arg;
250 	char dname[LDOMS_MAX_NAME_LEN];
251 
252 	if (ds_dom_hdl_to_name(dhdl, dname, LDOMS_MAX_NAME_LEN) != 0) {
253 		(void) strcpy(dname, "<unknown>");
254 	}
255 
256 	LDMA_DBG("%s: REGISTER hdl=%llx, dhdl=%llx (%s) ver=%hd.%hd",
257 	    agent->info->name, hdl, dhdl, dname, ver->major, ver->minor);
258 
259 	/*
260 	 * Record client information.  Access control is done on a
261 	 * message-by-message basis upon receipt of the message.
262 	 */
263 	if (!ldma_connexion_add(agent, hdl, dhdl, ver)) {
264 		LDMA_INFO("agent %s failed to add connection from "
265 		    "domain %s", agent->info->name, dname);
266 	}
267 }
268 
269 /*
270  * Agent unregister callback. This callback is invoked when a client is
271  * unregistered and stops using the service provided by an agent.
272  */
273 static void
274 ldma_unreg_cb(ds_hdl_t hdl, ds_cb_arg_t arg)
275 {
276 	ldma_agent_t *agent = (ldma_agent_t *)arg;
277 
278 	LDMA_DBG("%s: UNREGISTER hdl=%llx", agent->info->name, hdl);
279 
280 	if (!ldma_connexion_delete(agent, hdl)) {
281 		LDMA_INFO("agent %s failed to unregister handle %llx",
282 		    agent->info->name, hdl);
283 	}
284 }
285 
286 /*
287  * Agent data callback. This callback is invoked when an agent receives a new
288  * message from a client. Any request from a client which is not the control
289  * domain is immediatly rejected. Otherwise the message is forwarded to the
290  * appropriate handler function provided by the agent, depending on the message
291  * type.
292  */
293 static void
294 ldma_data_cb(ds_hdl_t hdl, ds_cb_arg_t arg, void *buf, size_t len)
295 {
296 	ldma_agent_t *agent = (ldma_agent_t *)arg;
297 	ldma_msg_handler_t *handler;
298 	ldma_message_header_t *request = buf;
299 	ldma_message_header_t *reply = NULL;
300 	ldma_connexion_t *connp;
301 	ds_ver_t conn_ver;
302 	ds_domain_hdl_t conn_dhdl;
303 	ldma_request_status_t status;
304 	size_t request_dlen, reply_len, reply_dlen = 0;
305 	int i;
306 
307 	/* check the message size */
308 	if (len < LDMA_MESSAGE_HEADER_SIZE) {
309 		LDMA_INFO("agent %s has ignored message with an invalid "
310 		    "size of %d bytes", agent->info->name, len);
311 		return;
312 	}
313 
314 	request_dlen = LDMA_MESSAGE_DLEN(len);
315 
316 	LDMA_DBG("%s: DATA hdl=%llx, request num=%llu type=0x%x info=0x%x "
317 	    "dlen=%d", agent->info->name, hdl, request->msg_num,
318 	    request->msg_type, request->msg_info, request_dlen);
319 
320 	(void) mutex_lock(&agent->conn_lock);
321 	connp = ldma_connexion_lookup(agent, hdl);
322 	if (connp != NULL) {
323 		conn_dhdl = connp->dhdl;
324 		conn_ver = connp->ver;
325 	}
326 	(void) mutex_unlock(&agent->conn_lock);
327 
328 	/* reject any request which is not in the connexion table */
329 	if (connp == NULL) {
330 		LDMA_DBG("%s: DATA hdl=%llx, rejecting request from a "
331 		    "distrusted domain", agent->info->name, hdl);
332 		status = LDMA_REQ_DENIED;
333 		goto do_reply;
334 	}
335 
336 	handler = NULL;
337 
338 	for (i = 0; i < agent->info->nhandlers; i++) {
339 		if (agent->info->handlers[i].msg_type == request->msg_type) {
340 			handler = &agent->info->handlers[i];
341 			break;
342 		}
343 	}
344 
345 	if (handler == NULL) {
346 		/* this type of message is not defined by the agent */
347 		LDMA_DBG("%s: DATA hdl=%llx, unknown message type %x",
348 		    agent->info->name, hdl, request->msg_type);
349 		status = LDMA_REQ_NOTSUP;
350 		goto do_reply;
351 	}
352 
353 	/* reject any request from a guest which is not allowed */
354 	if ((conn_dhdl != LDMA_CONTROL_DOMAIN_DHDL) &&
355 	    (handler->msg_flags & LDMA_MSGFLG_ACCESS_ANY) == 0) {
356 		LDMA_DBG("%s: DATA hdl=%llx, rejecting request from a "
357 		    "distrusted domain", agent->info->name, hdl);
358 		status = LDMA_REQ_DENIED;
359 		goto do_reply;
360 	}
361 
362 	if (handler->msg_handler == NULL) {
363 		/*
364 		 * This type of message is defined by the agent but it
365 		 * has no handler. That means there is no processing to
366 		 * do, the message is just ignored, but the request is
367 		 * successfully completed.
368 		 */
369 		LDMA_DBG("%s: DATA hdl=%llx, no handler",
370 		    agent->info->name, hdl);
371 		status = LDMA_REQ_COMPLETED;
372 		goto do_reply;
373 	}
374 
375 	/* invoke the message handler of the agent */
376 	status = (*handler->msg_handler)(&conn_ver, request, request_dlen,
377 	    &reply, &reply_dlen);
378 
379 	LDMA_DBG("%s: DATA hdl=%llx, handler stat=%d reply=%p rlen=%d",
380 	    agent->info->name, hdl, status, (void *)reply, reply_dlen);
381 
382 do_reply:
383 	/*
384 	 * If the handler has provided a reply message, we use it directly.
385 	 * Otherwise, we build a reply depending on the status of the request.
386 	 * In that case, we re-use the request buffer to build the reply
387 	 * message.
388 	 */
389 	if (reply == NULL) {
390 
391 		reply = request;
392 		reply_dlen = 0;
393 
394 		if (status == LDMA_REQ_COMPLETED) {
395 			/*
396 			 * The request was successful but no result message was
397 			 * provided so we send an empty result message.
398 			 */
399 			reply->msg_type = LDMA_MSG_RESULT;
400 			reply->msg_info = 0;
401 
402 		} else {
403 			/*
404 			 * The request has failed but no error message was
405 			 * provided so we send an error message based on the
406 			 * request status.
407 			 */
408 			reply->msg_type = LDMA_MSG_ERROR;
409 			reply->msg_info =
410 			    (status == LDMA_REQ_NOTSUP)? LDMA_MSGERR_NOTSUP :
411 			    (status == LDMA_REQ_INVALID)? LDMA_MSGERR_INVALID :
412 			    (status == LDMA_REQ_DENIED)? LDMA_MSGERR_DENY :
413 			    LDMA_MSGERR_FAIL;
414 		}
415 	}
416 
417 	reply_len = LDMA_MESSAGE_SIZE(reply_dlen);
418 
419 	LDMA_DBG("%s: DATA hdl=%llx, reply num=%llu type=0x%x info=0x%x "
420 	    "dlen=%d", agent->info->name, hdl, reply->msg_num,
421 	    reply->msg_type, reply->msg_info, reply_dlen);
422 
423 	if (ds_send_msg(hdl, reply, reply_len) != 0) {
424 		LDMA_ERR("agent %s has failed to send reply for request %llu",
425 		    agent->info->name, request->msg_num);
426 	}
427 
428 	if (reply != request)
429 		free(reply);
430 }
431 
432 /*
433  * Register an agent. Return 0 if the agent was successfully registered.
434  */
435 static int
436 ldma_register(ldma_agent_info_t *agent_info)
437 {
438 	ldma_agent_t	*agent;
439 	ds_capability_t	ds_cap;
440 	ds_ops_t	ds_ops;
441 
442 	agent = malloc(sizeof (ldma_agent_t));
443 	if (agent == NULL)
444 		goto register_fail;
445 
446 	agent->info = agent_info;
447 	(void) mutex_init(&agent->conn_lock, USYNC_THREAD, NULL);
448 	ldma_connexion_init(agent);
449 
450 	ds_cap.svc_id = agent_info->name;
451 	ds_cap.vers = agent_info->vers;
452 	ds_cap.nvers = agent_info->nvers;
453 
454 	ds_ops.ds_reg_cb = ldma_reg_cb;
455 	ds_ops.ds_unreg_cb = ldma_unreg_cb;
456 	ds_ops.ds_data_cb = ldma_data_cb;
457 	ds_ops.cb_arg = agent;
458 
459 	if (ds_svc_reg(&ds_cap, &ds_ops) == 0) {
460 		LDMA_INFO("agent %s registered", agent_info->name);
461 		return (0);
462 	}
463 
464 register_fail:
465 
466 	LDMA_ERR("agent %s has failed to register", agent_info->name);
467 	free(agent);
468 	return (-1);
469 }
470 
471 /*
472  * Register all known agents. Return the number of agents successfully
473  * registered.
474  */
475 static int
476 ldma_register_agents()
477 {
478 	int count = 0;
479 	ldma_agent_info_t **agent_infop;
480 
481 	for (agent_infop = ldma_agent_infos;
482 	    *agent_infop != NULL; agent_infop++) {
483 
484 		if (ldma_register(*agent_infop) == 0)
485 			count++;
486 	}
487 
488 	return (count);
489 }
490 
491 /*ARGSUSED*/
492 static void
493 ldma_sigusr_handler(int sig, siginfo_t *sinfo, void *ucontext)
494 {
495 	/*
496 	 * The child process can send the signal before the fork()
497 	 * call has returned in the parent process. So daemon_pid
498 	 * may not be set yet, and we don't check the pid in that
499 	 * case.
500 	 */
501 	if (sig != SIGUSR1 || sinfo->si_code != SI_USER ||
502 	    (daemon_pid > 0 && sinfo->si_pid != daemon_pid))
503 		return;
504 
505 	/*
506 	 * The parent process has received a USR1 signal from the child.
507 	 * This means that the daemon has correctly started and the parent
508 	 * can exit.
509 	 */
510 	exit(0);
511 }
512 
513 static void
514 ldma_start(boolean_t standalone)
515 {
516 	int stat, rv;
517 	struct sigaction action;
518 
519 	if (!standalone) {
520 		/*
521 		 * Some configuration of the daemon has to be done in the
522 		 * child, but we want the parent to report if the daemon
523 		 * has successfully started or not. So we setup a signal
524 		 * handler, and the child will notify the parent using the
525 		 * USR1 signal if the setup was successful. Otherwise the
526 		 * child will exit.
527 		 */
528 		action.sa_sigaction = ldma_sigusr_handler;
529 		action.sa_flags = SA_SIGINFO;
530 
531 		if (sigemptyset(&action.sa_mask) == -1) {
532 			LDMA_ERR("sigemptyset error (%d)", errno);
533 			exit(1);
534 		}
535 
536 		if (sigaction(SIGUSR1, &action, NULL) == -1) {
537 			LDMA_ERR("sigaction() error (%d)", errno);
538 			exit(1);
539 		}
540 
541 		if (sigrelse(SIGUSR1) == -1) {
542 			LDMA_ERR("sigrelse() error (%d)", errno);
543 			exit(1);
544 		}
545 
546 		if ((daemon_pid = fork()) == -1) {
547 			LDMA_ERR("fork() error (%d)", errno);
548 			exit(1);
549 		}
550 
551 		if (daemon_pid != 0) {
552 			/*
553 			 * The parent process waits until the child exits (in
554 			 * case of an error) or sends a USR1 signal (if the
555 			 * daemon has correctly started).
556 			 */
557 			for (;;) {
558 				rv = waitpid(daemon_pid, &stat, 0);
559 				if ((rv == daemon_pid && WIFEXITED(stat)) ||
560 				    (rv == -1 && errno != EINTR)) {
561 					/* child has exited or error */
562 					exit(1);
563 				}
564 			}
565 		}
566 
567 		/*
568 		 * Initialize child process
569 		 */
570 		if (sighold(SIGUSR1) == -1) {
571 			LDMA_ERR("sighold error (%d)", errno);
572 			exit(1);
573 		}
574 
575 		if (sigignore(SIGUSR1) == -1) {
576 			LDMA_ERR("sigignore error (%d)", errno);
577 			exit(1);
578 		}
579 
580 		if (setsid() == -1) {
581 			LDMA_ERR("setsid error (%d)", errno);
582 			exit(1);
583 		}
584 
585 		if (chdir("/") == -1) {
586 			LDMA_ERR("chdir error (%d)", errno);
587 			exit(1);
588 		}
589 		(void) umask(0);
590 
591 		/*
592 		 * Initialize file descriptors. Do not touch stderr
593 		 * which is initialized by SMF to point to the daemon
594 		 * specific log file.
595 		 */
596 		(void) close(STDIN_FILENO);
597 		if (open("/dev/null", O_RDWR) == -1) {
598 			LDMA_ERR("open /dev/null error (%d)", errno);
599 			exit(1);
600 		}
601 		if (dup2(STDIN_FILENO, STDOUT_FILENO) == -1) {
602 			LDMA_ERR("dup2 error (%d)", errno);
603 			exit(1);
604 		}
605 		closefrom(STDERR_FILENO + 1);
606 
607 		/* initialize logging */
608 		openlog(cmdname, LOG_CONS | LOG_NDELAY, LOG_DAEMON);
609 
610 		ldma_daemon = B_TRUE;
611 	}
612 
613 	/*
614 	 * Register the agents. It would be easier to do this before
615 	 * daemonizing so that any start error is directly reported. But
616 	 * this can not be done because agents are registered using libds
617 	 * and this will subscribe the daemon to some sysevents which is
618 	 * a process based subscription. Instead we notify the parent process
619 	 * either by exiting, or by sending a SIGUSR1 signal.
620 	 */
621 	if (ldma_register_agents() == 0) {
622 		/* no agent registered */
623 		LDMA_ERR("Unable to register any agent");
624 		exit(1);
625 	}
626 
627 	if (!standalone) {
628 		/* signal parent that startup was successful */
629 		if (kill(getppid(), SIGUSR1) == -1)
630 			exit(1);
631 	}
632 }
633 
634 static void
635 ldma_usage()
636 {
637 	(void) fprintf(stderr, "usage: %s\n", cmdname);
638 }
639 
640 int
641 main(int argc, char *argv[])
642 {
643 	int opt;
644 	boolean_t standalone = B_FALSE;
645 
646 	cmdname = basename(argv[0]);
647 
648 	/* disable getopt error messages */
649 	opterr = 0;
650 
651 	while ((opt = getopt(argc, argv, "ds")) != EOF) {
652 
653 		switch (opt) {
654 		case 'd':
655 			ldma_debug = B_TRUE;
656 			break;
657 		case 's':
658 			standalone = B_TRUE;
659 			break;
660 		default:
661 			ldma_usage();
662 			exit(1);
663 		}
664 	}
665 
666 	ldma_start(standalone);
667 
668 	/*
669 	 * Loop forever. Any incoming message will be received by libds and
670 	 * forwarded to the agent data callback (ldma_data_cb()) where it
671 	 * will be processed.
672 	 */
673 	for (;;) {
674 		(void) pause();
675 	}
676 
677 	/*NOTREACHED*/
678 	return (0);
679 }
680