Skip to content

Commit 45347e7

Browse files
jasowangmstsirkin
authored andcommitted
vhost_net: basic in_order support
This patch introduces basic in-order support for vhost-net. By recording the number of batched buffers in an array when calling `vhost_add_used_and_signal_n()`, we can reduce the number of userspace accesses. Note that the vhost-net batching logic is kept as we still count the number of buffers there. Testing Results: With testpmd: - TX: txonly mode + vhost_net with XDP_DROP on TAP shows a 17.5% improvement, from 4.75 Mpps to 5.35 Mpps. - RX: No obvious improvements were observed. With virtio-ring in-order experimental code in the guest: - TX: pktgen in the guest + XDP_DROP on TAP shows a 19% improvement, from 5.2 Mpps to 6.2 Mpps. - RX: pktgen on TAP with vhost_net + XDP_DROP in the guest achieves a 6.1% improvement, from 3.47 Mpps to 3.61 Mpps. Acked-by: Jonah Palmer <[email protected]> Acked-by: Eugenio Pérez <[email protected]> Signed-off-by: Jason Wang <[email protected]> Message-Id: <[email protected]> Signed-off-by: Michael S. Tsirkin <[email protected]> Tested-by: Lei Yang <[email protected]>
1 parent 67a873d commit 45347e7

File tree

1 file changed

+61
-25
lines changed

1 file changed

+61
-25
lines changed

drivers/vhost/net.c

Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ enum {
7474
(1ULL << VHOST_NET_F_VIRTIO_NET_HDR) |
7575
(1ULL << VIRTIO_NET_F_MRG_RXBUF) |
7676
(1ULL << VIRTIO_F_ACCESS_PLATFORM) |
77-
(1ULL << VIRTIO_F_RING_RESET)
77+
(1ULL << VIRTIO_F_RING_RESET) |
78+
(1ULL << VIRTIO_F_IN_ORDER)
7879
};
7980

8081
enum {
@@ -450,16 +451,17 @@ static int vhost_net_enable_vq(struct vhost_net *n,
450451
return vhost_poll_start(poll, sock->file);
451452
}
452453

453-
static void vhost_net_signal_used(struct vhost_net_virtqueue *nvq)
454+
static void vhost_net_signal_used(struct vhost_net_virtqueue *nvq,
455+
unsigned int count)
454456
{
455457
struct vhost_virtqueue *vq = &nvq->vq;
456458
struct vhost_dev *dev = vq->dev;
457459

458460
if (!nvq->done_idx)
459461
return;
460462

461-
vhost_add_used_and_signal_n(dev, vq, vq->heads, NULL,
462-
nvq->done_idx);
463+
vhost_add_used_and_signal_n(dev, vq, vq->heads,
464+
vq->nheads, count);
463465
nvq->done_idx = 0;
464466
}
465467

@@ -468,13 +470,20 @@ static void vhost_tx_batch(struct vhost_net *net,
468470
struct socket *sock,
469471
struct msghdr *msghdr)
470472
{
473+
struct vhost_virtqueue *vq = &nvq->vq;
474+
bool in_order = vhost_has_feature(vq, VIRTIO_F_IN_ORDER);
471475
struct tun_msg_ctl ctl = {
472476
.type = TUN_MSG_PTR,
473477
.num = nvq->batched_xdp,
474478
.ptr = nvq->xdp,
475479
};
476480
int i, err;
477481

482+
if (in_order) {
483+
vq->heads[0].len = 0;
484+
vq->nheads[0] = nvq->done_idx;
485+
}
486+
478487
if (nvq->batched_xdp == 0)
479488
goto signal_used;
480489

@@ -496,7 +505,7 @@ static void vhost_tx_batch(struct vhost_net *net,
496505
}
497506

498507
signal_used:
499-
vhost_net_signal_used(nvq);
508+
vhost_net_signal_used(nvq, in_order ? 1 : nvq->done_idx);
500509
nvq->batched_xdp = 0;
501510
}
502511

@@ -758,6 +767,7 @@ static void handle_tx_copy(struct vhost_net *net, struct socket *sock)
758767
int sent_pkts = 0;
759768
bool sock_can_batch = (sock->sk->sk_sndbuf == INT_MAX);
760769
bool busyloop_intr;
770+
bool in_order = vhost_has_feature(vq, VIRTIO_F_IN_ORDER);
761771

762772
do {
763773
busyloop_intr = false;
@@ -794,11 +804,13 @@ static void handle_tx_copy(struct vhost_net *net, struct socket *sock)
794804
break;
795805
}
796806

797-
/* We can't build XDP buff, go for single
798-
* packet path but let's flush batched
799-
* packets.
800-
*/
801-
vhost_tx_batch(net, nvq, sock, &msg);
807+
if (nvq->batched_xdp) {
808+
/* We can't build XDP buff, go for single
809+
* packet path but let's flush batched
810+
* packets.
811+
*/
812+
vhost_tx_batch(net, nvq, sock, &msg);
813+
}
802814
msg.msg_control = NULL;
803815
} else {
804816
if (tx_can_batch(vq, total_len))
@@ -819,8 +831,12 @@ static void handle_tx_copy(struct vhost_net *net, struct socket *sock)
819831
pr_debug("Truncated TX packet: len %d != %zd\n",
820832
err, len);
821833
done:
822-
vq->heads[nvq->done_idx].id = cpu_to_vhost32(vq, head);
823-
vq->heads[nvq->done_idx].len = 0;
834+
if (in_order) {
835+
vq->heads[0].id = cpu_to_vhost32(vq, head);
836+
} else {
837+
vq->heads[nvq->done_idx].id = cpu_to_vhost32(vq, head);
838+
vq->heads[nvq->done_idx].len = 0;
839+
}
824840
++nvq->done_idx;
825841
} while (likely(!vhost_exceeds_weight(vq, ++sent_pkts, total_len)));
826842

