Skip to content

Commit

Permalink
src/vhost.c: allow working with qemu as a vhost server.
Browse files Browse the repository at this point in the history
  • Loading branch information
outscale-fne committed Nov 9, 2020
1 parent db56b17 commit 9c2ff75
Show file tree
Hide file tree
Showing 6 changed files with 360 additions and 152 deletions.
20 changes: 14 additions & 6 deletions src/utils/qemu.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ int pg_util_spawn_qemu(const char *socket_path_0,
const char *socket_path_1,
const char *mac_0,
const char *mac_1,
const int is_client_0,
const int is_client_1,
const char *vm_image_path,
const char *vm_key_path,
const char *hugepages_path,
Expand All @@ -81,35 +83,41 @@ int pg_util_spawn_qemu(const char *socket_path_0,
pg_autofree char *argv_qemu = NULL;
const char *argv_sock_0 = "";
const char *argv_sock_1 = "";
const char *server_params = ",server,nowait";
pg_autofree char *argv_sock_0_t = NULL;
pg_autofree char *argv_sock_1_t = NULL;
pg_autofree char *ssh_cmd = NULL;
GError *error = NULL;

g_assert(g_file_test(socket_path_0, G_FILE_TEST_EXISTS));
if (socket_path_1)
if (!is_client_1)
g_assert(g_file_test(socket_path_0, G_FILE_TEST_EXISTS));
if (socket_path_1 && !is_client_1)
g_assert(g_file_test(socket_path_1, G_FILE_TEST_EXISTS));
g_assert(g_file_test(vm_image_path, G_FILE_TEST_EXISTS));
g_assert(g_file_test(vm_key_path, G_FILE_TEST_EXISTS));
g_assert(g_file_test(hugepages_path, G_FILE_TEST_EXISTS));

if (socket_path_0) {
argv_sock_0_t = g_strdup_printf(
PG_STRCAT(" -chardev socket,id=char0,path=%s",
PG_STRCAT(" -chardev socket,id=char0,path=%s%s",
" -netdev type=vhost-user,id=mynet0,",
"chardev=char0,vhostforce",
" -device virtio-net-pci,mac=%s",
",netdev=mynet0"), socket_path_0, mac_0);
",netdev=mynet0"), socket_path_0,
is_client_0 ? server_params : "",
mac_0);
argv_sock_0 = argv_sock_0_t;
}

if (socket_path_1) {
argv_sock_1_t = g_strdup_printf(
PG_STRCAT(" -chardev socket,id=char1,path=%s",
PG_STRCAT(" -chardev socket,id=char1,path=%s%s",
" -netdev type=vhost-user,id=mynet1,",
"chardev=char1,vhostforce",
" -device virtio-net-pci,mac=%s",
",netdev=mynet1"), socket_path_1, mac_1);
",netdev=mynet1"), socket_path_1,
is_client_0 ? server_params : "",
mac_1);
argv_sock_1 = argv_sock_1_t;
}

