[PATCH net-next 1/3] selftests/net: pass socket options to the scm_pidfd test flows

From: Andrew Halaney

Date: Mon Nov 02 2026 - 18:14:14 EST


pidfd_flow() and leader_flow() take booleans that pick between
SO_PASSPIDFD and SO_PASSPIDFD_THREAD. Make them take a zero-terminated
list of socket options for the receiver to enable instead, so tests for
further SO_PASS* options can reuse the same flows rather than copying
them just to muck with options.

Signed-off-by: Andrew Halaney <andrew@xxxxxxxxxxxx>
---
tools/testing/selftests/net/af_unix/scm_pidfd.c | 69 ++++++++++++-------------
1 file changed, 34 insertions(+), 35 deletions(-)

diff --git a/tools/testing/selftests/net/af_unix/scm_pidfd.c b/tools/testing/selftests/net/af_unix/scm_pidfd.c
index cbe53fab44fc..7524f3f6a8aa 100644
--- a/tools/testing/selftests/net/af_unix/scm_pidfd.c
+++ b/tools/testing/selftests/net/af_unix/scm_pidfd.c
@@ -765,20 +765,37 @@ static int read_pidfd_msg(int fd, struct pidfd_msg *out)
return 0;
}

+/* Zero-terminated lists of SOL_SOCKET options for the receiver to enable */
+static const int pass_tgid[] = { SO_PASSPIDFD, 0 };
+static const int pass_thread[] = { SO_PASSPIDFD_THREAD, 0 };
+static const int pass_both[] = { SO_PASSPIDFD, SO_PASSPIDFD_THREAD, 0 };
+
+static int set_opts(int fd, const int *opts)
+{
+ int on = 1;
+
+ for (; *opts; opts++) {
+ if (setsockopt(fd, SOL_SOCKET, *opts, &on, sizeof(on))) {
+ log_err("Failed to set socket option %d", *opts);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
/*
* Runs @nwriters threads of one child process against a SOCK_STREAM pair,
- * all of them queued before the parent reads. SO_PASSPIDFD is set when
- * @want_tgid is given, SO_PASSPIDFD_THREAD when @want_thread is. @nread
- * reads are returned in @out.
+ * all of them queued before the parent reads. The receiver enables @opts
+ * first. @nread reads are returned in @out.
*/
-static int pidfd_flow(void *(*sender)(void *), int nwriters, bool want_tgid,
- bool want_thread, struct pidfd_msg *out, int nread)
+static int pidfd_flow(void *(*sender)(void *), int nwriters, const int *opts,
+ struct pidfd_msg *out, int nread)
{
int child_status = 0;
int syncpipe[2];
int ackpipe[2];
int sk[2];
- int on = 1;
char sync;
pid_t child;
int i;
@@ -807,17 +824,8 @@ static int pidfd_flow(void *(*sender)(void *), int nwriters, bool want_tgid,
close(seq_pipe[0]);
close(seq_pipe[1]);

- if (want_tgid &&
- setsockopt(sk[0], SOL_SOCKET, SO_PASSPIDFD, &on, sizeof(on))) {
- log_err("Failed to set SO_PASSPIDFD");
+ if (set_opts(sk[0], opts))
return -1;
- }
-
- if (want_thread &&
- setsockopt(sk[0], SOL_SOCKET, SO_PASSPIDFD_THREAD, &on, sizeof(on))) {
- log_err("Failed to set SO_PASSPIDFD_THREAD");
- return -1;
- }

/* let the child know the options are set, it can write now */
if (write(syncpipe[1], "1", 1) != 1)
@@ -897,7 +905,7 @@ TEST(scm_pidfd_stream_glues_threads)
{
struct pidfd_msg msg[1] = { 0 };

- ASSERT_EQ(0, pidfd_flow(send_ids_thread, 2, true, false, msg, 1));
+ ASSERT_EQ(0, pidfd_flow(send_ids_thread, 2, pass_tgid, msg, 1));
EXPECT_EQ(sizeof(struct thread_ids) * 2, msg[0].len);

EXPECT_TRUE(msg[0].have_tgid);
@@ -914,7 +922,7 @@ TEST(scm_pidfd_thread_stream_splits_on_threads)
struct pidfd_msg msg[2] = { 0 };
int i;

- ASSERT_EQ(0, pidfd_flow(send_ids_thread, 2, true, true, msg, 2));
+ ASSERT_EQ(0, pidfd_flow(send_ids_thread, 2, pass_both, msg, 2));

for (i = 0; i < 2; i++) {
EXPECT_EQ(sizeof(struct thread_ids), msg[i].len);
@@ -937,29 +945,20 @@ TEST(scm_pidfd_thread_stream_splits_on_threads)
}

/* Sends from the thread-group leader */
-static int leader_flow(bool want_thread, struct pidfd_msg *out)
+static int leader_flow(const int *opts, struct pidfd_msg *out)
{
struct thread_ids ids = {
.pid = getpid(),
.tid = gettid(),
};
int sk[2];
- int on = 1;
int ret;

if (socketpair(AF_UNIX, SOCK_STREAM, 0, sk))
return -1;

- if (setsockopt(sk[0], SOL_SOCKET, SO_PASSPIDFD, &on, sizeof(on))) {
- log_err("Failed to set SO_PASSPIDFD");
+ if (set_opts(sk[0], opts))
return -1;
- }
-
- if (want_thread &&
- setsockopt(sk[0], SOL_SOCKET, SO_PASSPIDFD_THREAD, &on, sizeof(on))) {
- log_err("Failed to set SO_PASSPIDFD_THREAD");
- return -1;
- }

if (send(sk[1], &ids, sizeof(ids), 0) != sizeof(ids)) {
log_err("send");
@@ -980,7 +979,7 @@ TEST(scm_pidfd_leader_sender)

ASSERT_EQ(getpid(), gettid());

- ASSERT_EQ(0, leader_flow(false, &msg));
+ ASSERT_EQ(0, leader_flow(pass_tgid, &msg));
ASSERT_TRUE(msg.have_tgid);
EXPECT_FALSE(msg.have_thread);

@@ -995,7 +994,7 @@ TEST(scm_pidfd_thread_leader_sender)

ASSERT_EQ(getpid(), gettid());

- ASSERT_EQ(0, leader_flow(true, &msg));
+ ASSERT_EQ(0, leader_flow(pass_both, &msg));
ASSERT_TRUE(msg.have_tgid);
ASSERT_TRUE(msg.have_thread);

@@ -1012,7 +1011,7 @@ TEST(scm_pidfd_thread_and_group)
{
struct pidfd_msg msg = { 0 };

- ASSERT_EQ(0, pidfd_flow(send_ids_thread, 1, true, true, &msg, 1));
+ ASSERT_EQ(0, pidfd_flow(send_ids_thread, 1, pass_both, &msg, 1));
ASSERT_NE(msg.ids.pid, msg.ids.tid);
ASSERT_TRUE(msg.have_tgid);
ASSERT_TRUE(msg.have_thread);
@@ -1028,7 +1027,7 @@ TEST(scm_pidfd_thread)
{
struct pidfd_msg msg = { 0 };

- ASSERT_EQ(0, pidfd_flow(send_ids_thread, 1, false, true, &msg, 1));
+ ASSERT_EQ(0, pidfd_flow(send_ids_thread, 1, pass_thread, &msg, 1));
ASSERT_NE(msg.ids.pid, msg.ids.tid);
ASSERT_TRUE(msg.have_thread);
EXPECT_FALSE(msg.have_tgid);
@@ -1040,7 +1039,7 @@ TEST(scm_pidfd_thread_group)
{
struct pidfd_msg msg = { 0 };

- ASSERT_EQ(0, pidfd_flow(send_ids_thread, 1, true, false, &msg, 1));
+ ASSERT_EQ(0, pidfd_flow(send_ids_thread, 1, pass_tgid, &msg, 1));
ASSERT_NE(msg.ids.pid, msg.ids.tid);
ASSERT_TRUE(msg.have_tgid);
EXPECT_FALSE(msg.have_thread);
@@ -1052,7 +1051,7 @@ TEST(scm_pidfd_thread_creds)
{
struct pidfd_msg msg = { 0 };

- ASSERT_EQ(0, pidfd_flow(send_ids_creds_thread, 1, true, true, &msg, 1));
+ ASSERT_EQ(0, pidfd_flow(send_ids_creds_thread, 1, pass_both, &msg, 1));
ASSERT_NE(msg.ids.pid, msg.ids.tid);
ASSERT_TRUE(msg.have_tgid);
ASSERT_TRUE(msg.have_thread);

--
2.56.0