diff options
author | David Gibson <david@gibson.dropbear.id.au> | 2023-01-05 15:26:23 +1100 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2023-01-13 01:07:06 +0100 |
commit | 8a10f23720682ada5eb5f849404b193efbae6409 (patch) | |
tree | a93ed0671b8bad14e2a1e81c184ca1642d186b34 | |
parent | f1ed8dbfa732dd0c94461373fbcaea86b9eb1734 (diff) | |
download | passt-8a10f23720682ada5eb5f849404b193efbae6409.tar passt-8a10f23720682ada5eb5f849404b193efbae6409.tar.gz passt-8a10f23720682ada5eb5f849404b193efbae6409.tar.bz2 passt-8a10f23720682ada5eb5f849404b193efbae6409.tar.lz passt-8a10f23720682ada5eb5f849404b193efbae6409.tar.xz passt-8a10f23720682ada5eb5f849404b193efbae6409.tar.zst passt-8a10f23720682ada5eb5f849404b193efbae6409.zip |
udp: Unify udp_sock_handler_splice() with udp_sock_handler()
These two functions now have a very similar structure, and their first
part (calling recvmmsg()) is functionally identical. So, merge the two
functions into one.
This does have the side effect of meaning we no longer receive multiple
packets at once for splice (we already didn't for tap). This does hurt
throughput for small spliced packets, but improves it for large spliced
packets and tap packets.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r-- | udp.c | 94 |
1 files changed, 34 insertions, 60 deletions
@@ -591,52 +591,6 @@ static void udp_splice_sendfrom(const struct ctx *c, unsigned start, unsigned n, } /** - * udp_sock_handler_splice() - Handler for socket mapped to "spliced" connection - * @c: Execution context - * @ref: epoll reference - * @events: epoll events bitmap - * @now: Current timestamp - */ -static void udp_sock_handler_splice(const struct ctx *c, union epoll_ref ref, - uint32_t events, const struct timespec *now) -{ - in_port_t dst = ref.r.p.udp.udp.port; - int v6 = ref.r.p.udp.udp.v6, n, i, m; - struct mmsghdr *mmh_recv; - - if (!(events & EPOLLIN)) - return; - - if (v6) - mmh_recv = udp6_l2_mh_sock; - else - mmh_recv = udp4_l2_mh_sock; - - n = recvmmsg(ref.r.s, mmh_recv, UDP_MAX_FRAMES, 0, NULL); - - if (n <= 0) - return; - - if (v6) - udp6_localname.sin6_port = htons(dst); - else - udp4_localname.sin_port = htons(dst); - - for (i = 0; i < n; i += m) { - in_port_t src = sa_port(v6, mmh_recv[i].msg_hdr.msg_name); - - for (m = 1; i + m < n; m++) { - void *mname = mmh_recv[i + m].msg_hdr.msg_name; - if (sa_port(v6, mname) != src) - break; - } - - udp_splice_sendfrom(c, i, m, src, dst, v6, ref.r.p.udp.udp.ns, - ref.r.p.udp.udp.orig, now); - } -} - -/** * udp_update_hdr4() - Update headers for one IPv4 datagram * @c: Execution context * @n: Index of buffer in udp4_l2_buf pool @@ -944,32 +898,52 @@ void udp_sock_handler(const struct ctx *c, union epoll_ref ref, uint32_t events, const struct timespec *now) { /* For not entirely clear reasons (data locality?) pasta gets - * better throughput if we receive the datagrams one at a - * time. + * better throughput if we receive tap datagrams one at a + * atime. For small splice datagrams throughput is slightly + * better if we do batch, but it's slightly worse for large + * splice datagrams. Since we don't know before we receive + * whether we'll use tap or splice, always go one at a time + * for pasta mode. */ ssize_t n = (c->mode == MODE_PASST ? UDP_MAX_FRAMES : 1); in_port_t dstport = ref.r.p.udp.udp.port; bool v6 = ref.r.p.udp.udp.v6; - struct mmsghdr *sock_mmh; + struct mmsghdr *mmh_recv; + unsigned int i, m; - if (events == EPOLLERR) + if (!(events & EPOLLIN)) return; - if (ref.r.p.udp.udp.splice) { - udp_sock_handler_splice(c, ref, events, now); - return; + if (v6) { + mmh_recv = udp6_l2_mh_sock; + udp6_localname.sin6_port = htons(dstport); + } else { + mmh_recv = udp4_l2_mh_sock; + udp4_localname.sin_port = htons(dstport); } - if (ref.r.p.udp.udp.v6) - sock_mmh = udp6_l2_mh_sock; - else - sock_mmh = udp4_l2_mh_sock; - - n = recvmmsg(ref.r.s, sock_mmh, n, 0, NULL); + n = recvmmsg(ref.r.s, mmh_recv, n, 0, NULL); if (n <= 0) return; - udp_tap_send(c, 0, n, dstport, v6, now); + if (!ref.r.p.udp.udp.splice) { + udp_tap_send(c, 0, n, dstport, v6, now); + return; + } + + for (i = 0; i < n; i += m) { + in_port_t src = sa_port(v6, mmh_recv[i].msg_hdr.msg_name); + + for (m = 1; i + m < n; m++) { + void *mname = mmh_recv[i + m].msg_hdr.msg_name; + if (sa_port(v6, mname) != src) + break; + } + + udp_splice_sendfrom(c, i, m, src, dstport, v6, + ref.r.p.udp.udp.ns, ref.r.p.udp.udp.orig, + now); + } } /** |