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