Expand Down
2 changes: 2 additions & 0 deletions src/utils/qemu.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ int pg_util_spawn_qemu(const char *socket_path_0,
const char *socket_path_1,
const char *mac_0,
const char *mac_1,
const int is_server_0,
const int is_server_1,
const char *vm_image_path,
const char *vm_ssh_key_path,
const char *hugepages_path,
Expand Down
167 changes: 76 additions & 91 deletions src/vhost.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ struct pg_vhost_state {
struct pg_vhost_socket *socket;
rte_atomic32_t allow_queuing;
int vid;
uint64_t flags;
struct rte_mbuf *in[PG_MAX_PKTS_BURST];
struct rte_mbuf *out[PG_MAX_PKTS_BURST];
PG_PKTS_COUNT_TYPE tx_bytes; /* TX: [vhost] --> VM */
Expand All @@ -94,20 +95,18 @@ struct pg_vhost_state {
#endif
};

static int new_vm(int dev);
static void destroy_vm(int dev);
static int on_new_device(int dev);
static void on_destroy_device(int dev);

static const struct vhost_device_ops virtio_net_device_ops = {
.new_device = new_vm,
.destroy_device = destroy_vm,
.new_device = on_new_device,
.destroy_device = on_destroy_device,
};

/* head of the socket list */
static LIST_HEAD(socket_list, pg_vhost_socket) sockets;
static char *sockets_path;
static int vhost_start_ok;
static int disable_freacture_mask;
static int enable_freacture_mask;

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

Expand All @@ -125,6 +124,22 @@ static struct pg_brick_config *vhost_config_new(const char *name,
return pg_brick_config_init(config, name, 1, 1, PG_MONOPOLE);
}

/**
* This function tell whether the targeted brick is
* acting as vhost server or not.
*
* @param brick the brick vhost brick targeted.
* @return 0 if acting as server else 1.
*/
static int pg_vhost_is_server(struct pg_brick *brick)
{
struct pg_vhost_state *state =
pg_brick_get_state(brick,
struct pg_vhost_state);

return state->flags & PG_VHOST_USER_CLIENT;
}

static int vhost_burst(struct pg_brick *brick, enum pg_side from,
uint16_t edge_index, struct rte_mbuf **pkts,
uint64_t pkts_mask, struct pg_error **errp)
Expand Down Expand Up @@ -259,15 +274,15 @@ static int vhost_poll(struct pg_brick *brick, uint16_t *pkts_cnt,
}

#ifndef RTE_VHOST_USER_CLIENT
#define RTE_VHOST_USER_CLIENT 0
#define RTE_VHOST_USER_CLIENT (1ULL << 0)
#endif

#ifndef RTE_VHOST_USER_NO_RECONNECT
#define RTE_VHOST_USER_NO_RECONNECT 0
#define RTE_VHOST_USER_NO_RECONNECT (1ULL << 1)
#endif

#ifndef RTE_VHOST_USER_DEQUEUE_ZERO_COPY
#define RTE_VHOST_USER_DEQUEUE_ZERO_COPY 0
#define RTE_VHOST_USER_DEQUEUE_ZERO_COPY (1ULL << 2)
#endif

static void vhost_create_socket(struct pg_vhost_state *state, uint64_t flags,
Expand All @@ -278,7 +293,9 @@ static void vhost_create_socket(struct pg_vhost_state *state, uint64_t flags,
int ret;

path = g_strdup_printf("%s/qemu-%s", sockets_path, state->brick.name);
g_remove(path);
/* If the socket is CLIENT do NOT destroy the socket. */
if (flags & 1 == 0)
g_remove(path);

printf("New vhost-user socket: %s, zero-copy %s\n", path,
(flags & RTE_VHOST_USER_DEQUEUE_ZERO_COPY) ?
Expand Down Expand Up @@ -326,48 +343,6 @@ static void vhost_create_socket(struct pg_vhost_state *state, uint64_t flags,
g_free(path);
}

#define VHOST_NOT_READY \
"vhost not ready, did you called vhost_start after packetgraph_start ?"

static int vhost_init(struct pg_brick *brick, struct pg_brick_config *config,
struct pg_error **errp)
{
struct pg_vhost_state *state;
struct pg_vhost_config *vhost_config;

state = pg_brick_get_state(brick, struct pg_vhost_state);
if (!vhost_start_ok) {
*errp = pg_error_new(VHOST_NOT_READY);
return -1;
}

vhost_config = (struct pg_vhost_config *) config->brick_config;
state->output = vhost_config->output;
state->vid = -1;
PG_PKTS_COUNT_SET(state->rx_bytes, 0);
PG_PKTS_COUNT_SET(state->tx_bytes, 0);
pg_vhost_enable(brick, enable_freacture_mask);
pg_vhost_disable(brick, disable_freacture_mask);

vhost_create_socket(state, vhost_config->flags, errp);
if (pg_error_is_set(errp))
return -1;

brick->burst = vhost_burst;
brick->poll = vhost_poll;

rte_atomic32_init(&state->allow_queuing);
rte_atomic32_set(&state->allow_queuing, 1);
#ifdef PG_VHOST_FASTER_YET_BROKEN_POLL
state->check_atomic = 1024;
state->check_counter = 0;
#endif /* PG_VHOST_FASTER_YET_BROKEN_POLL */

return 0;
}

#undef VHOST_NOT_READY

static enum pg_side vhost_get_side(struct pg_brick *brick)
{
struct pg_vhost_state *state =
Expand All @@ -389,13 +364,16 @@ struct pg_brick *pg_vhost_new(const char *name, uint64_t flags,

static void vhost_destroy(struct pg_brick *brick, struct pg_error **errp)
{
struct pg_vhost_state *state;

state = pg_brick_get_state(brick, struct pg_vhost_state);
struct pg_vhost_state *state =
pg_brick_get_state(brick, struct pg_vhost_state);
rte_vhost_driver_unregister(state->socket->path);

pthread_mutex_lock(&mutex);
g_remove(state->socket->path);

/* If the socket is client, do NOT destroy the existing socket. */
if (pg_vhost_is_server(brick) == 0)
g_remove(state->socket->path);

LIST_REMOVE(state->socket, socket_list);
g_free(state->socket->path);
g_free(state->socket);
Expand Down Expand Up @@ -425,7 +403,7 @@ static uint64_t tx_bytes(struct pg_brick *brick)
pg_brick_get_state(brick, struct pg_vhost_state)->tx_bytes);
}

static int new_vm(int dev)
static int on_new_device(int dev)
{
struct pg_vhost_socket *s = NULL;
char buf[256];
Expand All @@ -448,7 +426,7 @@ static int new_vm(int dev)
return 0;
}

static void destroy_vm(int dev)
static void on_destroy_device(int dev)
{
struct pg_vhost_socket *s = NULL;
char buf[256];
Expand All @@ -472,11 +450,50 @@ static void destroy_vm(int dev)
break;
}
}

pthread_mutex_unlock(&mutex);
}

#define VHOST_NOT_READY \
"vhost not ready, did you called vhost_start after packetgraph_start ?"

static int vhost_init(struct pg_brick *brick, struct pg_brick_config *config,
struct pg_error **errp)
{
struct pg_vhost_state *state;
struct pg_vhost_config *vhost_config;

state = pg_brick_get_state(brick, struct pg_vhost_state);
if (!vhost_start_ok) {
*errp = pg_error_new(VHOST_NOT_READY);
return -1;
}

vhost_config = (struct pg_vhost_config *) config->brick_config;
state->output = vhost_config->output;
state->vid = -1;
state->flags = vhost_config->flags;
PG_PKTS_COUNT_SET(state->rx_bytes, 0);
PG_PKTS_COUNT_SET(state->tx_bytes, 0);
vhost_create_socket(state, vhost_config->flags, errp);
if (pg_error_is_set(errp))
return -1;

brick->burst = vhost_burst;
brick->poll = vhost_poll;

rte_atomic32_init(&state->allow_queuing);
rte_atomic32_set(&state->allow_queuing, 1);
#ifdef PG_VHOST_FASTER_YET_BROKEN_POLL
state->check_atomic = 1024;
state->check_counter = 0;
#endif /* PG_VHOST_FASTER_YET_BROKEN_POLL */

return 0;
}

#undef VHOST_NOT_READY


/**
* Check that the socket path exists and has the right perm and store it
*
Expand Down Expand Up @@ -542,38 +559,6 @@ int pg_vhost_start(const char *base_dir, struct pg_error **errp)
return 0;
}

int pg_vhost_global_enable(uint64_t feature_mask)
{
enable_freacture_mask |= feature_mask;
return 0;
}

int pg_vhost_global_disable(uint64_t feature_mask)
{
disable_freacture_mask |= feature_mask;
return 0;
}

int pg_vhost_enable(struct pg_brick *brick, uint64_t feature_mask)
{
const char *path = pg_vhost_socket_path(brick);

if (unlikely(!path))
return -1;
return rte_vhost_driver_enable_features(path,
feature_mask) ? -1 : 0;
}

int pg_vhost_disable(struct pg_brick *brick, uint64_t feature_mask)
{
const char *path = pg_vhost_socket_path(brick);

if (unlikely(!path))
return -1;
return rte_vhost_driver_disable_features(path,
feature_mask) ? -1 : 0;
}

static void vhost_link(struct pg_brick *brick, enum pg_side side, int edge)
{
struct pg_vhost_state *state =
Expand Down
1 change: 1 addition & 0 deletions tests/integration/tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ static inline int start_qemu_graph(struct branch *branch,
int qemu_pid = pg_util_spawn_qemu(sock_path_graph(branch),
sock_read_path_graph(branch),
tmp_mac, mac_reader,
0,0,
glob_vm_path,
glob_vm_key_path,
glob_hugepages_path, errp);
Expand Down
1 change: 1 addition & 0 deletions tests/vhost/bench-vhost.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ void test_benchmark_vhost(char *vm_image_path,
qemu_pid = pg_util_spawn_qemu(socket_path_enter,
socket_path_exit,
mac1_str, mac2_str,
0,0,
vm_image_path, vm_ssh_key_path,
hugepages_path, &error);
g_assert(!error);
Expand Down
Loading

0 comments on commit 9c2ff75

Please sign in to comment.