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 2/4] selftests: net: test IPV6_FL_F_REMOTE
Date: Thu, 30 Jul 2026 18:39:54 -0700 [thread overview]
Message-ID: <20260731013954.752355-1-kuba@kernel.org> (raw)
In-Reply-To: <20260727043516.93101-3-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 [2]: [PATCH net-next 2/4] selftests: net: test IPV6_FL_F_REMOTE ---
commit bdc4decc572fa37fb4ef0e74f408cc6167e8342d
Author: Marcelo Mendes Spessoto Junior <marcelomspessoto@gmail.com>
selftests: net: test IPV6_FL_F_REMOTE
This adds coverage for the IPV6_FL_F_REMOTE flag of IPV6_FLOWLABEL_MGR by
setting up a loopback TCP connection with a flow label on the SYN and then
querying the accepted socket with getsockopt(). The connection setup is
factored into two new helpers, tcp_listen() and tcp_connect().
A few questions below.
[Severity: Low]
The commit message says:
"This flag retrieves the latest label received by the socket with
a getsockopt query."
Does the new test actually cover the "latest label" part?
ipv6_flowlabel_opt_get() in net/ipv6/ip6_flowlabel.c returns
np->rcv_flowinfo masked with IPV6_FLOWLABEL_MASK. For TCP, rcv_flowinfo is
set unconditionally for the child socket from the SYN in
tcp_v6_syn_recv_sock():
net/ipv6/tcp_ipv6.c:tcp_v6_syn_recv_sock() {
...
newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb));
...
}
and it is only refreshed later, in tcp_v6_do_rcv(), when rxflow or rxtclass
are enabled on the socket:
net/ipv6/tcp_ipv6.c:tcp_v6_do_rcv() {
...
if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb));
...
}
The new test queries the accepted socket right after accept(), never sets
IPV6_FLOWINFO or IPV6_TCLASS on it, and never exchanges data afterwards, so
only the SYN-time value is observed and the refresh path above would remain
untested. Would it make sense to either extend the test (enable
IPV6_FLOWINFO on the accepted socket and send data carrying a second label)
or reword the commit message to say the label seen at connection setup?
> diff --git a/tools/testing/selftests/net/ipv6_flowlabel_mgr.c b/tools/testing/selftests/net/ipv6_flowlabel_mgr.c
> index cfa7e6270994a..383a84ea9385c 100644
> --- a/tools/testing/selftests/net/ipv6_flowlabel_mgr.c
> +++ b/tools/testing/selftests/net/ipv6_flowlabel_mgr.c
[ ... ]
> @@ -82,6 +92,52 @@ static int flowlabel_renew(int fd, uint32_t label, uint16_t linger)
[ ... ]
> +static void tcp_connect(int listener, uint32_t flowlabel, int *client, int *accepted)
> +{
> + INIT_SIN6_LOOPBACK(addr);
> + const int one = 1;
> + int cfd, afd;
> +
> + cfd = socket(PF_INET6, SOCK_STREAM, 0);
> + if (cfd == -1)
> + error(1, errno, "socket client");
> +
> + if (flowlabel_get(cfd, flowlabel, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE))
> + error(1, errno, "flowlabel_get");
[Severity: Low]
Should this get be paired with the existing flowlabel_put() helper?
Every other test in this file pairs get and put explicitly, but tcp_connect()
only releases the label implicitly through close(cfd). That path goes
fl6_free_socklist() -> fl_release(), and fl_release() applies the linger
timeout rather than freeing the label right away:
net/ipv6/ip6_flowlabel.c:fl_release() {
...
fl->lastuse = jiffies;
if (atomic_dec_and_test(&fl->users)) {
unsigned long ttd = fl->lastuse + fl->linger;
...
}
So the label value stays reserved for roughly FL_MIN_LINGER seconds after the
helper's socket is closed. The commit message says the helpers exist so other
features such as IPV6_FL_F_REFLECT can reuse them; wouldn't a second
tcp_connect(listener, 6, ...) in the same run then fail in flowlabel_get()
with IPV6_FL_S_EXCL|IPV6_FL_F_CREATE and abort the whole binary via
error(1, ...)? Adding flowlabel_put(cfd, flowlabel) before closing the client
socket, or making the share mode a parameter, would match the style used
elsewhere in this file.
> + if (setsockopt(cfd, SOL_IPV6, IPV6_FLOWINFO_SEND, &one, sizeof(one)))
> + error(1, errno, "setsockopt flowinfo_send");
> + addr.sin6_flowinfo = htonl(flowlabel);
> +
> + if (connect(cfd, (void *)&addr, sizeof(addr)))
> + error(1, errno, "connect");
> +
> + afd = accept(listener, NULL, NULL);
> + if (afd == -1)
> + error(1, errno, "accept");
> +
> + *client = cfd;
> + *accepted = afd;
> +}
> +
> static void run_tests(int fd)
> {
> int wstatus;
> @@ -183,6 +239,21 @@ static void run_tests(int fd)
> expect_fail(flowlabel_get(fd, 5, IPV6_FL_S_ANY, IPV6_FL_F_CREATE));
> }
>
> + explain("Prepare TCP SYN for REMOTE flag validation");
> + int remote_listener = tcp_listen();
> + int remote_cfd, remote_afd;
[Severity: Low]
This isn't a bug, but these declarations come after executable statements,
while run_tests() already declares wstatus and pid at the top of the function
and the rest of the file uses top-of-block declarations. selftests/net
CFLAGS do not turn on -Wdeclaration-after-statement so it builds, but hoisting
remote_listener, remote_cfd, remote_afd, freq and freq_len to the top of
run_tests() (or putting the new test in its own block) would keep the style
consistent with no change in behaviour.
> + tcp_connect(remote_listener, 6, &remote_cfd, &remote_afd);
> + struct in6_flowlabel_req freq = {
> + .flr_action = IPV6_FL_A_GET,
> + .flr_flags = IPV6_FL_F_REMOTE,
> + };
> + socklen_t freq_len = sizeof(freq);
> + explain("Query for label sent by client with IPV6_FL_F_REMOTE");
> + expect_pass(getsockopt(remote_afd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &freq, &freq_len));
> + expect_pass(ntohl(freq.flr_label) != 6);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[Severity: Low]
Is this assertion written the way it was intended?
expect_pass() succeeds when its argument evaluates to zero:
#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)
#define expect_fail(x) __expect(!(x))
So expect_pass(ntohl(freq.flr_label) != 6) passes exactly when the label is
6, which is the intended check, but it reads as the opposite and the log line
printed on success is "[OK] ntohl(freq.flr_label) != 6". Every other use of
expect_pass()/expect_fail() in this file passes a setsockopt()/getsockopt()
return code rather than a value comparison.
Would a plain check be clearer here, for example:
if (ntohl(freq.flr_label) != REMOTE_LABEL)
error(1, 0, "unexpected remote flowlabel %u", ntohl(freq.flr_label));
Also, the expected label appears twice as a bare literal, in
tcp_connect(remote_listener, 6, ...) and in the comparison against 6. Could a
named constant be used at both sites so they cannot drift apart?
> + close(remote_afd);
> + close(remote_cfd);
> + close(remote_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 [this message]
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
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=20260731013954.752355-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