@@ -999,7 +1015,7 @@ static int peek_head_len(struct vhost_net_virtqueue *rvq, struct sock *sk)
9991015
}
10001016

10011017
static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk,
1002-
bool *busyloop_intr)
1018+
bool *busyloop_intr, unsigned int count)
10031019
{
10041020
struct vhost_net_virtqueue *rnvq = &net->vqs[VHOST_NET_VQ_RX];
10051021
struct vhost_net_virtqueue *tnvq = &net->vqs[VHOST_NET_VQ_TX];
@@ -1009,7 +1025,7 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk,
10091025

10101026
if (!len && rvq->busyloop_timeout) {
10111027
/* Flush batched heads first */
1012-
vhost_net_signal_used(rnvq);
1028+
vhost_net_signal_used(rnvq, count);
10131029
/* Both tx vq and rx socket were polled here */
10141030
vhost_net_busy_poll(net, rvq, tvq, busyloop_intr, true);
10151031

@@ -1021,22 +1037,25 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk,
10211037

10221038
/* This is a multi-buffer version of vhost_get_desc, that works if
10231039
* vq has read descriptors only.
1024-
* @vq - the relevant virtqueue
1040+
* @nvq - the relevant vhost_net virtqueue
10251041
* @datalen - data length we'll be reading
10261042
* @iovcount - returned count of io vectors we fill
10271043
* @log - vhost log
10281044
* @log_num - log offset
10291045
* @quota - headcount quota, 1 for big buffer
10301046
* returns number of buffer heads allocated, negative on error
10311047
*/
1032-
static int get_rx_bufs(struct vhost_virtqueue *vq,
1048+
static int get_rx_bufs(struct vhost_net_virtqueue *nvq,
10331049
struct vring_used_elem *heads,
1050+
u16 *nheads,
10341051
int datalen,
10351052
unsigned *iovcount,
10361053
struct vhost_log *log,
10371054
unsigned *log_num,
10381055
unsigned int quota)
10391056
{
1057+
struct vhost_virtqueue *vq = &nvq->vq;
1058+
bool in_order = vhost_has_feature(vq, VIRTIO_F_IN_ORDER);
10401059
unsigned int out, in;
10411060
int seg = 0;
10421061
int headcount = 0;
@@ -1073,14 +1092,16 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
10731092
nlogs += *log_num;
10741093
log += *log_num;
10751094
}
1076-
heads[headcount].id = cpu_to_vhost32(vq, d);
10771095
len = iov_length(vq->iov + seg, in);
1078-
heads[headcount].len = cpu_to_vhost32(vq, len);
1079-
datalen -= len;
1096+
if (!in_order) {
1097+
heads[headcount].id = cpu_to_vhost32(vq, d);
1098+
heads[headcount].len = cpu_to_vhost32(vq, len);
1099+
}
10801100
++headcount;
1101+
datalen -= len;
10811102
seg += in;
10821103
}
1083-
heads[headcount - 1].len = cpu_to_vhost32(vq, len + datalen);
1104+
10841105
*iovcount = seg;
10851106
if (unlikely(log))
10861107
*log_num = nlogs;
@@ -1090,6 +1111,15 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
10901111
r = UIO_MAXIOV + 1;
10911112
goto err;
10921113
}
1114+
1115+
if (!in_order)
1116+
heads[headcount - 1].len = cpu_to_vhost32(vq, len + datalen);
1117+
else {
1118+
heads[0].len = cpu_to_vhost32(vq, len + datalen);
1119+
heads[0].id = cpu_to_vhost32(vq, d);
1120+
nheads[0] = headcount;
1121+
}
1122+
10931123
return headcount;
10941124
err:
10951125
vhost_discard_vq_desc(vq, headcount);
@@ -1102,6 +1132,8 @@ static void handle_rx(struct vhost_net *net)
11021132
{
11031133
struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_RX];
11041134
struct vhost_virtqueue *vq = &nvq->vq;
1135+
bool in_order = vhost_has_feature(vq, VIRTIO_F_IN_ORDER);
1136+
unsigned int count = 0;
11051137
unsigned in, log;
11061138
struct vhost_log *vq_log;
11071139
struct msghdr msg = {
@@ -1149,12 +1181,13 @@ static void handle_rx(struct vhost_net *net)
11491181

11501182
do {
11511183
sock_len = vhost_net_rx_peek_head_len(net, sock->sk,
1152-
&busyloop_intr);
1184+
&busyloop_intr, count);
11531185
if (!sock_len)
11541186
break;
11551187
sock_len += sock_hlen;
11561188
vhost_len = sock_len + vhost_hlen;
1157-
headcount = get_rx_bufs(vq, vq->heads + nvq->done_idx,
1189+
headcount = get_rx_bufs(nvq, vq->heads + count,
1190+
vq->nheads + count,
11581191
vhost_len, &in, vq_log, &log,
11591192
likely(mergeable) ? UIO_MAXIOV : 1);
11601193
/* On error, stop handling until the next kick. */
@@ -1230,8 +1263,11 @@ static void handle_rx(struct vhost_net *net)
12301263
goto out;
12311264
}
12321265
nvq->done_idx += headcount;
1233-
if (nvq->done_idx > VHOST_NET_BATCH)
1234-
vhost_net_signal_used(nvq);
1266+
count += in_order ? 1 : headcount;
1267+
if (nvq->done_idx > VHOST_NET_BATCH) {
1268+
vhost_net_signal_used(nvq, count);
1269+
count = 0;
1270+
}
12351271
if (unlikely(vq_log))
12361272
vhost_log_write(vq, vq_log, log, vhost_len,
12371273
vq->iov, in);
@@ -1243,7 +1279,7 @@ static void handle_rx(struct vhost_net *net)
12431279
else if (!sock_len)
12441280
vhost_net_enable_vq(net, vq);
12451281
out:
1246-
vhost_net_signal_used(nvq);
1282+
vhost_net_signal_used(nvq, count);
12471283
mutex_unlock(&vq->mutex);
12481284
}
12491285

0 commit comments

Comments
 (0)