try_recv() was meant to support both @expect_success cases, but all the
callers use @expect_success=false anyway. Drop the unused logic and fold in
MSG_DONTWAIT. Adapt callers.
Subtle change here: recv() return value of 0 will also be considered (an
unexpected) success.
Signed-off-by: Michal Luczaj <mhal@rbox.co>
---
.../selftests/bpf/prog_tests/sockmap_redir.c | 25 +++++++++-------------
1 file changed, 10 insertions(+), 15 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c b/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c
index 9c461d93113db20de65ac353f92dfdbe32ffbd3b..c1bf1076e8152b7d83c3e07e2dce746b5a39cf7e 100644
--- a/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c
+++ b/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c
@@ -144,17 +144,14 @@ static void get_redir_params(struct redir_spec *redir,
*redirect_flags = 0;
}
-static void try_recv(const char *prefix, int fd, int flags, bool expect_success)
+static void fail_recv(const char *prefix, int fd, int more_flags)
{
ssize_t n;
char buf;
- errno = 0;
- n = recv(fd, &buf, 1, flags);
- if (n < 0 && expect_success)
- FAIL_ERRNO("%s: unexpected failure: retval=%zd", prefix, n);
- if (!n && !expect_success)
- FAIL("%s: expected failure: retval=%zd", prefix, n);
+ n = recv(fd, &buf, 1, MSG_DONTWAIT | more_flags);
+ if (n >= 0)
+ FAIL("%s: unexpected success: retval=%zd", prefix, n);
}
static void handle_unsupported(int sd_send, int sd_peer, int sd_in, int sd_out,
@@ -188,13 +185,13 @@ static void handle_unsupported(int sd_send, int sd_peer, int sd_in, int sd_out,
}
/* Ensure queues are empty */
- try_recv("bpf.recv(sd_send)", sd_send, MSG_DONTWAIT, false);
+ fail_recv("bpf.recv(sd_send)", sd_send, 0);
if (sd_in != sd_send)
- try_recv("bpf.recv(sd_in)", sd_in, MSG_DONTWAIT, false);
+ fail_recv("bpf.recv(sd_in)", sd_in, 0);
- try_recv("bpf.recv(sd_out)", sd_out, MSG_DONTWAIT, false);
+ fail_recv("bpf.recv(sd_out)", sd_out, 0);
if (sd_recv != sd_out)
- try_recv("bpf.recv(sd_recv)", sd_recv, MSG_DONTWAIT, false);
+ fail_recv("bpf.recv(sd_recv)", sd_recv, 0);
}
static void test_send_redir_recv(int sd_send, int send_flags, int sd_peer,
@@ -257,15 +254,13 @@ static void test_send_redir_recv(int sd_send, int send_flags, int sd_peer,
if (send_flags & MSG_OOB) {
/* Fail reading OOB while in sockmap */
- try_recv("bpf.recv(sd_out, MSG_OOB)", sd_out,
- MSG_OOB | MSG_DONTWAIT, false);
+ fail_recv("bpf.recv(sd_out, MSG_OOB)", sd_out, MSG_OOB);
/* Remove sd_out from sockmap */
xbpf_map_delete_elem(maps->out, &u32(0));
/* Check that OOB was dropped on redirect */
- try_recv("recv(sd_out, MSG_OOB)", sd_out,
- MSG_OOB | MSG_DONTWAIT, false);
+ fail_recv("recv(sd_out, MSG_OOB)", sd_out, MSG_OOB);
goto del_in;
}
--
2.50.1
On Fri, Sep 05, 2025 at 01:11 PM +02, Michal Luczaj wrote:
> try_recv() was meant to support both @expect_success cases, but all the
> callers use @expect_success=false anyway. Drop the unused logic and fold in
> MSG_DONTWAIT. Adapt callers.
>
> Subtle change here: recv() return value of 0 will also be considered (an
> unexpected) success.
>
> Signed-off-by: Michal Luczaj <mhal@rbox.co>
> ---
> .../selftests/bpf/prog_tests/sockmap_redir.c | 25 +++++++++-------------
> 1 file changed, 10 insertions(+), 15 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c b/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c
> index 9c461d93113db20de65ac353f92dfdbe32ffbd3b..c1bf1076e8152b7d83c3e07e2dce746b5a39cf7e 100644
> --- a/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c
> +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c
> @@ -144,17 +144,14 @@ static void get_redir_params(struct redir_spec *redir,
> *redirect_flags = 0;
> }
>
> -static void try_recv(const char *prefix, int fd, int flags, bool expect_success)
> +static void fail_recv(const char *prefix, int fd, int more_flags)
> {
> ssize_t n;
> char buf;
>
> - errno = 0;
> - n = recv(fd, &buf, 1, flags);
> - if (n < 0 && expect_success)
> - FAIL_ERRNO("%s: unexpected failure: retval=%zd", prefix, n);
> - if (!n && !expect_success)
> - FAIL("%s: expected failure: retval=%zd", prefix, n);
> + n = recv(fd, &buf, 1, MSG_DONTWAIT | more_flags);
> + if (n >= 0)
> + FAIL("%s: unexpected success: retval=%zd", prefix, n);
> }
This bit, which you highlighted in the description, I don't get.
If we're expecting to receive exactly one byte, why treat a short read
as a succcess? Why not make it a strict "n != 1" check?
[...]
On Tue, Sep 09, 2025 at 11:51 AM +02, Jakub Sitnicki wrote:
> On Fri, Sep 05, 2025 at 01:11 PM +02, Michal Luczaj wrote:
>> try_recv() was meant to support both @expect_success cases, but all the
>> callers use @expect_success=false anyway. Drop the unused logic and fold in
>> MSG_DONTWAIT. Adapt callers.
>>
>> Subtle change here: recv() return value of 0 will also be considered (an
>> unexpected) success.
>>
>> Signed-off-by: Michal Luczaj <mhal@rbox.co>
>> ---
>> .../selftests/bpf/prog_tests/sockmap_redir.c | 25 +++++++++-------------
>> 1 file changed, 10 insertions(+), 15 deletions(-)
>>
>> diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c b/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c
>> index 9c461d93113db20de65ac353f92dfdbe32ffbd3b..c1bf1076e8152b7d83c3e07e2dce746b5a39cf7e 100644
>> --- a/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c
>> +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c
>> @@ -144,17 +144,14 @@ static void get_redir_params(struct redir_spec *redir,
>> *redirect_flags = 0;
>> }
>>
>> -static void try_recv(const char *prefix, int fd, int flags, bool expect_success)
>> +static void fail_recv(const char *prefix, int fd, int more_flags)
>> {
>> ssize_t n;
>> char buf;
>>
>> - errno = 0;
>> - n = recv(fd, &buf, 1, flags);
>> - if (n < 0 && expect_success)
>> - FAIL_ERRNO("%s: unexpected failure: retval=%zd", prefix, n);
>> - if (!n && !expect_success)
>> - FAIL("%s: expected failure: retval=%zd", prefix, n);
>> + n = recv(fd, &buf, 1, MSG_DONTWAIT | more_flags);
>> + if (n >= 0)
>> + FAIL("%s: unexpected success: retval=%zd", prefix, n);
>> }
>
> This bit, which you highlighted in the description, I don't get.
>
> If we're expecting to receive exactly one byte, why treat a short read
> as a succcess? Why not make it a strict "n != 1" check?
>
> [...]
Nevermind. It makes sense now. We do want to report a failure for 0-len
msg recv as well. You're effectively checking if the rcv queue is empty.
I'd add MSG_PEEK, to signal that we're _just checking_ if the socket is
readable, and turn the check into the below to succeed only when
queue is empty:
(n != -1 || (errno != EAGAIN && errno != EWOULDBLOCK))
It's a minor thing. Leaving it up to you. Either way:
Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com>
On 9/9/25 12:15, Jakub Sitnicki wrote:
> On Tue, Sep 09, 2025 at 11:51 AM +02, Jakub Sitnicki wrote:
>> On Fri, Sep 05, 2025 at 01:11 PM +02, Michal Luczaj wrote:
>>> try_recv() was meant to support both @expect_success cases, but all the
>>> callers use @expect_success=false anyway. Drop the unused logic and fold in
>>> MSG_DONTWAIT. Adapt callers.
>>>
>>> Subtle change here: recv() return value of 0 will also be considered (an
>>> unexpected) success.
>>>
>>> Signed-off-by: Michal Luczaj <mhal@rbox.co>
>>> ---
>>> .../selftests/bpf/prog_tests/sockmap_redir.c | 25 +++++++++-------------
>>> 1 file changed, 10 insertions(+), 15 deletions(-)
>>>
>>> diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c b/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c
>>> index 9c461d93113db20de65ac353f92dfdbe32ffbd3b..c1bf1076e8152b7d83c3e07e2dce746b5a39cf7e 100644
>>> --- a/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c
>>> +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c
>>> @@ -144,17 +144,14 @@ static void get_redir_params(struct redir_spec *redir,
>>> *redirect_flags = 0;
>>> }
>>>
>>> -static void try_recv(const char *prefix, int fd, int flags, bool expect_success)
>>> +static void fail_recv(const char *prefix, int fd, int more_flags)
>>> {
>>> ssize_t n;
>>> char buf;
>>>
>>> - errno = 0;
>>> - n = recv(fd, &buf, 1, flags);
>>> - if (n < 0 && expect_success)
>>> - FAIL_ERRNO("%s: unexpected failure: retval=%zd", prefix, n);
>>> - if (!n && !expect_success)
>>> - FAIL("%s: expected failure: retval=%zd", prefix, n);
>>> + n = recv(fd, &buf, 1, MSG_DONTWAIT | more_flags);
>>> + if (n >= 0)
>>> + FAIL("%s: unexpected success: retval=%zd", prefix, n);
>>> }
>>
>> This bit, which you highlighted in the description, I don't get.
>>
>> If we're expecting to receive exactly one byte, why treat a short read
>> as a succcess? Why not make it a strict "n != 1" check?
>>
>> [...]
>
> Nevermind. It makes sense now. We do want to report a failure for 0-len
> msg recv as well. You're effectively checking if the rcv queue is empty.
>
> I'd add MSG_PEEK, to signal that we're _just checking_ if the socket is
> readable, and turn the check into the below to succeed only when
> queue is empty:
>
> (n != -1 || (errno != EAGAIN && errno != EWOULDBLOCK))
Well, looks like adding MSG_PEEK exposed a bug in the test. I'll fix that.
Thanks,
Michal
On Tue, Sep 09, 2025 at 11:25 PM +02, Michal Luczaj wrote:
> On 9/9/25 12:15, Jakub Sitnicki wrote:
>> On Tue, Sep 09, 2025 at 11:51 AM +02, Jakub Sitnicki wrote:
>>> On Fri, Sep 05, 2025 at 01:11 PM +02, Michal Luczaj wrote:
>>>> try_recv() was meant to support both @expect_success cases, but all the
>>>> callers use @expect_success=false anyway. Drop the unused logic and fold in
>>>> MSG_DONTWAIT. Adapt callers.
>>>>
>>>> Subtle change here: recv() return value of 0 will also be considered (an
>>>> unexpected) success.
>>>>
>>>> Signed-off-by: Michal Luczaj <mhal@rbox.co>
>>>> ---
>>>> .../selftests/bpf/prog_tests/sockmap_redir.c | 25 +++++++++-------------
>>>> 1 file changed, 10 insertions(+), 15 deletions(-)
>>>>
>>>> diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c b/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c
>>>> index 9c461d93113db20de65ac353f92dfdbe32ffbd3b..c1bf1076e8152b7d83c3e07e2dce746b5a39cf7e 100644
>>>> --- a/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c
>>>> +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_redir.c
>>>> @@ -144,17 +144,14 @@ static void get_redir_params(struct redir_spec *redir,
>>>> *redirect_flags = 0;
>>>> }
>>>>
>>>> -static void try_recv(const char *prefix, int fd, int flags, bool expect_success)
>>>> +static void fail_recv(const char *prefix, int fd, int more_flags)
>>>> {
>>>> ssize_t n;
>>>> char buf;
>>>>
>>>> - errno = 0;
>>>> - n = recv(fd, &buf, 1, flags);
>>>> - if (n < 0 && expect_success)
>>>> - FAIL_ERRNO("%s: unexpected failure: retval=%zd", prefix, n);
>>>> - if (!n && !expect_success)
>>>> - FAIL("%s: expected failure: retval=%zd", prefix, n);
>>>> + n = recv(fd, &buf, 1, MSG_DONTWAIT | more_flags);
>>>> + if (n >= 0)
>>>> + FAIL("%s: unexpected success: retval=%zd", prefix, n);
>>>> }
>>>
>>> This bit, which you highlighted in the description, I don't get.
>>>
>>> If we're expecting to receive exactly one byte, why treat a short read
>>> as a succcess? Why not make it a strict "n != 1" check?
>>>
>>> [...]
>>
>> Nevermind. It makes sense now. We do want to report a failure for 0-len
>> msg recv as well. You're effectively checking if the rcv queue is empty.
>>
>> I'd add MSG_PEEK, to signal that we're _just checking_ if the socket is
>> readable, and turn the check into the below to succeed only when
>> queue is empty:
>>
>> (n != -1 || (errno != EAGAIN && errno != EWOULDBLOCK))
>
> Well, looks like adding MSG_PEEK exposed a bug in the test. I'll fix that.
The gift that keeps on giving xD
Other alternatives that should also work, but who knows:
- select/poll/epoll readability check
- ioctl(SIOCINQ) but no way to tell if 0-len msg is pending
© 2016 - 2026 Red Hat, Inc.