From: Jakub Kicinski <kuba@kernel.org>
To: marcelomspessoto@gmail.com
Cc: Jakub Kicinski <kuba@kernel.org>,
netdev@vger.kernel.org, linux-kselftest@vger.kernel.org,
marcelospe@proton.me
Subject: Re: [PATCH net-next 3/4] selftests: net: test IPV6_FL_F_REFLECT
Date: Thu, 30 Jul 2026 18:39:55 -0700 [thread overview]
Message-ID: <20260731013955.752403-1-kuba@kernel.org> (raw)
In-Reply-To: <20260727043516.93101-4-marcelospe@proton.me>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
---
--- Patch [3]: [PATCH net-next 3/4] selftests: net: test IPV6_FL_F_REFLECT ---
commit 9b79debc5b7eacef4cf0bdc8e171841fff374daf
Author: Marcelo Mendes Spessoto Junior <marcelomspessoto@gmail.com>
selftests: net: test IPV6_FL_F_REFLECT
This adds a REFLECT sub-test to tools/testing/selftests/net/ipv6_flowlabel_mgr.c,
reusing the existing tcp_listen()/tcp_connect() helpers to set up a connection.
A new set_flowlabel_consistency() helper toggles
/proc/sys/net/ipv6/flowlabel_consistency around the new test block, since the
kernel refuses IPV6_FL_F_REFLECT while that sysctl is enabled.
A few questions below.
> Author: Marcelo Mendes Spessoto Junior <marcelomspessoto@gmail.com>
> Signed-off-by: Marcelo Mendes Spessoto Junior <marcelospe@proton.me>
[Severity: Low]
The author address in the commit header (marcelomspessoto@gmail.com) does not
match the Signed-off-by address (marcelospe@proton.me), which checkpatch
reports as "email address ... from: does not match Signed-off-by". Since the
Developer's Certificate of Origin is tied to the author identity, could the
From:/Signed-off-by be made consistent (or both addresses listed) so the patch
can be applied?
> diff --git a/tools/testing/selftests/net/ipv6_flowlabel_mgr.c b/tools/testing/selftests/net/ipv6_flowlabel_mgr.c
> index 383a84ea9385c..da253dff2cfd4 100644
> --- a/tools/testing/selftests/net/ipv6_flowlabel_mgr.c
> +++ b/tools/testing/selftests/net/ipv6_flowlabel_mgr.c
[ ... ]
> @@ -138,6 +139,19 @@ static void tcp_connect(int listener, uint32_t flowlabel, int *client, int *acce
> *accepted = afd;
> }
>
> +static void set_flowlabel_consistency(bool enable)
> +{
> + int fd;
> +
> + fd = open("/proc/sys/net/ipv6/flowlabel_consistency", O_WRONLY);
> + if (fd == -1)
> + error(1, errno, "open flowlabel_consistency");
[Severity: Low]
Should an unavailable or unwritable sysctl be a skip rather than a hard
failure? Any open()/write()/close() error here calls error(1, ...), which
exits the whole ipv6_flowlabel_mgr binary with status 1, so kselftest reports
FAIL rather than SKIP (exit code 4).
Before this patch the binary only issued setsockopt()/getsockopt() and needed
no privileges, and it already degrades gracefully elsewhere:
if (setuid(USHRT_MAX)) {
fprintf(stderr, "[INFO] skip setuid child test\n");
exit(0);
}
With this change, environments without a writable /proc/sys hierarchy
(CONFIG_SYSCTL=n, /proc not mounted or read-only, restricted container, no
CAP_NET_ADMIN over the netns) turn all the pre-existing, unrelated flowlabel
management assertions into a FAIL. Could only the REFLECT sub-test be skipped
in that case?
> + if (write(fd, enable ? "1" : "0", 1) != 1)
> + error(1, errno, "write flowlabel_consistency");
> + if (close(fd))
> + error(1, errno, "close flowlabel_consistency");
> +}
[Severity: Medium]
Does this leave net.ipv6.flowlabel_consistency permanently at 0 in the
namespace the test ran in?
Two things stand out. First, the helper never reads the current value, so
set_flowlabel_consistency(true) is a hardcoded write of "1" rather than a
restore, and an administrator's deliberate 0 is silently overwritten even on
success.
Second, everything between the disable and the "restore" in run_tests() aborts
the process on failure, so the restore is skipped entirely:
#define __expect(x) \
do { \
if (!(x)) \
fprintf(stderr, "[OK] " #x "\n"); \
else \
error(1, 0, "[ERR] " #x " (line %d)", __LINE__); \
} while (0)
and tcp_listen()/tcp_connect() likewise call error(1, errno, ...) on
socket/bind/listen/connect/accept failure. There is no atexit() or signal
handler, so any failing assertion (or a signal) exits with the sysctl still 0.
That direction is fail-open, since ipv6_flowlabel_get() only rejects the flag
while the sysctl is set:
net/ipv6/ip6_flowlabel.c:ipv6_flowlabel_get() {
if (freq->flr_flags & IPV6_FL_F_REFLECT) {
if (READ_ONCE(net->ipv6.sysctl.flowlabel_consistency)) {
net_info_ratelimited("Can not set IPV6_FL_F_REFLECT if flowlabel_consistency sysctl is enable\n");
return -EPERM;
}
}
Under ipv6_flowlabel.sh the throwaway netns from in_netns.sh absorbs the leak,
but ipv6_flowlabel_mgr is installed as a standalone TEST_GEN_FILES binary with
its own option parsing and is commonly run directly, in which case the writes
land in the caller's (typically init_net) namespace and persist after the test.
Would it fit the existing convention better to set the prerequisite from the
wrapper script inside the namespace, the way the other sysctls in this suite
are handled?
./in_netns.sh \
sh -c 'sysctl -q -w net.ipv6.auto_flowlabels=0 && ./ipv6_flowlabel -l 1'
> static void run_tests(int fd)
> {
> int wstatus;
[ ... ]
> @@ -254,6 +268,37 @@ static void run_tests(int fd)
> close(remote_afd);
> close(remote_cfd);
> close(remote_listener);
> +
> + explain("Prepare TCP SYN for REFLECT flag validation");
> + set_flowlabel_consistency(false);
> + int reflect_listener = tcp_listen();
> + struct in6_flowlabel_req reflect_on = {
> + .flr_action = IPV6_FL_A_GET,
> + .flr_flags = IPV6_FL_F_REFLECT,
> + };
> + explain("Enable REFLECT on the listener before the client connects");
> + expect_pass(setsockopt(reflect_listener, SOL_IPV6, IPV6_FLOWLABEL_MGR, &reflect_on, sizeof(reflect_on)));
[Severity: Low]
This isn't a bug, but three of the new assertion lines exceed the 100 column
limit checkpatch enforces (counting the leading tab as 8 columns): the
setsockopt() line above is around 113 columns, the getsockopt() line below is
around 111, and the two lines using &reflect_off are around 110. The
pre-existing REMOTE block stays under the limit. Wrapping the arguments or
shortening the variable names would address it.
> + int reflect_cfd, reflect_afd;
> + tcp_connect(reflect_listener, 7, &reflect_cfd, &reflect_afd);
> + struct in6_flowlabel_req reflect_query = {
> + .flr_action = IPV6_FL_A_GET,
> + };
> + socklen_t reflect_query_len = sizeof(reflect_query);
> + explain("Query the accepted socket's outgoing label, should be reflected");
> + expect_pass(getsockopt(reflect_afd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &reflect_query, &reflect_query_len));
> + expect_pass(ntohl(reflect_query.flr_label) != 7);
[Severity: Low]
Does this line assert the opposite of what it reads as? expect_pass() is
__expect(), which succeeds when the expression is false:
#define __expect(x) \
do { \
if (!(x)) \
fprintf(stderr, "[OK] " #x "\n"); \
else \
error(1, 0, "[ERR] " #x " (line %d)", __LINE__); \
} while (0)
#define expect_pass(x) __expect(x)
So this passes only when ntohl(reflect_query.flr_label) == 7, which is the
intended check, but the failure diagnostic prints
"[ERR] ntohl(reflect_query.flr_label) != 7", i.e. the inverse of the real
expectation. Someone later "fixing" the condition to == 7 would silently
invert the test so it passes exactly when reflection is broken.
The macro was written for syscall return codes where 0 means pass; would an
explicit comparison spelled out as a return-code style check, or a separate
value-comparison macro, be clearer here? The same idiom was introduced by the
earlier REMOTE patch in this series
(expect_pass(ntohl(freq.flr_label) != 6)), so both could be adjusted together.
> + struct in6_flowlabel_req reflect_off = {
> + .flr_action = IPV6_FL_A_PUT,
> + .flr_flags = IPV6_FL_F_REFLECT,
> + };
> + explain("PUT+REFLECT disables reflection on the accepted socket");
> + expect_pass(setsockopt(reflect_afd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &reflect_off, sizeof(reflect_off)));
> + explain("cannot disable reflection twice");
> + expect_fail(setsockopt(reflect_afd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &reflect_off, sizeof(reflect_off)));
> + set_flowlabel_consistency(true);
> + close(reflect_afd);
> + close(reflect_cfd);
> + close(reflect_listener);
> }
next prev parent reply other threads:[~2026-07-31 1:39 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-27 4:25 [PATCH net-next 0/4] net: selftests: adjustments to ipv6_flowlabel_mgr Marcelo Mendes Spessoto Junior
2026-07-27 4:25 ` [PATCH net-next 1/4] selftests: net: test IPV6_FL_A_RENEW Marcelo Mendes Spessoto Junior
2026-07-31 1:39 ` Jakub Kicinski
2026-07-27 4:25 ` [PATCH net-next 2/4] selftests: net: test IPV6_FL_F_REMOTE Marcelo Mendes Spessoto Junior
2026-07-31 1:39 ` Jakub Kicinski
2026-07-31 1:42 ` Jakub Kicinski
2026-07-27 4:25 ` [PATCH net-next 3/4] selftests: net: test IPV6_FL_F_REFLECT Marcelo Mendes Spessoto Junior
2026-07-31 1:39 ` Jakub Kicinski [this message]
2026-07-27 4:25 ` [PATCH 4/4] selftests: net: adopt harness for flow label mgr Marcelo Mendes Spessoto Junior
2026-07-31 1:39 ` Jakub Kicinski
2026-07-31 1:41 ` [PATCH net-next 0/4] net: selftests: adjustments to ipv6_flowlabel_mgr Jakub Kicinski
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260731013955.752403-1-kuba@kernel.org \
--to=kuba@kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=marcelomspessoto@gmail.com \
--cc=marcelospe@proton.me \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox