aboutgitcodebugslistschat
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2024-09-06 15:17:10 +1000
committerStefano Brivio <sbrivio@redhat.com>2024-09-06 12:53:38 +0200
commitaff5a49b0e75dd08428a88c05d98f39885556c8b (patch)
tree0d7dd172361c9ee573076ca5724d69108f03e7a9
parentbd99f02a64f46cae44ef13c3cb934b8baa9c1a2c (diff)
downloadpasst-aff5a49b0e75dd08428a88c05d98f39885556c8b.tar
passt-aff5a49b0e75dd08428a88c05d98f39885556c8b.tar.gz
passt-aff5a49b0e75dd08428a88c05d98f39885556c8b.tar.bz2
passt-aff5a49b0e75dd08428a88c05d98f39885556c8b.tar.lz
passt-aff5a49b0e75dd08428a88c05d98f39885556c8b.tar.xz
passt-aff5a49b0e75dd08428a88c05d98f39885556c8b.tar.zst
passt-aff5a49b0e75dd08428a88c05d98f39885556c8b.zip
udp: Handle more error conditions in udp_sock_errs()
udp_sock_errs() reads out everything in the socket error queue. However we've seen some cases[0] where an EPOLLERR event is active, but there isn't anything in the queue. One possibility is that the error is reported instead by the SO_ERROR sockopt. Check for that case and report it as best we can. If we still get an EPOLLERR without visible error, we have no way to clear the error state, so treat it as an unrecoverable error. [0] https://github.com/containers/podman/issues/23686#issuecomment-2324945010 Link: https://bugs.passt.top/show_bug.cgi?id=95 Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
-rw-r--r--udp.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/udp.c b/udp.c
index 85a14de..ae91027 100644
--- a/udp.c
+++ b/udp.c
@@ -450,7 +450,8 @@ static int udp_sock_recverr(int s)
static int udp_sock_errs(const struct ctx *c, int s, uint32_t events)
{
unsigned n_err = 0;
- int rc;
+ socklen_t errlen;
+ int rc, err;
ASSERT(!c->no_udp);
@@ -464,6 +465,24 @@ static int udp_sock_errs(const struct ctx *c, int s, uint32_t events)
if (rc < 0)
return -1; /* error reading error, unrecoverable */
+ errlen = sizeof(err);
+ if (getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &errlen) < 0 ||
+ errlen != sizeof(err)) {
+ err_perror("Error reading SO_ERROR");
+ return -1; /* error reading error, unrecoverable */
+ }
+
+ if (err) {
+ debug("Unqueued error on UDP socket %i: %s", s, strerror(err));
+ n_err++;
+ }
+
+ if (!n_err) {
+ /* EPOLLERR, but no errors to clear !? */
+ err("EPOLLERR event without reported errors on socket %i", s);
+ return -1; /* no way to clear, unrecoverable */
+ }
+
return n_err;
}