Skip to content

Commit

Permalink
dm: vm_event: add vm_event support in cmd monitor
Browse files Browse the repository at this point in the history
This patch added vm_event support in command monitor, so that vm_event
can be sent to a client (e.g., Libvirt) through the monitor.
As the command monitor works in socket server mode, the vm_event sending
process is designed in this way:
1. If a client wishes to receive vm_event, it issues a
   REGISTER_VM_EVENT_CLIENT command to the monitor.
2. Command monitor then handles the REGISTER_VM_EVENT_CLIENT command. If
   it is legitimate, the client is registered as as vm_event receiver.
   The command monitor then send a ACK to the client, and keeps the socket
   connection.
3. When a vm_event is generated, the command monitor send it out through
   the socket connection.
4. Only one event client is allowed.
5. The registration is cancelled on socket disconnection.

Tracked-On: projectacrn#8547
Signed-off-by: Wu Zhou <wu.zhou@intel.com>
Reviewed-by: Jian Jun Chen <jian.jun.chen@intel.com>
  • Loading branch information
izhouwu committed Jan 19, 2024
1 parent 6a13b10 commit e84048c
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 4 deletions.
1 change: 1 addition & 0 deletions devicemodel/core/cmd_monitor/cmd_monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ static void register_socket_message_handlers(struct vmctx *ctx)
register_command_handler(user_vm_destroy_handler, &arg, DESTROY);
register_command_handler(user_vm_blkrescan_handler, &arg, BLKRESCAN);
register_command_handler(user_vm_jack_event_handler, &arg, JACKCONNECT);
register_command_handler(user_vm_register_vm_event_client_handler, &arg, REGISTER_VM_EVENT_CLIENT);
}

int init_cmd_monitor(struct vmctx *ctx)
Expand Down
1 change: 1 addition & 0 deletions devicemodel/core/cmd_monitor/command.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
GEN_CMD_OBJ(DESTROY), \
GEN_CMD_OBJ(BLKRESCAN), \
GEN_CMD_OBJ(JACKCONNECT), \
GEN_CMD_OBJ(REGISTER_VM_EVENT_CLIENT), \

struct command dm_command_list[CMDS_NUM] = {CMD_OBJS};

Expand Down
3 changes: 2 additions & 1 deletion devicemodel/core/cmd_monitor/command.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@
#define DESTROY "destroy"
#define BLKRESCAN "blkrescan"
#define JACKCONNECT "jack_connect"
#define REGISTER_VM_EVENT_CLIENT "register_vm_event_client"

#define CMDS_NUM 3U
#define CMDS_NUM 4U
#define CMD_NAME_MAX 32U
#define CMD_ARG_MAX 320U

Expand Down
72 changes: 72 additions & 0 deletions devicemodel/core/cmd_monitor/command_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,78 @@ static int send_socket_ack(struct socket_dev *sock, int fd, bool normal)
return ret;
}

static struct socket_client *vm_event_client = NULL;
static pthread_mutex_t vm_event_client_mutex = PTHREAD_MUTEX_INITIALIZER;

static void vm_event_free_cb(struct socket_client *self)
{
vm_event_client = NULL;
}

static int set_vm_event_client(struct socket_client *client)
{
if (vm_event_client != NULL) {
pr_err("vm event client already registerred.\n");
return -1;
} else {
vm_event_client = client;
client->per_client_mutex = &vm_event_client_mutex;
client->free_client_cb = vm_event_free_cb;
return 0;
}
}

int vm_monitor_send_vm_event(const char *msg)
{
int ret = -1;
struct socket_client *client;
pthread_mutex_t *per_client_mutex = &vm_event_client_mutex;

pthread_mutex_lock(per_client_mutex);
client = vm_event_client;
if (msg == NULL || client == NULL) {
pthread_mutex_unlock(per_client_mutex);
return -1;
}
memset(client->buf, 0, CLIENT_BUF_LEN);
memcpy(client->buf, msg, strlen(msg));
client->len = strlen(msg);
ret = write_socket_char(client);
pthread_mutex_unlock(per_client_mutex);
return ret;
}

