static void net_vhost_user_event(void *opaque, int event) { const char *name = opaque; NetClientState *ncs[MAX_QUEUE_NUM]; VhostUserState *s; Error *err = NULL; int queues; queues = qemu_find_net_clients_except(name, ncs, NET_CLIENT_OPTIONS_KIND_NIC, MAX_QUEUE_NUM); assert(queues < MAX_QUEUE_NUM); s = DO_UPCAST(VhostUserState, nc, ncs[0]); trace_vhost_user_event(s->chr->label, event); switch (event) { case CHR_EVENT_OPENED: s->watch = qemu_chr_fe_add_watch(s->chr, G_IO_HUP, net_vhost_user_watch, s); if (vhost_user_start(queues, ncs) < 0) { qemu_chr_disconnect(s->chr); return; } qmp_set_link(name, true, &err); break; case CHR_EVENT_CLOSED: qmp_set_link(name, false, &err); vhost_user_stop(queues, ncs); g_source_remove(s->watch); s->watch = 0; break; } if (err) { error_report_err(err); } }
static void chr_read(void *opaque, const uint8_t *buf, int size) { TestServer *s = opaque; CharDriverState *chr = s->chr; VhostUserMsg msg; uint8_t *p = (uint8_t *) &msg; int fd; if (s->test_fail) { qemu_chr_disconnect(chr); /* now switch to non-failure */ s->test_fail = false; } if (size != VHOST_USER_HDR_SIZE) { g_test_message("Wrong message size received %d\n", size); return; } g_mutex_lock(&s->data_mutex); memcpy(p, buf, VHOST_USER_HDR_SIZE); if (msg.size) { p += VHOST_USER_HDR_SIZE; size = qemu_chr_fe_read_all(chr, p, msg.size); if (size != msg.size) { g_test_message("Wrong message size received %d != %d\n", size, msg.size); return; } } switch (msg.request) { case VHOST_USER_GET_FEATURES: /* send back features to qemu */ msg.flags |= VHOST_USER_REPLY_MASK; msg.size = sizeof(m.payload.u64); msg.payload.u64 = 0x1ULL << VHOST_F_LOG_ALL | 0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES; if (s->queues > 1) { msg.payload.u64 |= 0x1ULL << VIRTIO_NET_F_MQ; } if (s->test_flags >= TEST_FLAGS_BAD) { msg.payload.u64 = 0; s->test_flags = TEST_FLAGS_END; } p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); break; case VHOST_USER_SET_FEATURES: g_assert_cmpint(msg.payload.u64 & (0x1ULL << VHOST_USER_F_PROTOCOL_FEATURES), !=, 0ULL); if (s->test_flags == TEST_FLAGS_DISCONNECT) { qemu_chr_disconnect(chr); s->test_flags = TEST_FLAGS_BAD; } break; case VHOST_USER_GET_PROTOCOL_FEATURES: /* send back features to qemu */ msg.flags |= VHOST_USER_REPLY_MASK; msg.size = sizeof(m.payload.u64); msg.payload.u64 = 1 << VHOST_USER_PROTOCOL_F_LOG_SHMFD; if (s->queues > 1) { msg.payload.u64 |= 1 << VHOST_USER_PROTOCOL_F_MQ; } p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); break; case VHOST_USER_GET_VRING_BASE: /* send back vring base to qemu */ msg.flags |= VHOST_USER_REPLY_MASK; msg.size = sizeof(m.payload.state); msg.payload.state.num = 0; p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); assert(msg.payload.state.index < s->queues * 2); s->rings &= ~(0x1ULL << msg.payload.state.index); break; case VHOST_USER_SET_MEM_TABLE: /* received the mem table */ memcpy(&s->memory, &msg.payload.memory, sizeof(msg.payload.memory)); s->fds_num = qemu_chr_fe_get_msgfds(chr, s->fds, G_N_ELEMENTS(s->fds)); /* signal the test that it can continue */ g_cond_signal(&s->data_cond); break; case VHOST_USER_SET_VRING_KICK: case VHOST_USER_SET_VRING_CALL: /* consume the fd */ qemu_chr_fe_get_msgfds(chr, &fd, 1); /* * This is a non-blocking eventfd. * The receive function forces it to be blocking, * so revert it back to non-blocking. */ qemu_set_nonblock(fd); break; case VHOST_USER_SET_LOG_BASE: if (s->log_fd != -1) { close(s->log_fd); s->log_fd = -1; } qemu_chr_fe_get_msgfds(chr, &s->log_fd, 1); msg.flags |= VHOST_USER_REPLY_MASK; msg.size = 0; p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE); g_cond_signal(&s->data_cond); break; case VHOST_USER_SET_VRING_BASE: assert(msg.payload.state.index < s->queues * 2); s->rings |= 0x1ULL << msg.payload.state.index; break; case VHOST_USER_GET_QUEUE_NUM: msg.flags |= VHOST_USER_REPLY_MASK; msg.size = sizeof(m.payload.u64); msg.payload.u64 = s->queues; p = (uint8_t *) &msg; qemu_chr_fe_write_all(chr, p, VHOST_USER_HDR_SIZE + msg.size); break; default: break; } g_mutex_unlock(&s->data_mutex); }