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.
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.
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]
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Logical Domains (LDoms) Agents Daemon
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.
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.
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.
59 #include <sys/debug.h>
60 #include <sys/ldoms.h>
61 #include <sys/types.h>
67 #define LDMA_MODULE "ldm-agent-daemon"
69 #define LDMA_CONTROL_DOMAIN_DHDL 0 /* id of the control domain */
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 */
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 */
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
;
88 boolean_t ldma_debug
= B_FALSE
;
89 boolean_t ldma_daemon
= B_FALSE
;
91 static ldma_agent_info_t
*ldma_agent_infos
[] = {
99 static pid_t daemon_pid
= 0;
102 * Lookup connexion in agent connexion table.
104 static ldma_connexion_t
*
105 ldma_connexion_lookup(ldma_agent_t
*agent
, ds_hdl_t hdl
)
107 ldma_connexion_t
*connp
;
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
)
119 * Add connextion to agent connexion table.
122 ldma_connexion_add(ldma_agent_t
*agent
, ds_hdl_t hdl
, ds_domain_hdl_t dhdl
,
125 ldma_connexion_t
*connp
;
126 ldma_connexion_t
*availp
= NULL
;
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
)
133 if (availp
== NULL
&& connp
->hdl
== DS_INVALID_HDL
)
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
,
145 (void) mutex_unlock(&agent
->conn_lock
);
146 LDMA_INFO("agent %s too many connections", agent
->info
->name
);
150 LDMA_DBG("agent %s adding connection (%x) %llx, %llx, %d.%d",
151 agent
->info
->name
, availp
, hdl
, dhdl
, verp
->major
, verp
->minor
);
156 (void) mutex_unlock(&agent
->conn_lock
);
161 * Delete connexion from agent connexion table.
164 ldma_connexion_delete(ldma_agent_t
*agent
, ds_hdl_t hdl
)
166 ldma_connexion_t
*connp
;
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
);
176 LDMA_DBG("agent %s deleting connection (%x) %llx", agent
->info
->name
,
179 connp
->hdl
= DS_INVALID_HDL
;
181 connp
->ver
.major
= 0;
182 connp
->ver
.minor
= 0;
183 (void) mutex_unlock(&agent
->conn_lock
);
188 * Initialize connexion table.
191 ldma_connexion_init(ldma_agent_t
*agent
)
193 ldma_connexion_t
*connp
;
196 for (connp
= agent
->conn
, i
= 0; i
< LDOMS_MAX_DOMAINS
; i
++, connp
++) {
197 connp
->hdl
= DS_INVALID_HDL
;
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.
206 static ldma_message_header_t
*
207 ldma_alloc_msg(uint64_t msg_num
, uint32_t msg_type
, size_t msg_dlen
)
209 ldma_message_header_t
*msg
;
212 msg_len
= LDMA_MESSAGE_SIZE(msg_dlen
);
213 msg
= malloc(msg_len
);
217 msg
->msg_num
= msg_num
;
218 msg
->msg_type
= msg_type
;
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.
230 ldma_message_header_t
*
231 ldma_alloc_result_msg(ldma_message_header_t
*request
, size_t msg_dlen
)
235 msg_num
= (request
== NULL
)? 0 : request
->msg_num
;
237 return (ldma_alloc_msg(msg_num
, LDMA_MSG_RESULT
, msg_dlen
));
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.
246 ldma_reg_cb(ds_hdl_t hdl
, ds_cb_arg_t arg
, ds_ver_t
*ver
,
247 ds_domain_hdl_t dhdl
)
249 ldma_agent_t
*agent
= (ldma_agent_t
*)arg
;
250 char dname
[LDOMS_MAX_NAME_LEN
];
252 if (ds_dom_hdl_to_name(dhdl
, dname
, LDOMS_MAX_NAME_LEN
) != 0) {
253 (void) strcpy(dname
, "<unknown>");
256 LDMA_DBG("%s: REGISTER hdl=%llx, dhdl=%llx (%s) ver=%hd.%hd",
257 agent
->info
->name
, hdl
, dhdl
, dname
, ver
->major
, ver
->minor
);
260 * Record client information. Access control is done on a
261 * message-by-message basis upon receipt of the message.
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
);
270 * Agent unregister callback. This callback is invoked when a client is
271 * unregistered and stops using the service provided by an agent.
274 ldma_unreg_cb(ds_hdl_t hdl
, ds_cb_arg_t arg
)
276 ldma_agent_t
*agent
= (ldma_agent_t
*)arg
;
278 LDMA_DBG("%s: UNREGISTER hdl=%llx", agent
->info
->name
, hdl
);
280 if (!ldma_connexion_delete(agent
, hdl
)) {
281 LDMA_INFO("agent %s failed to unregister handle %llx",
282 agent
->info
->name
, hdl
);
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
294 ldma_data_cb(ds_hdl_t hdl
, ds_cb_arg_t arg
, void *buf
, size_t len
)
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
;
302 ds_domain_hdl_t conn_dhdl
;
303 ldma_request_status_t status
;
304 size_t request_dlen
, reply_len
, reply_dlen
= 0;
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
);
314 request_dlen
= LDMA_MESSAGE_DLEN(len
);
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
);
320 (void) mutex_lock(&agent
->conn_lock
);
321 connp
= ldma_connexion_lookup(agent
, hdl
);
323 conn_dhdl
= connp
->dhdl
;
324 conn_ver
= connp
->ver
;
326 (void) mutex_unlock(&agent
->conn_lock
);
328 /* reject any request which is not in the connexion table */
330 LDMA_DBG("%s: DATA hdl=%llx, rejecting request from a "
331 "distrusted domain", agent
->info
->name
, hdl
);
332 status
= LDMA_REQ_DENIED
;
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
];
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
;
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
;
362 if (handler
->msg_handler
== NULL
) {
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.
369 LDMA_DBG("%s: DATA hdl=%llx, no handler",
370 agent
->info
->name
, hdl
);
371 status
= LDMA_REQ_COMPLETED
;
375 /* invoke the message handler of the agent */
376 status
= (*handler
->msg_handler
)(&conn_ver
, request
, request_dlen
,
377 &reply
, &reply_dlen
);
379 LDMA_DBG("%s: DATA hdl=%llx, handler stat=%d reply=%p rlen=%d",
380 agent
->info
->name
, hdl
, status
, (void *)reply
, reply_dlen
);
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
394 if (status
== LDMA_REQ_COMPLETED
) {
396 * The request was successful but no result message was
397 * provided so we send an empty result message.
399 reply
->msg_type
= LDMA_MSG_RESULT
;
404 * The request has failed but no error message was
405 * provided so we send an error message based on the
408 reply
->msg_type
= LDMA_MSG_ERROR
;
410 (status
== LDMA_REQ_NOTSUP
)? LDMA_MSGERR_NOTSUP
:
411 (status
== LDMA_REQ_INVALID
)? LDMA_MSGERR_INVALID
:
412 (status
== LDMA_REQ_DENIED
)? LDMA_MSGERR_DENY
:
417 reply_len
= LDMA_MESSAGE_SIZE(reply_dlen
);
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
);
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
);
428 if (reply
!= request
)
433 * Register an agent. Return 0 if the agent was successfully registered.
436 ldma_register(ldma_agent_info_t
*agent_info
)
439 ds_capability_t ds_cap
;
442 agent
= malloc(sizeof (ldma_agent_t
));
446 agent
->info
= agent_info
;
447 (void) mutex_init(&agent
->conn_lock
, USYNC_THREAD
, NULL
);
448 ldma_connexion_init(agent
);
450 ds_cap
.svc_id
= agent_info
->name
;
451 ds_cap
.vers
= agent_info
->vers
;
452 ds_cap
.nvers
= agent_info
->nvers
;
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
;
459 if (ds_svc_reg(&ds_cap
, &ds_ops
) == 0) {
460 LDMA_INFO("agent %s registered", agent_info
->name
);
466 LDMA_ERR("agent %s has failed to register", agent_info
->name
);
472 * Register all known agents. Return the number of agents successfully
476 ldma_register_agents()
479 ldma_agent_info_t
**agent_infop
;
481 for (agent_infop
= ldma_agent_infos
;
482 *agent_infop
!= NULL
; agent_infop
++) {
484 if (ldma_register(*agent_infop
) == 0)
493 ldma_sigusr_handler(int sig
, siginfo_t
*sinfo
, void *ucontext
)
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
501 if (sig
!= SIGUSR1
|| sinfo
->si_code
!= SI_USER
||
502 (daemon_pid
> 0 && sinfo
->si_pid
!= daemon_pid
))
506 * The parent process has received a USR1 signal from the child.
507 * This means that the daemon has correctly started and the parent
514 ldma_start(boolean_t standalone
)
517 struct sigaction action
;
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
528 action
.sa_sigaction
= ldma_sigusr_handler
;
529 action
.sa_flags
= SA_SIGINFO
;
531 if (sigemptyset(&action
.sa_mask
) == -1) {
532 LDMA_ERR("sigemptyset error (%d)", errno
);
536 if (sigaction(SIGUSR1
, &action
, NULL
) == -1) {
537 LDMA_ERR("sigaction() error (%d)", errno
);
541 if (sigrelse(SIGUSR1
) == -1) {
542 LDMA_ERR("sigrelse() error (%d)", errno
);
546 if ((daemon_pid
= fork()) == -1) {
547 LDMA_ERR("fork() error (%d)", errno
);
551 if (daemon_pid
!= 0) {
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).
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 */
568 * Initialize child process
570 if (sighold(SIGUSR1
) == -1) {
571 LDMA_ERR("sighold error (%d)", errno
);
575 if (sigignore(SIGUSR1
) == -1) {
576 LDMA_ERR("sigignore error (%d)", errno
);
580 if (setsid() == -1) {
581 LDMA_ERR("setsid error (%d)", errno
);
585 if (chdir("/") == -1) {
586 LDMA_ERR("chdir error (%d)", errno
);
592 * Initialize file descriptors. Do not touch stderr
593 * which is initialized by SMF to point to the daemon
596 (void) close(STDIN_FILENO
);
597 if (open("/dev/null", O_RDWR
) == -1) {
598 LDMA_ERR("open /dev/null error (%d)", errno
);
601 if (dup2(STDIN_FILENO
, STDOUT_FILENO
) == -1) {
602 LDMA_ERR("dup2 error (%d)", errno
);
605 closefrom(STDERR_FILENO
+ 1);
607 /* initialize logging */
608 openlog(cmdname
, LOG_CONS
| LOG_NDELAY
, LOG_DAEMON
);
610 ldma_daemon
= B_TRUE
;
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.
621 if (ldma_register_agents() == 0) {
622 /* no agent registered */
623 LDMA_ERR("Unable to register any agent");
628 /* signal parent that startup was successful */
629 if (kill(getppid(), SIGUSR1
) == -1)
637 (void) fprintf(stderr
, "usage: %s\n", cmdname
);
641 main(int argc
, char *argv
[])
644 boolean_t standalone
= B_FALSE
;
646 cmdname
= basename(argv
[0]);
648 /* disable getopt error messages */
651 while ((opt
= getopt(argc
, argv
, "ds")) != EOF
) {
666 ldma_start(standalone
);
669 * Loop forever. Any incoming message will be received by libds and
670 * forwarded to the agent data callback (ldma_data_cb()) where it