diff options
author | David Gibson <david@gibson.dropbear.id.au> | 2024-09-06 15:17:08 +1000 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2024-09-06 12:53:33 +0200 |
commit | bd092ca421be8908aadbeb2ecdfb9fede0f67c07 (patch) | |
tree | 3824e5297f3463e192148afd12da96d6c31e8d66 | |
parent | 88bfa3801e187ac33ca9de552612bc30a1708c72 (diff) | |
download | passt-bd092ca421be8908aadbeb2ecdfb9fede0f67c07.tar passt-bd092ca421be8908aadbeb2ecdfb9fede0f67c07.tar.gz passt-bd092ca421be8908aadbeb2ecdfb9fede0f67c07.tar.bz2 passt-bd092ca421be8908aadbeb2ecdfb9fede0f67c07.tar.lz passt-bd092ca421be8908aadbeb2ecdfb9fede0f67c07.tar.xz passt-bd092ca421be8908aadbeb2ecdfb9fede0f67c07.tar.zst passt-bd092ca421be8908aadbeb2ecdfb9fede0f67c07.zip |
udp: Split socket error handling out from udp_sock_recv()
Currently udp_sock_recv() both attempts to clear socket errors and read
a batch of datagrams for forwarding. That made sense initially, since
both listening and reply sockets need to do this. However, we have certain
error cases which will add additional complexity to the error processing.
Furthermore, if we ever wanted to more thoroughly handle errors received
here - e.g. by synthesising ICMP messages on the tap device - it will
likely require different handling for the listening and reply socket cases.
So, split handling of error events into its own udp_sock_errs() function.
While we're there, allow it to report "unrecoverable errors". We don't
have any of these so far, but some cases we're working on might require it.
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r-- | udp.c | 46 |
1 files changed, 40 insertions, 6 deletions
@@ -437,12 +437,38 @@ static bool udp_sock_recverr(int s) } /** + * udp_sock_errs() - Process errors on a socket + * @c: Execution context + * @s: Socket to receive from + * @events: epoll events bitmap + * + * Return: Number of errors handled, or < 0 if we have an unrecoverable error + */ +static int udp_sock_errs(const struct ctx *c, int s, uint32_t events) +{ + unsigned n_err = 0; + + ASSERT(!c->no_udp); + + if (!(events & EPOLLERR)) + return 0; /* Nothing to do */ + + /* Empty the error queue */ + while (udp_sock_recverr(s)) + n_err++; + + return n_err; +} + +/** * udp_sock_recv() - Receive datagrams from a socket * @c: Execution context * @s: Socket to receive from * @events: epoll events bitmap * @mmh mmsghdr array to receive into * + * Return: Number of datagrams received + * * #syscalls recvmmsg arm:recvmmsg_time64 i686:recvmmsg_time64 */ static int udp_sock_recv(const struct ctx *c, int s, uint32_t events, @@ -459,12 +485,6 @@ static int udp_sock_recv(const struct ctx *c, int s, uint32_t events, ASSERT(!c->no_udp); - /* Clear any errors first */ - if (events & EPOLLERR) { - while (udp_sock_recverr(s)) - ; - } - if (!(events & EPOLLIN)) return 0; @@ -492,6 +512,13 @@ void udp_listen_sock_handler(const struct ctx *c, union epoll_ref ref, const socklen_t sasize = sizeof(udp_meta[0].s_in); int n, i; + if (udp_sock_errs(c, ref.fd, events) < 0) { + err("UDP: Unrecoverable error on listening socket:" + " (%s port %hu)", pif_name(ref.udp.pif), ref.udp.port); + /* FIXME: what now? close/re-open socket? */ + return; + } + if ((n = udp_sock_recv(c, ref.fd, events, udp_mh_recv)) <= 0) return; @@ -566,6 +593,13 @@ void udp_reply_sock_handler(const struct ctx *c, union epoll_ref ref, ASSERT(!c->no_udp && uflow); + if (udp_sock_errs(c, from_s, events) < 0) { + flow_err(uflow, "Unrecoverable error on reply socket"); + flow_err_details(uflow); + udp_flow_close(c, uflow); + return; + } + if ((n = udp_sock_recv(c, from_s, events, udp_mh_recv)) <= 0) return; |