dm: support VMs communication with virtio-console

Add feature that client uos can still connect to server uos after
rebooting.

Tracked-On: #3459
Signed-off-by: Gao Junhao <junhao.gao@intel.com>
Reviewed-by: Jian Jun Chen <jian.jun.chen@intel.com>
Acked-by: Yu Wang <yu1.wang@intel.com>
This commit is contained in:
Gao Junhao 2019-07-18 08:44:45 +00:00 committed by ACRN System Integration
parent 18ecdc123a
commit ff299d5c50
1 changed files with 67 additions and 35 deletions

View File

@ -109,7 +109,9 @@ struct virtio_console_port {
struct virtio_console_backend {
struct virtio_console_port *port;
struct mevent *evp;
struct mevent *conn_evp;
int fd;
int server_fd;
bool open;
enum virtio_console_be_type be_type;
int pts_fd; /* only valid for PTY */
@ -428,6 +430,19 @@ virtio_console_reset_backend(struct virtio_console_backend *be)
be->open = false;
}
static void
virtio_console_socket_clear(struct virtio_console_backend *be)
{
if (be->conn_evp) {
mevent_delete(be->conn_evp);
be->conn_evp = NULL;
}
if (be->fd != -1) {
close(be->fd);
be->fd = -1;
}
}
static void
virtio_console_backend_read(int fd __attribute__((unused)),
enum ev_type t __attribute__((unused)),
@ -470,6 +485,11 @@ virtio_console_backend_read(int fd __attribute__((unused)),
if (len == -1 && errno == EAGAIN)
return;
/* when client uos reboot or shutdown,
* be->fd will be closed, then the return
* value of readv function will be 0 */
if (len == 0 || errno == ECONNRESET)
goto clear;
/* any other errors */
goto close;
}
@ -478,11 +498,22 @@ virtio_console_backend_read(int fd __attribute__((unused)),
} while (vq_has_descs(vq));
vq_endchains(vq, 1);
return;
close:
virtio_console_reset_backend(be);
WPRINTF(("vtcon: be read failed and close! len = %d, errno = %d\n",
len, errno));
clear:
if (be->be_type == VIRTIO_CONSOLE_BE_SOCKET && (be->socket_type == NULL
|| !strcmp(be->socket_type,"server"))) {
virtio_console_socket_clear(be);
} else if (be->be_type == VIRTIO_CONSOLE_BE_SOCKET
&& !strcmp(be->socket_type,"client")) {
virtio_console_reset_backend(be);
WPRINTF(("vtcon: be read failed and close! len = %d, errno = %d\n",
len, errno));
}
}
static void
@ -517,6 +548,13 @@ virtio_console_backend_write(struct virtio_console_port *port, void *arg,
if (ret == -1 && (errno == EAGAIN || errno == ENOTCONN))
return;
if (ret == -1 && errno == EBADF) {
if (be->be_type == VIRTIO_CONSOLE_BE_SOCKET && (be->socket_type == NULL
|| !strcmp(be->socket_type,"server"))) {
virtio_console_socket_clear(be);
return;
}
}
virtio_console_reset_backend(be);
WPRINTF(("vtcon: be write failed! errno = %d\n", errno));
}
@ -617,7 +655,6 @@ virtio_console_accept_new_connection(int fd __attribute__((unused)),
{
int accepted_fd;
int close_true;
uint32_t len;
struct sockaddr_un addr;
struct virtio_console_backend *be = arg;
@ -628,30 +665,18 @@ virtio_console_accept_new_connection(int fd __attribute__((unused)),
addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
len = sizeof(addr);
accepted_fd = accept(be->fd, (struct sockaddr *)&addr, &len);
/* be->server_fd is kept for client uos reconnect again */
accepted_fd = accept(be->server_fd, (struct sockaddr *)&addr, &len);
if (accepted_fd == -1) {
WPRINTF(("accept error= %d, addr.sun_path=%s\n", errno, addr.sun_path));
return;
} else {
/* close the fd associated with listening socket
* and reuse it for accepted socket.
*/
close_true = 1;
setsockopt(be->fd, SOL_SOCKET, SO_REUSEADDR, &close_true, sizeof(int));
close(be->fd);
be->fd = accepted_fd;
}
if (be->evp) {
/* close the event associated with listening socket
* and reuse it for accepted socket.
*/
mevent_delete(be->evp);
}
be->evp = mevent_add(be->fd, EVF_READ, virtio_console_backend_read, be,
virtio_console_teardown_backend, be);
if (be->evp == NULL) {
be->conn_evp = mevent_add(be->fd, EVF_READ, virtio_console_backend_read, be,
NULL, NULL);
if (be->conn_evp == NULL) {
WPRINTF(("accepted fd mevent_add failed\n"));
return;
}
@ -745,21 +770,11 @@ virtio_console_config_backend(struct virtio_console_backend *be)
WPRINTF(("Backend config: fcntl Error\n"));
return -1;
}
be->evp = mevent_add(fd, EVF_READ, virtio_console_accept_new_connection, be, NULL, NULL);
if (be->evp == NULL) {
WPRINTF(("Socket Accept mevent_add failed\n"));
return -1;
}
} else if (!strcmp(be->socket_type,"client")) {
if (access(be->portpath,0)) {
WPRINTF(("%s not exist\n", be->portpath));
return -1;
}
/*
* When the VM reset, client will not able to connect to server.
* But here only show some warning.
* TODO: implement re-connect function
*/
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
WPRINTF(("vtcon: connect error[%d] \n", errno));
} else {
@ -866,6 +881,7 @@ virtio_console_add_backend(struct virtio_console *console, char *opt)
}
be->fd = fd;
be->server_fd = fd;
be->be_type = be_type;
be->portpath = portpath;
be->socket_type = socket_type;
@ -885,17 +901,24 @@ virtio_console_add_backend(struct virtio_console *console, char *opt)
}
if (virtio_console_backend_can_read(be_type)) {
if (isatty(fd)) {
if (be->be_type == VIRTIO_CONSOLE_BE_SOCKET && (be->socket_type == NULL
|| !strcmp(be->socket_type,"server"))) {
be->evp = mevent_add(fd, EVF_READ,
virtio_console_accept_new_connection, be,
virtio_console_teardown_backend, be);
}
else if (isatty(fd) || (be->be_type == VIRTIO_CONSOLE_BE_SOCKET
&& !strcmp(be->socket_type,"client"))) {
be->evp = mevent_add(fd, EVF_READ,
virtio_console_backend_read, be,
virtio_console_teardown_backend, be);
if (be->evp == NULL) {
WPRINTF(("vtcon: mevent_add failed\n"));
error = -1;
goto out;
}
console->ref_count++;
}
if (be->evp == NULL) {
WPRINTF(("vtcon: mevent_add failed\n"));
error = -1;
goto out;
}
console->ref_count++;
}
virtio_console_open_port(be->port, true);
@ -952,6 +975,15 @@ virtio_console_close_backend(struct virtio_console_backend *be)
case VIRTIO_CONSOLE_BE_STDIO:
virtio_console_restore_stdio();
break;
case VIRTIO_CONSOLE_BE_SOCKET:
if (be->socket_type == NULL || !strcmp(be->socket_type,"server")) {
virtio_console_socket_clear(be);
if (be->server_fd > 0) {
close(be->server_fd);
be->server_fd = -1;
}
}
break;
default:
break;
}