/* When a client issues the REGISTER_VM_EVENT_CLIENT command,
* this handler will register that client as this VM's only vm_event receiver,
* and keeps the socket connection. Then vm events will be sent to
* the client through this connection.
*/
int user_vm_register_vm_event_client_handler(void *arg, void *command_para)
{
int ret;
struct command_parameters *cmd_para = (struct command_parameters *)command_para;
struct handler_args *hdl_arg = (struct handler_args *)arg;
struct socket_dev *sock = (struct socket_dev *)hdl_arg->channel_arg;
struct socket_client *client = NULL;
bool cmd_completed = false;

client = find_socket_client(sock, cmd_para->fd);
if (client == NULL)
return -1;

if (set_vm_event_client(client) == 0) {
cmd_completed = true;
}

pr_dbg("%s: client with fd %d registerred\n", __func__, client->fd);

ret = send_socket_ack(sock, cmd_para->fd, cmd_completed);
if (ret < 0) {
pr_err("%s: Failed to send ACK message by socket.\n", __func__);
}
return ret;
}

int user_vm_destroy_handler(void *arg, void *command_para)
{
int ret;
Expand Down
2 changes: 2 additions & 0 deletions devicemodel/core/cmd_monitor/command_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ extern struct socket_dev *sock_server;
int user_vm_destroy_handler(void *arg, void *command_para);
int user_vm_blkrescan_handler(void *arg, void *command_para);
int user_vm_jack_event_handler(void *arg, void *command_para);
int user_vm_register_vm_event_client_handler(void *arg, void *command_para);

#endif
14 changes: 12 additions & 2 deletions devicemodel/core/cmd_monitor/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,23 @@ static int setup_and_listen_unix_socket(const char *sock_path, int num)
}
static void free_socket_client(struct socket_dev *sock, struct socket_client *client)
{
pthread_mutex_t *per_client_mutex = client->per_client_mutex;
pthread_mutex_lock(&sock->client_mtx);
LIST_REMOVE(client, list);
pthread_mutex_unlock(&sock->client_mtx);

if (per_client_mutex) {
pthread_mutex_lock(per_client_mutex);
}
if (client->free_client_cb) {
client->free_client_cb(client);
}
close(client->fd);
client->fd = -1;
free(client);
if (per_client_mutex) {
pthread_mutex_unlock(per_client_mutex);
}
}

int write_socket_char(struct socket_client *client)
Expand Down Expand Up @@ -142,7 +152,8 @@ static struct socket_client *new_socket_client(struct socket_dev *sock)
__func__);
goto alloc_client;
}

/* If per client mutex is needed, init in callback */
client->per_client_mutex = NULL;
client->addr_len = sizeof(client->addr);
client->fd =
accept(sock->sock_fd, (struct sockaddr *)&client->addr,
Expand All @@ -153,7 +164,6 @@ static struct socket_client *new_socket_client(struct socket_dev *sock)
__func__, sock->sock_fd, strerror(errno));
goto accept_con;
}

pthread_mutex_lock(&sock->client_mtx);
LIST_INSERT_HEAD(&sock->client_head, client, list);
pthread_mutex_unlock(&sock->client_mtx);
Expand Down
6 changes: 5 additions & 1 deletion devicemodel/core/cmd_monitor/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ struct socket_client {
socklen_t addr_len;
char buf[CLIENT_BUF_LEN];
int len; /* buf len */

/* When a client is registered as vm_event receiver, we need this per_client_mutex
* to make sure it is safe to free the client when client disconnects.
*/
pthread_mutex_t *per_client_mutex;
void (*free_client_cb)(struct socket_client *self);
LIST_ENTRY(socket_client) list;
};

Expand Down
3 changes: 3 additions & 0 deletions devicemodel/include/monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,7 @@ unsigned get_wakeup_reason(void);
int set_wakeup_timer(time_t t);
int acrn_parse_intr_monitor(const char *opt);
int vm_monitor_blkrescan(void *arg, char *devargs);

int vm_monitor_send_vm_event(const char *msg);

#endif

0 comments on commit e84048c

Please sign in to comment.