Skip to content

Commit

Permalink
Add support for VSOCK to engine/net.c
Browse files Browse the repository at this point in the history
* configure: add option to enable/disable vsock support

* engines/net.c: add vsock support

The  VSOCK  address family facilitates communication between virtual
machines and the host they are running on.

The addressing is formed by 2 integers: <CID, port>
- CID: Context ID, it is the ID assigned to the VM
  0, 1, 2 CIDs are reserved:
  0 - hypervisor CID (rarely used)
  1 - local communication (loopback)
  2 - host CID (the guest can always reach the host using CID=2)

- port: port number on 32bit to reach a specific process

* examples: add 3 simple job files for vsock (one sender, one receiver
  and one that uses vsock loopback interface similar to
  examples/netio.fio)

* fio.1: add vsock to supported protocols together with the required
  parameters

* HOWTO.rst: add vsock to supported protocols together with the required
  parameters

Signed-off-by: Marco Pinna <[email protected]>
  • Loading branch information
MPinna committed Feb 6, 2024
1 parent 625b155 commit cedf7ce
Show file tree
Hide file tree
Showing 7 changed files with 234 additions and 6 deletions.
7 changes: 5 additions & 2 deletions HOWTO.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2626,10 +2626,13 @@ with the caveat that when used on the command line, they must come after the
User datagram protocol V6.
**unix**
UNIX domain socket.
**vsock**
VSOCK protocol.

When the protocol is TCP or UDP, the port must also be given, as well as the
hostname if the job is a TCP listener or UDP reader. For unix sockets, the
When the protocol is TCP, UDP or VSOCK, the port must also be given, as well as the
hostname if the job is a TCP or VSOCK listener or UDP reader. For unix sockets, the
normal :option:`filename` option should be used and the port is invalid.
When the protocol is VSOCK, the :option:`hostname` is the CID of the remote VM.

.. option:: listen : [netsplice] [net]

Expand Down
22 changes: 22 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -1728,6 +1728,25 @@ elif compile_prog "" "-lws2_32" "TCP_NODELAY"; then
fi
print_config "TCP_NODELAY" "$tcp_nodelay"

##########################################
# Check whether we have vsock
if test "$vsock" != "yes" ; then
vsock="no"
fi
cat > $TMPC << EOF
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/vm_sockets.h>
int main(int argc, char **argv)
{
return socket(AF_VSOCK, SOCK_STREAM, 0);
}
EOF
if compile_prog "" "" "vsock"; then
vsock="yes"
fi
print_config "vsock" "$vsock"

##########################################
# Check whether we have SO_SNDBUF
if test "$window_size" != "yes" ; then
Expand Down Expand Up @@ -3192,6 +3211,9 @@ fi
if test "$ipv6" = "yes" ; then
output_sym "CONFIG_IPV6"
fi
if test "$vsock" = "yes"; then
output_sym "CONFIG_VSOCK"
fi
if test "$http" = "yes" ; then
output_sym "CONFIG_HTTP"
fi
Expand Down
149 changes: 147 additions & 2 deletions engines/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#include <sys/socket.h>
#include <sys/un.h>

#ifdef CONFIG_VSOCK
#include <linux/vm_sockets.h>
#endif

#include "../fio.h"
#include "../verify.h"
#include "../optgroup.h"
Expand All @@ -30,6 +34,9 @@ struct netio_data {
struct sockaddr_in addr;
struct sockaddr_in6 addr6;
struct sockaddr_un addr_un;
#ifdef CONFIG_VSOCK
struct sockaddr_vm addr_vm;
#endif
uint64_t udp_send_seq;
uint64_t udp_recv_seq;
};
Expand Down Expand Up @@ -69,6 +76,7 @@ enum {
FIO_TYPE_UNIX = 3,
FIO_TYPE_TCP_V6 = 4,
FIO_TYPE_UDP_V6 = 5,
FIO_TYPE_VSOCK_STREAM = 6,
};

static int str_hostname_cb(void *data, const char *input);
Expand Down Expand Up @@ -126,6 +134,12 @@ static struct fio_option options[] = {
.oval = FIO_TYPE_UNIX,
.help = "UNIX domain socket",
},
#ifdef CONFIG_VSOCK
{ .ival = "vsock",
.oval = FIO_TYPE_VSOCK_STREAM,
.help = "Virtual socket",
},
#endif
},
.category = FIO_OPT_C_ENGINE,
.group = FIO_OPT_G_NETIO,
Expand Down Expand Up @@ -223,6 +237,16 @@ static inline int is_ipv6(struct netio_options *o)
return o->proto == FIO_TYPE_UDP_V6 || o->proto == FIO_TYPE_TCP_V6;
}

