aboutgitcodebugslistschat
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2023-01-05 15:26:18 +1100
committerStefano Brivio <sbrivio@redhat.com>2023-01-13 01:06:51 +0100
commita6e919a9511402bd45d7fc80540c1f93166cb4af (patch)
treef72bb01037172dfc244ff7f47f3becae31fd2865
parentc196953f1e60c550d24b8a9f6ac2099075845a66 (diff)
downloadpasst-a6e919a9511402bd45d7fc80540c1f93166cb4af.tar
passt-a6e919a9511402bd45d7fc80540c1f93166cb4af.tar.gz
passt-a6e919a9511402bd45d7fc80540c1f93166cb4af.tar.bz2
passt-a6e919a9511402bd45d7fc80540c1f93166cb4af.tar.lz
passt-a6e919a9511402bd45d7fc80540c1f93166cb4af.tar.xz
passt-a6e919a9511402bd45d7fc80540c1f93166cb4af.tar.zst
passt-a6e919a9511402bd45d7fc80540c1f93166cb4af.zip
udp: Move sending pasta tap frames to the end of udp_sock_handler()
udp_sock_handler() has a surprising difference in flow between pasta and passt mode: For pasta we send each frame to the tap interface as we prepare it. For passt, though, we prepare all the frames, then send them with a single sendmmsg(). Alter the pasta path to also prepare all the frames, then send them at the end. We already have a suitable data structure for the passt case. This will make it easier to abstract out the tap backend difference in future. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r--udp.c61
1 files changed, 42 insertions, 19 deletions
diff --git a/udp.c b/udp.c
index 4610a02..a27fe88 100644
--- a/udp.c
+++ b/udp.c
@@ -784,6 +784,35 @@ static size_t udp_update_hdr6(const struct ctx *c, int n, in_port_t dstport,
}
/**
+ * udp_tap_send_pasta() - Send datagrams to the pasta tap interface
+ * @c: Execution context
+ * @mmh: Array of message headers to send
+ * @n: Number of message headers to send
+ *
+ * #syscalls:pasta write
+ */
+static void udp_tap_send_pasta(const struct ctx *c, struct mmsghdr *mmh,
+ unsigned int n)
+{
+ unsigned int i, j;
+
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < mmh[i].msg_hdr.msg_iovlen; j++) {
+ struct iovec *iov = &mmh[i].msg_hdr.msg_iov[j];
+
+ /* We can't use writev() because the tap
+ * character device relies on the write()
+ * boundaries to discern frame boundaries
+ */
+ if (write(c->fd_tap, iov->iov_base, iov->iov_len) < 0)
+ debug("tap write: %s", strerror(errno));
+ else
+ pcap(iov->iov_base, iov->iov_len);
+ }
+ }
+}
+
+/**
* udp_sock_handler() - Handle new data from socket
* @c: Execution context
* @ref: epoll reference
@@ -835,31 +864,25 @@ void udp_sock_handler(const struct ctx *c, union epoll_ref ref, uint32_t events,
else
buf_len = udp_update_hdr4(c, i, dstport, now);
- if (c->mode == MODE_PASTA) {
- void *frame = tap_iov[i].iov_base;
+ tap_iov[i].iov_len = buf_len;
- if (write(c->fd_tap, frame, buf_len) < 0)
- debug("tap write: %s", strerror(errno));
- pcap(frame, buf_len);
- } else {
- tap_iov[i].iov_len = buf_len;
-
- /* With bigger messages, qemu closes the connection. */
- if (msg_bufs && msg_len + buf_len > SHRT_MAX) {
- tap_mmh[msg_i].msg_hdr.msg_iovlen = msg_bufs;
- msg_i++;
- tap_mmh[msg_i].msg_hdr.msg_iov = &tap_iov[i];
- msg_len = msg_bufs = 0;
- }
-
- msg_len += buf_len;
- msg_bufs++;
+ /* With bigger messages, qemu closes the connection. */
+ if (c->mode == MODE_PASST && msg_bufs &&
+ msg_len + buf_len > SHRT_MAX) {
+ tap_mmh[msg_i].msg_hdr.msg_iovlen = msg_bufs;
+ msg_i++;
+ tap_mmh[msg_i].msg_hdr.msg_iov = &tap_iov[i];
+ msg_len = msg_bufs = 0;
}
+ msg_len += buf_len;
+ msg_bufs++;
}
tap_mmh[msg_i].msg_hdr.msg_iovlen = msg_bufs;
- if (c->mode == MODE_PASTA)
+ if (c->mode == MODE_PASTA) {
+ udp_tap_send_pasta(c, tap_mmh, msg_i + 1);
return;
+ }
ret = sendmmsg(c->fd_tap, tap_mmh, msg_i + 1,
MSG_NOSIGNAL | MSG_DONTWAIT);