static inline int is_vsock_stream(struct netio_options *o)
{
return o->proto == FIO_TYPE_VSOCK_STREAM;
}

static inline int is_vsock(struct netio_options *o)
{
return is_vsock_stream(o);
}

static int set_window_size(struct thread_data *td, int fd)
{
#ifdef CONFIG_NET_WINDOWSIZE
Expand Down Expand Up @@ -732,6 +756,11 @@ static int fio_netio_connect(struct thread_data *td, struct fio_file *f)
} else if (o->proto == FIO_TYPE_UNIX) {
domain = AF_UNIX;
type = SOCK_STREAM;
#ifdef CONFIG_VSOCK
} else if (o->proto == FIO_TYPE_VSOCK_STREAM) {
domain = AF_VSOCK;
type = SOCK_STREAM;
#endif
} else {
log_err("fio: bad network type %d\n", o->proto);
f->fd = -1;
Expand Down Expand Up @@ -809,7 +838,16 @@ static int fio_netio_connect(struct thread_data *td, struct fio_file *f)
close(f->fd);
return 1;
}
#ifdef CONFIG_VSOCK
} else if (o->proto == FIO_TYPE_VSOCK_STREAM) {
socklen_t len = sizeof(nd->addr_vm);

if (connect(f->fd, (struct sockaddr *) &nd->addr_vm, len) < 0) {
td_verror(td, errno, "connect");
close(f->fd);
return 1;
}
#endif
} else {
struct sockaddr_un *addr = &nd->addr_un;
socklen_t len;
Expand Down Expand Up @@ -849,6 +887,11 @@ static int fio_netio_accept(struct thread_data *td, struct fio_file *f)
if (o->proto == FIO_TYPE_TCP) {
socklen = sizeof(nd->addr);
f->fd = accept(nd->listenfd, (struct sockaddr *) &nd->addr, &socklen);
#ifdef CONFIG_VSOCK
} else if (o->proto == FIO_TYPE_VSOCK_STREAM) {
socklen = sizeof(nd->addr_vm);
f->fd = accept(nd->listenfd, (struct sockaddr *) &nd->addr_vm, &socklen);
#endif
} else {
socklen = sizeof(nd->addr6);
f->fd = accept(nd->listenfd, (struct sockaddr *) &nd->addr6, &socklen);
Expand Down Expand Up @@ -890,6 +933,11 @@ static void fio_netio_send_close(struct thread_data *td, struct fio_file *f)
if (is_ipv6(o)) {
to = (struct sockaddr *) &nd->addr6;
len = sizeof(nd->addr6);
#ifdef CONFIG_VSOCK
} else if (is_vsock(o)) {
to = NULL;
len = 0;
#endif
} else {
to = (struct sockaddr *) &nd->addr;
len = sizeof(nd->addr);
Expand Down Expand Up @@ -960,6 +1008,11 @@ static int fio_netio_send_open(struct thread_data *td, struct fio_file *f)
if (is_ipv6(o)) {
len = sizeof(nd->addr6);
to = (struct sockaddr *) &nd->addr6;
#ifdef CONFIG_VSOCK
} else if (is_vsock(o)) {
len = sizeof(nd->addr_vm);
to = (struct sockaddr *) &nd->addr_vm;
#endif
} else {
len = sizeof(nd->addr);
to = (struct sockaddr *) &nd->addr;
Expand Down Expand Up @@ -1023,13 +1076,17 @@ static int fio_fill_addr(struct thread_data *td, const char *host, int af,

memset(&hints, 0, sizeof(hints));

if (is_tcp(o))
if (is_tcp(o) || is_vsock(o))
hints.ai_socktype = SOCK_STREAM;
else
hints.ai_socktype = SOCK_DGRAM;

if (is_ipv6(o))
hints.ai_family = AF_INET6;
#ifdef CONFIG_VSOCK
else if (is_vsock(o))
hints.ai_family = AF_VSOCK;
#endif
else
hints.ai_family = AF_INET;

Expand Down Expand Up @@ -1110,12 +1167,49 @@ static int fio_netio_setup_connect_unix(struct thread_data *td,
return 0;
}

#ifdef CONFIG_VSOCK
static int fio_netio_setup_connect_vsock(struct thread_data *td,
const char *host, unsigned short port)
{
struct netio_data *nd = td->io_ops_data;
struct sockaddr_vm *addr = &nd->addr_vm;
int cid;

if (!host) {
log_err("fio: connect with no host to connect to.\n");
if (td_read(td))
log_err("fio: did you forget to set 'listen'?\n");

td_verror(td, EINVAL, "no hostname= set");
return 1;
}

addr->svm_family = AF_VSOCK;
addr->svm_port = port;

if (host) {
cid = atoi(host);
if (cid < VMADDR_CID_LOCAL || cid > UINT32_MAX) {
log_err("fio: invalid CID %d\n", cid);
return 1;
}
addr->svm_cid = cid;
}

return 0;
}
#endif

static int fio_netio_setup_connect(struct thread_data *td)
{
struct netio_options *o = td->eo;

if (is_udp(o) || is_tcp(o))
return fio_netio_setup_connect_inet(td, td->o.filename,o->port);
#ifdef CONFIG_VSOCK
else if (is_vsock(o))
return fio_netio_setup_connect_vsock(td, td->o.filename, o->port);
#endif
else
return fio_netio_setup_connect_unix(td, td->o.filename);
}
Expand Down Expand Up @@ -1268,6 +1362,48 @@ static int fio_netio_setup_listen_inet(struct thread_data *td, short port)
return 0;
}

#ifdef CONFIG_VSOCK
static int fio_netio_setup_listen_vsock(struct thread_data *td, short port)
{
struct netio_data *nd = td->io_ops_data;
struct sockaddr_vm *addr = &nd->addr_vm;
int fd, opt, type, domain;
socklen_t len;

type = SOCK_STREAM;
domain = AF_VSOCK;

fd = socket(domain, type, 0);
if (fd < 0) {
td_verror(td, errno, "socket");
return 1;
}

opt = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &opt, sizeof(opt)) < 0) {
td_verror(td, errno, "setsockopt");
close(fd);
return 1;
}

len = sizeof(*addr);

nd->addr_vm.svm_family = AF_VSOCK;
nd->addr_vm.svm_cid = VMADDR_CID_ANY;
nd->addr_vm.svm_port = port;

if (bind(fd, (struct sockaddr *) addr, len) < 0) {
close(fd);
td_verror(td, errno, "bind");
return 1;
}

nd->listenfd = fd;

return 0;
}
#endif

static int fio_netio_setup_listen(struct thread_data *td)
{
struct netio_data *nd = td->io_ops_data;
Expand All @@ -1276,6 +1412,10 @@ static int fio_netio_setup_listen(struct thread_data *td)

if (is_udp(o) || is_tcp(o))
ret = fio_netio_setup_listen_inet(td, o->port);
#ifdef CONFIG_VSOCK
else if (is_vsock(o))
ret = fio_netio_setup_listen_vsock(td, o->port);
#endif
else
ret = fio_netio_setup_listen_unix(td, td->o.filename);

Expand Down Expand Up @@ -1311,14 +1451,19 @@ static int fio_netio_init(struct thread_data *td)
if (o->proto == FIO_TYPE_UNIX && o->port) {
log_err("fio: network IO port not valid with unix socket\n");
return 1;
#ifdef CONFIG_VSOCK
} else if (o->proto == FIO_TYPE_VSOCK_STREAM && !o->port) {
log_err("fio: network IO requires port for vsock\n");
return 1;
#endif
} else if (o->proto != FIO_TYPE_UNIX && !o->port) {
log_err("fio: network IO requires port for tcp or udp\n");
return 1;
}

o->port += td->subjob_number;

if (!is_tcp(o)) {
if (!is_tcp(o) && !is_vsock_stream(o)) {
if (o->listen) {
log_err("fio: listen only valid for TCP proto IO\n");
return 1;
Expand Down
22 changes: 22 additions & 0 deletions examples/netio_vsock.fio
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Example network job, just defines two clients that send/recv data
[global]
ioengine=net

port=8888
protocol=vsock
bs=4k
size=100g

#set the below option to enable end-to-end data integrity tests
#verify=md5

[receiver]
listen
rw=read

[sender]
# 1 (VMADDR_CID_LOCAL) is the well-known address
# for local communication (loopback)
hostname=1
startdelay=1
rw=write
14 changes: 14 additions & 0 deletions examples/netio_vsock_receiver.fio
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Example network job, just defines a receiver
[global]
ioengine=net
port=8888
protocol=vsock
bs=4k
size=100g

#set the below option to enable end-to-end data integrity tests
#verify=md5

[receiver]
listen
rw=read
17 changes: 17 additions & 0 deletions examples/netio_vsock_sender.fio
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Example network job, just defines a sender
[global]
ioengine=net
port=8888
protocol=vsock
bs=4k
size=100g

#set the below option to enable end-to-end data integrity tests
#verify=md5

[sender]
# set the 'hostname' option to the CID of the listening domain
hostname=3
startdelay=1
rw=write

Loading

0 comments on commit cedf7ce

Please sign in to comment.