[PATCH v5 bpf-next 0/4] BPF iterator for UNIX domain socket.

STALE1815d

Revision v5 of 6 in this series.

14 messages, 3 authors, 2021-08-16 · open the first message on its own page

[PATCH v5 bpf-next 0/4] BPF iterator for UNIX domain socket.

From: Kuniyuki Iwashima <hidden>
Date: 2021-08-12 16:46:19

This patch set adds BPF iterator support for UNIX domain socket.  The first
patch implements it, and the second adds "%c" support for BPF_SEQ_PRINTF().


Changelog:
  v5:
  - Align header line of bpf_iter_unix.c
  - Add test for "%c"

  v4:
  https://lore.kernel.org/netdev/20210810092807.13190-1-kuniyu@amazon.co.jp/
  - Check IS_BUILTIN(CONFIG_UNIX)
  - Support "%c" in BPF_SEQ_PRINTF()
  - Uncomment the code to print the name of the abstract socket
  - Mention the LLVM fix in README.rst
  - Remove the 'aligned' attribute in bpf_iter.h
  - Keep the format string on a single line

  v3:
  https://lore.kernel.org/netdev/20210804070851.97834-1-kuniyu@amazon.co.jp/
  - Export some functions for CONFIG_UNIX=m

  v2:
  https://lore.kernel.org/netdev/20210803011110.21205-1-kuniyu@amazon.co.jp/
  - Implement bpf_iter specific seq_ops->stop()
  - Add bpf_iter__unix in bpf_iter.h
  - Move common definitions in selftest to bpf_tracing_net.h
  - Include the code for abstract UNIX domain socket as comment in selftest
  - Use ASSERT_OK_PTR() instead of CHECK()
  - Make ternary operators on single line

  v1:
  https://lore.kernel.org/netdev/20210729233645.4869-1-kuniyu@amazon.co.jp/


Kuniyuki Iwashima (4):
  bpf: af_unix: Implement BPF iterator for UNIX domain socket.
  bpf: Support "%c" in bpf_bprintf_prepare().
  selftest/bpf: Implement sample UNIX domain socket iterator program.
  selftest/bpf: Extend the bpf_snprintf() test for "%c".

 include/linux/btf_ids.h                       |  3 +-
 kernel/bpf/helpers.c                          | 14 +++
 net/unix/af_unix.c                            | 93 +++++++++++++++++++
 tools/testing/selftests/bpf/README.rst        | 38 ++++++++
 .../selftests/bpf/prog_tests/bpf_iter.c       | 16 ++++
 .../selftests/bpf/prog_tests/snprintf.c       |  4 +-
 tools/testing/selftests/bpf/progs/bpf_iter.h  |  8 ++
 .../selftests/bpf/progs/bpf_iter_unix.c       | 77 +++++++++++++++
 .../selftests/bpf/progs/bpf_tracing_net.h     |  4 +
 .../selftests/bpf/progs/test_snprintf.c       |  7 +-
 10 files changed, 259 insertions(+), 5 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/progs/bpf_iter_unix.c

-- 
2.30.2

[PATCH v5 bpf-next 1/4] bpf: af_unix: Implement BPF iterator for UNIX domain socket.

From: Kuniyuki Iwashima <hidden>
Date: 2021-08-12 16:46:30

This patch implements the BPF iterator for the UNIX domain socket.

Currently, the batch optimisation introduced for the TCP iterator in the
commit 04c7820b776f ("bpf: tcp: Bpf iter batching and lock_sock") is not
used for the UNIX domain socket.  It will require replacing the big lock
for the hash table with small locks for each hash list not to block other
processes.

Signed-off-by: Kuniyuki Iwashima <redacted>
Acked-by: Yonghong Song <redacted>
---
 include/linux/btf_ids.h |  3 +-
 net/unix/af_unix.c      | 93 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+), 1 deletion(-)
diff --git a/include/linux/btf_ids.h b/include/linux/btf_ids.h
index 57890b357f85..bed4b9964581 100644
--- a/include/linux/btf_ids.h
+++ b/include/linux/btf_ids.h
@@ -172,7 +172,8 @@ extern struct btf_id_set name;
 	BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP_TW, tcp_timewait_sock)		\
 	BTF_SOCK_TYPE(BTF_SOCK_TYPE_TCP6, tcp6_sock)			\
 	BTF_SOCK_TYPE(BTF_SOCK_TYPE_UDP, udp_sock)			\
-	BTF_SOCK_TYPE(BTF_SOCK_TYPE_UDP6, udp6_sock)
+	BTF_SOCK_TYPE(BTF_SOCK_TYPE_UDP6, udp6_sock)			\
+	BTF_SOCK_TYPE(BTF_SOCK_TYPE_UNIX, unix_sock)
 
 enum {
 #define BTF_SOCK_TYPE(name, str) name,
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index ec02e70a549b..e671f49b77df 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -113,6 +113,7 @@
 #include <linux/security.h>
 #include <linux/freezer.h>
 #include <linux/file.h>
+#include <linux/btf_ids.h>
 
 #include "scm.h"
 
@@ -3131,6 +3132,64 @@ static const struct seq_operations unix_seq_ops = {
 	.stop   = unix_seq_stop,
 	.show   = unix_seq_show,
 };
+
+#if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL)
+struct bpf_iter__unix {
+	__bpf_md_ptr(struct bpf_iter_meta *, meta);
+	__bpf_md_ptr(struct unix_sock *, unix_sk);
+	uid_t uid __aligned(8);
+};
+
+static int unix_prog_seq_show(struct bpf_prog *prog, struct bpf_iter_meta *meta,
+			      struct unix_sock *unix_sk, uid_t uid)
+{
+	struct bpf_iter__unix ctx;
+
+	meta->seq_num--;  /* skip SEQ_START_TOKEN */
+	ctx.meta = meta;
+	ctx.unix_sk = unix_sk;
+	ctx.uid = uid;
+	return bpf_iter_run_prog(prog, &ctx);
+}
+
+static int bpf_iter_unix_seq_show(struct seq_file *seq, void *v)
+{
+	struct bpf_iter_meta meta;
+	struct bpf_prog *prog;
+	struct sock *sk = v;
+	uid_t uid;
+
+	if (v == SEQ_START_TOKEN)
+		return 0;
+
+	uid = from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk));
+	meta.seq = seq;
+	prog = bpf_iter_get_info(&meta, false);
+	return unix_prog_seq_show(prog, &meta, v, uid);
+}
+
+static void bpf_iter_unix_seq_stop(struct seq_file *seq, void *v)
+{
+	struct bpf_iter_meta meta;
+	struct bpf_prog *prog;
+
+	if (!v) {
+		meta.seq = seq;
+		prog = bpf_iter_get_info(&meta, true);
+		if (prog)
+			(void)unix_prog_seq_show(prog, &meta, v, 0);
+	}
+
+	unix_seq_stop(seq, v);
+}
+
+static const struct seq_operations bpf_iter_unix_seq_ops = {
+	.start	= unix_seq_start,
+	.next	= unix_seq_next,
+	.stop	= bpf_iter_unix_seq_stop,
+	.show	= bpf_iter_unix_seq_show,
+};
+#endif
 #endif
 
 static const struct net_proto_family unix_family_ops = {
@@ -3171,6 +3230,35 @@ static struct pernet_operations unix_net_ops = {
 	.exit = unix_net_exit,
 };
 
+#if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
+DEFINE_BPF_ITER_FUNC(unix, struct bpf_iter_meta *meta,
+		     struct unix_sock *unix_sk, uid_t uid)
+
+static const struct bpf_iter_seq_info unix_seq_info = {
+	.seq_ops		= &bpf_iter_unix_seq_ops,
+	.init_seq_private	= bpf_iter_init_seq_net,
+	.fini_seq_private	= bpf_iter_fini_seq_net,
+	.seq_priv_size		= sizeof(struct seq_net_private),
+};
+
+static struct bpf_iter_reg unix_reg_info = {
+	.target			= "unix",
+	.ctx_arg_info_size	= 1,
+	.ctx_arg_info		= {
+		{ offsetof(struct bpf_iter__unix, unix_sk),
+		  PTR_TO_BTF_ID_OR_NULL },
+	},
+	.seq_info		= &unix_seq_info,
+};
+
+static void __init bpf_iter_register(void)
+{
+	unix_reg_info.ctx_arg_info[0].btf_id = btf_sock_ids[BTF_SOCK_TYPE_UNIX];
+	if (bpf_iter_reg_target(&unix_reg_info))
+		pr_warn("Warning: could not register bpf iterator unix\n");
+}
+#endif
+
 static int __init af_unix_init(void)
 {
 	int rc = -1;
@@ -3186,6 +3274,11 @@ static int __init af_unix_init(void)
 	sock_register(&unix_family_ops);
 	register_pernet_subsys(&unix_net_ops);
 	unix_bpf_build_proto();
+
+#if IS_BUILTIN(CONFIG_UNIX) && defined(CONFIG_BPF_SYSCALL) && defined(CONFIG_PROC_FS)
+	bpf_iter_register();
+#endif
+
 out:
 	return rc;
 }
-- 
2.30.2

[PATCH v5 bpf-next 2/4] bpf: Support "%c" in bpf_bprintf_prepare().

From: Kuniyuki Iwashima <hidden>
Date: 2021-08-12 16:46:46

/proc/net/unix uses "%c" to print a single-byte character to escape '\0' in
the name of the abstract UNIX domain socket.  The following selftest uses
it, so this patch adds support for "%c".  Note that it does not support
wide character ("%lc" and "%llc") for simplicity.

Signed-off-by: Kuniyuki Iwashima <redacted>
Acked-by: Yonghong Song <redacted>
---
 kernel/bpf/helpers.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index 15746f779fe1..6d3aaf94e9ac 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -907,6 +907,20 @@ int bpf_bprintf_prepare(char *fmt, u32 fmt_size, const u64 *raw_args,
 			tmp_buf += err;
 			num_spec++;
 
+			continue;
+		} else if (fmt[i] == 'c') {
+			if (!tmp_buf)
+				goto nocopy_fmt;
+
+			if (tmp_buf_end == tmp_buf) {
+				err = -ENOSPC;
+				goto out;
+			}
+
+			*tmp_buf = raw_args[num_spec];
+			tmp_buf++;
+			num_spec++;
+
 			continue;
 		}
 
-- 
2.30.2

[PATCH v5 bpf-next 3/4] selftest/bpf: Implement sample UNIX domain socket iterator program.

From: Kuniyuki Iwashima <hidden>
Date: 2021-08-12 16:47:00

The iterator can output almost the same result compared to /proc/net/unix.
The header line is aligned, and the Inode column uses "%8lu" because "%5lu"
can be easily overflown.

  # cat /sys/fs/bpf/unix
  Num               RefCount Protocol Flags    Type St Inode    Path
  ffff963c06689800: 00000002 00000000 00010000 0001 01    18697 private/defer
  ffff963c7c979c00: 00000002 00000000 00000000 0001 01   598245 @Hello@World@

  # cat /proc/net/unix
  Num       RefCount Protocol Flags    Type St Inode Path
  ffff963c06689800: 00000002 00000000 00010000 0001 01 18697 private/defer
  ffff963c7c979c00: 00000002 00000000 00000000 0001 01 598245 @Hello@World@

Note that this prog requires the patch ([0]) for LLVM code gen.  Thanks to
Yonghong Song for analysing and fixing.

[0] https://reviews.llvm.org/D107483

Signed-off-by: Kuniyuki Iwashima <redacted>
Acked-by: Yonghong Song <redacted>
---
 tools/testing/selftests/bpf/README.rst        | 38 +++++++++
 .../selftests/bpf/prog_tests/bpf_iter.c       | 16 ++++
 tools/testing/selftests/bpf/progs/bpf_iter.h  |  8 ++
 .../selftests/bpf/progs/bpf_iter_unix.c       | 77 +++++++++++++++++++
 .../selftests/bpf/progs/bpf_tracing_net.h     |  4 +
 5 files changed, 143 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/progs/bpf_iter_unix.c
diff --git a/tools/testing/selftests/bpf/README.rst b/tools/testing/selftests/bpf/README.rst
index 9b17f2867488..314a63b69399 100644
--- a/tools/testing/selftests/bpf/README.rst
+++ b/tools/testing/selftests/bpf/README.rst
@@ -228,3 +228,41 @@ To fix this issue, user newer libbpf.
 .. Links
 .. _clang reloc patch: https://reviews.llvm.org/D102712
 .. _kernel llvm reloc: /Documentation/bpf/llvm_reloc.rst
+
+bpf_iter_unix.o test failure and LLVM optimisation
+==================================================
+
+The ``bpf_iter/unix`` subtest requires `the fix`__ to prevent the LLVM compiler
+from transforming the loop exit condition.
+
+Without the fix, the compiler generates the following code:
+
+.. code-block:: c
+
+  ; 				 for (i = 1; i < len; i++)
+       110:	07 09 00 00 01 00 00 00	r9 += 1
+       111:	5d 98 09 00 00 00 00 00	if r8 != r9 goto +9 <LBB0_18>
+
+The loop exit condition, where the upper bound is not a constant, is
+changed from ``<`` to ``!=``.  Thus, the verifier always evaluates it as true,
+misleading to an infinite loop.
+
+.. code-block:: c
+
+  The sequence of 8193 jumps is too complex.
+  processed 196506 insns (limit 1000000) max_states_per_insn 4 total_states 1830 peak_states 1830 mark_read 3
+
+The fix prevents the optimisation by estimating its cost higher in such a
+case:
+
+.. code-block:: c
+
+  ; 				 for (i = 1; i < len; i++)
+       110:	07 09 00 00 01 00 00 00	r9 += 1
+       111:	ad 89 09 00 00 00 00 00	if r9 < r8 goto +9 <LBB0_18>
+
+The patch is available in LLVM 14 trunk and has been `backported`__ to the LLVM
+13.x release branch.
+
+__ https://reviews.llvm.org/D107483
+__ https://bugs.llvm.org/show_bug.cgi?id=51363
diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c
index 1f1aade56504..77ac24b191d4 100644
--- a/tools/testing/selftests/bpf/prog_tests/bpf_iter.c
+++ b/tools/testing/selftests/bpf/prog_tests/bpf_iter.c
@@ -13,6 +13,7 @@
 #include "bpf_iter_tcp6.skel.h"
 #include "bpf_iter_udp4.skel.h"
 #include "bpf_iter_udp6.skel.h"
+#include "bpf_iter_unix.skel.h"
 #include "bpf_iter_test_kern1.skel.h"
 #include "bpf_iter_test_kern2.skel.h"
 #include "bpf_iter_test_kern3.skel.h"
@@ -313,6 +314,19 @@ static void test_udp6(void)
 	bpf_iter_udp6__destroy(skel);
 }
 
+static void test_unix(void)
+{
+	struct bpf_iter_unix *skel;
+
+	skel = bpf_iter_unix__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "bpf_iter_unix__open_and_load"))
+		return;
+
+	do_dummy_read(skel->progs.dump_unix);
+
+	bpf_iter_unix__destroy(skel);
+}
+
 /* The expected string is less than 16 bytes */
 static int do_read_with_fd(int iter_fd, const char *expected,
 			   bool read_one_char)
@@ -1255,6 +1269,8 @@ void test_bpf_iter(void)
 		test_udp4();
 	if (test__start_subtest("udp6"))
 		test_udp6();
+	if (test__start_subtest("unix"))
+		test_unix();
 	if (test__start_subtest("anon"))
 		test_anon_iter(false);
 	if (test__start_subtest("anon-read-one-char"))
diff --git a/tools/testing/selftests/bpf/progs/bpf_iter.h b/tools/testing/selftests/bpf/progs/bpf_iter.h
index 3d83b185c4bc..8cfaeba1ddbf 100644
--- a/tools/testing/selftests/bpf/progs/bpf_iter.h
+++ b/tools/testing/selftests/bpf/progs/bpf_iter.h
@@ -12,6 +12,7 @@
 #define tcp6_sock tcp6_sock___not_used
 #define bpf_iter__udp bpf_iter__udp___not_used
 #define udp6_sock udp6_sock___not_used
+#define bpf_iter__unix bpf_iter__unix___not_used
 #define bpf_iter__bpf_map_elem bpf_iter__bpf_map_elem___not_used
 #define bpf_iter__bpf_sk_storage_map bpf_iter__bpf_sk_storage_map___not_used
 #define bpf_iter__sockmap bpf_iter__sockmap___not_used
@@ -32,6 +33,7 @@
 #undef tcp6_sock
 #undef bpf_iter__udp
 #undef udp6_sock
+#undef bpf_iter__unix
 #undef bpf_iter__bpf_map_elem
 #undef bpf_iter__bpf_sk_storage_map
 #undef bpf_iter__sockmap
@@ -103,6 +105,12 @@ struct udp6_sock {
 	struct ipv6_pinfo inet6;
 } __attribute__((preserve_access_index));
 
+struct bpf_iter__unix {
+	struct bpf_iter_meta *meta;
+	struct unix_sock *unix_sk;
+	uid_t uid;
+} __attribute__((preserve_access_index));
+
 struct bpf_iter__bpf_map_elem {
 	struct bpf_iter_meta *meta;
 	struct bpf_map *map;
diff --git a/tools/testing/selftests/bpf/progs/bpf_iter_unix.c b/tools/testing/selftests/bpf/progs/bpf_iter_unix.c
new file mode 100644
index 000000000000..0a50b610f6f3
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/bpf_iter_unix.c
@@ -0,0 +1,77 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright Amazon.com Inc. or its affiliates. */
+#include "bpf_iter.h"
+#include "bpf_tracing_net.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_endian.h>
+
+char _license[] SEC("license") = "GPL";
+
+static long sock_i_ino(const struct sock *sk)
+{
+	const struct socket *sk_socket = sk->sk_socket;
+	const struct inode *inode;
+	unsigned long ino;
+
+	if (!sk_socket)
+		return 0;
+
+	inode = &container_of(sk_socket, struct socket_alloc, socket)->vfs_inode;
+	bpf_probe_read_kernel(&ino, sizeof(ino), &inode->i_ino);
+	return ino;
+}
+
+SEC("iter/unix")
+int dump_unix(struct bpf_iter__unix *ctx)
+{
+	struct unix_sock *unix_sk = ctx->unix_sk;
+	struct sock *sk = (struct sock *)unix_sk;
+	struct seq_file *seq;
+	__u32 seq_num;
+
+	if (!unix_sk)
+		return 0;
+
+	seq = ctx->meta->seq;
+	seq_num = ctx->meta->seq_num;
+	if (seq_num == 0)
+		BPF_SEQ_PRINTF(seq, "Num               RefCount Protocol Flags    Type St Inode    Path\n");
+
+	BPF_SEQ_PRINTF(seq, "%pK: %08X %08X %08X %04X %02X %8lu",
+		       unix_sk,
+		       sk->sk_refcnt.refs.counter,
+		       0,
+		       sk->sk_state == TCP_LISTEN ? __SO_ACCEPTCON : 0,
+		       sk->sk_type,
+		       sk->sk_socket ?
+		       (sk->sk_state == TCP_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) :
+		       (sk->sk_state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING),
+		       sock_i_ino(sk));
+
+	if (unix_sk->addr) {
+		if (!UNIX_ABSTRACT(unix_sk)) {
+			BPF_SEQ_PRINTF(seq, " %s", unix_sk->addr->name->sun_path);
+		} else {
+			/* The name of the abstract UNIX domain socket starts
+			 * with '\0' and can contain '\0'.  The null bytes
+			 * should be escaped as done in unix_seq_show().
+			 */
+			int i, len;
+
+			len = unix_sk->addr->len - sizeof(short);
+
+			BPF_SEQ_PRINTF(seq, " @");
+
+			/* unix_mkname() tests this upper bound. */
+			if (len < sizeof(struct sockaddr_un))
+				for (i = 1; i < len; i++)
+					BPF_SEQ_PRINTF(seq, "%c",
+						       unix_sk->addr->name->sun_path[i] ?:
+						       '@');
+		}
+	}
+
+	BPF_SEQ_PRINTF(seq, "\n");
+
+	return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
index 3af0998a0623..eef5646ddb19 100644
--- a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
+++ b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
@@ -5,6 +5,10 @@
 #define AF_INET			2
 #define AF_INET6		10
 
+#define __SO_ACCEPTCON		(1 << 16)
+#define UNIX_HASH_SIZE		256
+#define UNIX_ABSTRACT(unix_sk)	(unix_sk->addr->hash < UNIX_HASH_SIZE)
+
 #define SOL_TCP			6
 #define TCP_CONGESTION		13
 #define TCP_CA_NAME_MAX		16
-- 
2.30.2

[PATCH v5 bpf-next 4/4] selftest/bpf: Extend the bpf_snprintf() test for "%c".

From: Kuniyuki Iwashima <hidden>
Date: 2021-08-12 16:47:24

This patch adds a "positive" pattern for "%c", which intentionally uses a
__u32 value (0x64636261, "dbca") to print a single character "a".  If the
implementation went wrong, other 3 bytes might show up as the part of the
latter "%+05s".

Also, this patch adds two "negative" patterns for wide character.

Signed-off-by: Kuniyuki Iwashima <redacted>
---
 tools/testing/selftests/bpf/prog_tests/snprintf.c | 4 +++-
 tools/testing/selftests/bpf/progs/test_snprintf.c | 7 ++++---
 2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/snprintf.c b/tools/testing/selftests/bpf/prog_tests/snprintf.c
index dffbcaa1ec98..f77d7def7fed 100644
--- a/tools/testing/selftests/bpf/prog_tests/snprintf.c
+++ b/tools/testing/selftests/bpf/prog_tests/snprintf.c
@@ -19,7 +19,7 @@
 #define EXP_ADDR_OUT "0000000000000000 ffff00000add4e55 "
 #define EXP_ADDR_RET sizeof(EXP_ADDR_OUT "unknownhashedptr")
 
-#define EXP_STR_OUT  "str1 longstr"
+#define EXP_STR_OUT  "str1         a longstr"
 #define EXP_STR_RET  sizeof(EXP_STR_OUT)
 
 #define EXP_OVER_OUT "%over"
@@ -114,6 +114,8 @@ void test_snprintf_negative(void)
 	ASSERT_ERR(load_single_snprintf("%"), "invalid specifier 3");
 	ASSERT_ERR(load_single_snprintf("%12345678"), "invalid specifier 4");
 	ASSERT_ERR(load_single_snprintf("%--------"), "invalid specifier 5");
+	ASSERT_ERR(load_single_snprintf("%lc"), "invalid specifier 6");
+	ASSERT_ERR(load_single_snprintf("%llc"), "invalid specifier 7");
 	ASSERT_ERR(load_single_snprintf("\x80"), "non ascii character");
 	ASSERT_ERR(load_single_snprintf("\x1"), "non printable character");
 }
diff --git a/tools/testing/selftests/bpf/progs/test_snprintf.c b/tools/testing/selftests/bpf/progs/test_snprintf.c
index e2ad26150f9b..afc2c583125b 100644
--- a/tools/testing/selftests/bpf/progs/test_snprintf.c
+++ b/tools/testing/selftests/bpf/progs/test_snprintf.c
@@ -40,6 +40,7 @@ int handler(const void *ctx)
 	/* Convenient values to pretty-print */
 	const __u8 ex_ipv4[] = {127, 0, 0, 1};
 	const __u8 ex_ipv6[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+	const __u32 chr1 = 0x64636261; /* dcba */
 	static const char str1[] = "str1";
 	static const char longstr[] = "longstr";
 
@@ -59,9 +60,9 @@ int handler(const void *ctx)
 	/* Kernel pointers */
 	addr_ret = BPF_SNPRINTF(addr_out, sizeof(addr_out), "%pK %px %p",
 				0, 0xFFFF00000ADD4E55, 0xFFFF00000ADD4E55);
-	/* Strings embedding */
-	str_ret  = BPF_SNPRINTF(str_out, sizeof(str_out), "%s %+05s",
-				str1, longstr);
+	/* Strings and single-byte character embedding */
+	str_ret  = BPF_SNPRINTF(str_out, sizeof(str_out), "%s % 9c %+05s",
+				str1, chr1, longstr);
 	/* Overflow */
 	over_ret = BPF_SNPRINTF(over_out, sizeof(over_out), "%%overflow");
 	/* Padding of fixed width numbers */
-- 
2.30.2

Re: [PATCH v5 bpf-next 3/4] selftest/bpf: Implement sample UNIX domain socket iterator program.

From: Andrii Nakryiko <hidden>
Date: 2021-08-13 23:26:06

On Thu, Aug 12, 2021 at 9:46 AM Kuniyuki Iwashima [off-list ref] wrote:
The iterator can output almost the same result compared to /proc/net/unix.
The header line is aligned, and the Inode column uses "%8lu" because "%5lu"
can be easily overflown.

  # cat /sys/fs/bpf/unix
  Num               RefCount Protocol Flags    Type St Inode    Path
It's totally my OCD, but why the column name is not aligned with
values? I mean the "Inode" column. It's left aligned, but values
(numbers) are right-aligned? I'd fix that while applying, but I can't
apply due to selftests failures, so please take a look.

  ffff963c06689800: 00000002 00000000 00010000 0001 01    18697 private/defer
  ffff963c7c979c00: 00000002 00000000 00000000 0001 01   598245 @Hello@World@

  # cat /proc/net/unix
  Num       RefCount Protocol Flags    Type St Inode Path
  ffff963c06689800: 00000002 00000000 00010000 0001 01 18697 private/defer
  ffff963c7c979c00: 00000002 00000000 00000000 0001 01 598245 @Hello@World@

Note that this prog requires the patch ([0]) for LLVM code gen.  Thanks to
Yonghong Song for analysing and fixing.

[0] https://reviews.llvm.org/D107483

Signed-off-by: Kuniyuki Iwashima <redacted>
Acked-by: Yonghong Song <redacted>
---
This selftests breaks test_progs-no_alu32 ([0], the error log is super
long and can freeze browser; it looks like an infinite loop and BPF
verifier just keeps reporting it until it runs out of 1mln
instructions or something). Please check what's going on there, I
can't land it as it is right now.

  [0] https://github.com/kernel-patches/bpf/runs/3326071112?check_suite_focus=true#step:6:124288

 tools/testing/selftests/bpf/README.rst        | 38 +++++++++
 .../selftests/bpf/prog_tests/bpf_iter.c       | 16 ++++
 tools/testing/selftests/bpf/progs/bpf_iter.h  |  8 ++
 .../selftests/bpf/progs/bpf_iter_unix.c       | 77 +++++++++++++++++++
 .../selftests/bpf/progs/bpf_tracing_net.h     |  4 +
 5 files changed, 143 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/progs/bpf_iter_unix.c
[...]
+                       /* The name of the abstract UNIX domain socket starts
+                        * with '\0' and can contain '\0'.  The null bytes
+                        * should be escaped as done in unix_seq_show().
+                        */
+                       int i, len;
+
no_alu32 variant probably isn't happy about using int for this, it
probably does << 32, >> 32 dance and loses track of actual value in
the loop. You can try using u64 instead.
+                       len = unix_sk->addr->len - sizeof(short);
+
+                       BPF_SEQ_PRINTF(seq, " @");
+
+                       /* unix_mkname() tests this upper bound. */
+                       if (len < sizeof(struct sockaddr_un))
+                               for (i = 1; i < len; i++)
if you move above if inside the loop to break out of the loop, does it
change how Clang generates code?

for (i = 1; i < len i++) {
    if (i >= sizeof(struct sockaddr_un))
        break;
    BPF_SEQ_PRINTF(...);
}

quoted hunk
+                                       BPF_SEQ_PRINTF(seq, "%c",
+                                                      unix_sk->addr->name->sun_path[i] ?:
+                                                      '@');
+               }
+       }
+
+       BPF_SEQ_PRINTF(seq, "\n");
+
+       return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
index 3af0998a0623..eef5646ddb19 100644
--- a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
+++ b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
@@ -5,6 +5,10 @@
 #define AF_INET                        2
 #define AF_INET6               10

+#define __SO_ACCEPTCON         (1 << 16)
+#define UNIX_HASH_SIZE         256
+#define UNIX_ABSTRACT(unix_sk) (unix_sk->addr->hash < UNIX_HASH_SIZE)
+
 #define SOL_TCP                        6
 #define TCP_CONGESTION         13
 #define TCP_CA_NAME_MAX                16
--
2.30.2

Re: [PATCH v5 bpf-next 4/4] selftest/bpf: Extend the bpf_snprintf() test for "%c".

From: Andrii Nakryiko <hidden>
Date: 2021-08-13 23:28:21

On Thu, Aug 12, 2021 at 9:47 AM Kuniyuki Iwashima [off-list ref] wrote:
quoted hunk
This patch adds a "positive" pattern for "%c", which intentionally uses a
__u32 value (0x64636261, "dbca") to print a single character "a".  If the
implementation went wrong, other 3 bytes might show up as the part of the
latter "%+05s".

Also, this patch adds two "negative" patterns for wide character.

Signed-off-by: Kuniyuki Iwashima <redacted>
---
 tools/testing/selftests/bpf/prog_tests/snprintf.c | 4 +++-
 tools/testing/selftests/bpf/progs/test_snprintf.c | 7 ++++---
 2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/snprintf.c b/tools/testing/selftests/bpf/prog_tests/snprintf.c
index dffbcaa1ec98..f77d7def7fed 100644
--- a/tools/testing/selftests/bpf/prog_tests/snprintf.c
+++ b/tools/testing/selftests/bpf/prog_tests/snprintf.c
@@ -19,7 +19,7 @@
 #define EXP_ADDR_OUT "0000000000000000 ffff00000add4e55 "
 #define EXP_ADDR_RET sizeof(EXP_ADDR_OUT "unknownhashedptr")

-#define EXP_STR_OUT  "str1 longstr"
+#define EXP_STR_OUT  "str1         a longstr"
 #define EXP_STR_RET  sizeof(EXP_STR_OUT)

 #define EXP_OVER_OUT "%over"
@@ -114,6 +114,8 @@ void test_snprintf_negative(void)
        ASSERT_ERR(load_single_snprintf("%"), "invalid specifier 3");
        ASSERT_ERR(load_single_snprintf("%12345678"), "invalid specifier 4");
        ASSERT_ERR(load_single_snprintf("%--------"), "invalid specifier 5");
+       ASSERT_ERR(load_single_snprintf("%lc"), "invalid specifier 6");
+       ASSERT_ERR(load_single_snprintf("%llc"), "invalid specifier 7");
        ASSERT_ERR(load_single_snprintf("\x80"), "non ascii character");
        ASSERT_ERR(load_single_snprintf("\x1"), "non printable character");
 }
diff --git a/tools/testing/selftests/bpf/progs/test_snprintf.c b/tools/testing/selftests/bpf/progs/test_snprintf.c
index e2ad26150f9b..afc2c583125b 100644
--- a/tools/testing/selftests/bpf/progs/test_snprintf.c
+++ b/tools/testing/selftests/bpf/progs/test_snprintf.c
@@ -40,6 +40,7 @@ int handler(const void *ctx)
        /* Convenient values to pretty-print */
        const __u8 ex_ipv4[] = {127, 0, 0, 1};
        const __u8 ex_ipv6[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+       const __u32 chr1 = 0x64636261; /* dcba */
        static const char str1[] = "str1";
        static const char longstr[] = "longstr";
@@ -59,9 +60,9 @@ int handler(const void *ctx)
        /* Kernel pointers */
        addr_ret = BPF_SNPRINTF(addr_out, sizeof(addr_out), "%pK %px %p",
                                0, 0xFFFF00000ADD4E55, 0xFFFF00000ADD4E55);
-       /* Strings embedding */
-       str_ret  = BPF_SNPRINTF(str_out, sizeof(str_out), "%s %+05s",
-                               str1, longstr);
+       /* Strings and single-byte character embedding */
+       str_ret  = BPF_SNPRINTF(str_out, sizeof(str_out), "%s % 9c %+05s",
+                               str1, chr1, longstr);

Why this hackery with __u32? You are making an endianness assumption
(it will break on big-endian), and you'd never write real code like
that. Just pass 'a', what's wrong with that?
        /* Overflow */
        over_ret = BPF_SNPRINTF(over_out, sizeof(over_out), "%%overflow");
        /* Padding of fixed width numbers */
--
2.30.2

Re: [PATCH v5 bpf-next 4/4] selftest/bpf: Extend the bpf_snprintf() test for "%c".

From: Andrii Nakryiko <hidden>
Date: 2021-08-13 23:30:42

On Fri, Aug 13, 2021 at 4:28 PM Andrii Nakryiko
[off-list ref] wrote:
On Thu, Aug 12, 2021 at 9:47 AM Kuniyuki Iwashima [off-list ref] wrote:
quoted
This patch adds a "positive" pattern for "%c", which intentionally uses a
__u32 value (0x64636261, "dbca") to print a single character "a".  If the
implementation went wrong, other 3 bytes might show up as the part of the
latter "%+05s".

Also, this patch adds two "negative" patterns for wide character.

Signed-off-by: Kuniyuki Iwashima <redacted>
---
 tools/testing/selftests/bpf/prog_tests/snprintf.c | 4 +++-
 tools/testing/selftests/bpf/progs/test_snprintf.c | 7 ++++---
 2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/snprintf.c b/tools/testing/selftests/bpf/prog_tests/snprintf.c
index dffbcaa1ec98..f77d7def7fed 100644
--- a/tools/testing/selftests/bpf/prog_tests/snprintf.c
+++ b/tools/testing/selftests/bpf/prog_tests/snprintf.c
@@ -19,7 +19,7 @@
 #define EXP_ADDR_OUT "0000000000000000 ffff00000add4e55 "
 #define EXP_ADDR_RET sizeof(EXP_ADDR_OUT "unknownhashedptr")

-#define EXP_STR_OUT  "str1 longstr"
+#define EXP_STR_OUT  "str1         a longstr"
 #define EXP_STR_RET  sizeof(EXP_STR_OUT)

 #define EXP_OVER_OUT "%over"
@@ -114,6 +114,8 @@ void test_snprintf_negative(void)
        ASSERT_ERR(load_single_snprintf("%"), "invalid specifier 3");
        ASSERT_ERR(load_single_snprintf("%12345678"), "invalid specifier 4");
        ASSERT_ERR(load_single_snprintf("%--------"), "invalid specifier 5");
+       ASSERT_ERR(load_single_snprintf("%lc"), "invalid specifier 6");
+       ASSERT_ERR(load_single_snprintf("%llc"), "invalid specifier 7");
        ASSERT_ERR(load_single_snprintf("\x80"), "non ascii character");
        ASSERT_ERR(load_single_snprintf("\x1"), "non printable character");
 }
diff --git a/tools/testing/selftests/bpf/progs/test_snprintf.c b/tools/testing/selftests/bpf/progs/test_snprintf.c
index e2ad26150f9b..afc2c583125b 100644
--- a/tools/testing/selftests/bpf/progs/test_snprintf.c
+++ b/tools/testing/selftests/bpf/progs/test_snprintf.c
@@ -40,6 +40,7 @@ int handler(const void *ctx)
        /* Convenient values to pretty-print */
        const __u8 ex_ipv4[] = {127, 0, 0, 1};
        const __u8 ex_ipv6[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+       const __u32 chr1 = 0x64636261; /* dcba */
        static const char str1[] = "str1";
        static const char longstr[] = "longstr";
@@ -59,9 +60,9 @@ int handler(const void *ctx)
        /* Kernel pointers */
        addr_ret = BPF_SNPRINTF(addr_out, sizeof(addr_out), "%pK %px %p",
                                0, 0xFFFF00000ADD4E55, 0xFFFF00000ADD4E55);
-       /* Strings embedding */
-       str_ret  = BPF_SNPRINTF(str_out, sizeof(str_out), "%s %+05s",
-                               str1, longstr);
+       /* Strings and single-byte character embedding */
+       str_ret  = BPF_SNPRINTF(str_out, sizeof(str_out), "%s % 9c %+05s",
+                               str1, chr1, longstr);
Can you also add tests for %+2c, %-3c, %04c, %0c? Think outside the box ;)

Why this hackery with __u32? You are making an endianness assumption
(it will break on big-endian), and you'd never write real code like
that. Just pass 'a', what's wrong with that?
quoted
        /* Overflow */
        over_ret = BPF_SNPRINTF(over_out, sizeof(over_out), "%%overflow");
        /* Padding of fixed width numbers */
--
2.30.2

Re: [PATCH v5 bpf-next 3/4] selftest/bpf: Implement sample UNIX domain socket iterator program.

From: Kuniyuki Iwashima <hidden>
Date: 2021-08-14 00:21:19

From:   Andrii Nakryiko <redacted>
Date:   Fri, 13 Aug 2021 16:25:53 -0700
On Thu, Aug 12, 2021 at 9:46 AM Kuniyuki Iwashima [off-list ref] wrote:
quoted
The iterator can output almost the same result compared to /proc/net/unix.
The header line is aligned, and the Inode column uses "%8lu" because "%5lu"
can be easily overflown.

  # cat /sys/fs/bpf/unix
  Num               RefCount Protocol Flags    Type St Inode    Path
It's totally my OCD, but why the column name is not aligned with
values? I mean the "Inode" column. It's left aligned, but values
(numbers) are right-aligned? I'd fix that while applying, but I can't
apply due to selftests failures, so please take a look.
Ah, honestly, I've felt something strange about the column... will fix it!

quoted
  ffff963c06689800: 00000002 00000000 00010000 0001 01    18697 private/defer
  ffff963c7c979c00: 00000002 00000000 00000000 0001 01   598245 @Hello@World@

  # cat /proc/net/unix
  Num       RefCount Protocol Flags    Type St Inode Path
  ffff963c06689800: 00000002 00000000 00010000 0001 01 18697 private/defer
  ffff963c7c979c00: 00000002 00000000 00000000 0001 01 598245 @Hello@World@

Note that this prog requires the patch ([0]) for LLVM code gen.  Thanks to
Yonghong Song for analysing and fixing.

[0] https://reviews.llvm.org/D107483

Signed-off-by: Kuniyuki Iwashima <redacted>
Acked-by: Yonghong Song <redacted>
---
This selftests breaks test_progs-no_alu32 ([0], the error log is super
long and can freeze browser; it looks like an infinite loop and BPF
verifier just keeps reporting it until it runs out of 1mln
instructions or something). Please check what's going on there, I
can't land it as it is right now.

  [0] https://github.com/kernel-patches/bpf/runs/3326071112?check_suite_focus=true#step:6:124288

quoted
 tools/testing/selftests/bpf/README.rst        | 38 +++++++++
 .../selftests/bpf/prog_tests/bpf_iter.c       | 16 ++++
 tools/testing/selftests/bpf/progs/bpf_iter.h  |  8 ++
 .../selftests/bpf/progs/bpf_iter_unix.c       | 77 +++++++++++++++++++
 .../selftests/bpf/progs/bpf_tracing_net.h     |  4 +
 5 files changed, 143 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/progs/bpf_iter_unix.c
[...]
quoted
+                       /* The name of the abstract UNIX domain socket starts
+                        * with '\0' and can contain '\0'.  The null bytes
+                        * should be escaped as done in unix_seq_show().
+                        */
+                       int i, len;
+
no_alu32 variant probably isn't happy about using int for this, it
probably does << 32, >> 32 dance and loses track of actual value in
the loop. You can try using u64 instead.
Sorry, I missed the no_alu32 test.
Changing int to __u64 fixed the error, thanks!

quoted
+                       len = unix_sk->addr->len - sizeof(short);
+
+                       BPF_SEQ_PRINTF(seq, " @");
+
+                       /* unix_mkname() tests this upper bound. */
+                       if (len < sizeof(struct sockaddr_un))
+                               for (i = 1; i < len; i++)
if you move above if inside the loop to break out of the loop, does it
change how Clang generates code?

for (i = 1; i < len i++) {
    if (i >= sizeof(struct sockaddr_un))
        break;
    BPF_SEQ_PRINTF(...);
}
Yes, but there seems little defference.
Which is preferable?

---8<---
before (for inside if) <- -> after (if inside loop)
      96:	07 08 00 00 fe ff ff ff	r8 += -2			  |	; 			for (i = 1; i < len; i++) {
; 			if (len < sizeof(struct sockaddr_un))		  |	      97:	bf 81 00 00 00 00 00 00	r1 = r8
      97:	25 08 10 00 6d 00 00 00	if r8 > 109 goto +16 <LBB0_21>	  |	      98:	07 01 00 00 fc ff ff ff	r1 += -4
; 				for (i = 1; i < len; i++)		  |	      99:	25 01 12 00 6b 00 00 00	if r1 > 107 goto +18 <LBB0_21>
      98:	a5 08 0f 00 02 00 00 00	if r8 < 2 goto +15 <LBB0_21>	  |	     100:	07 08 00 00 fe ff ff ff	r8 += -2
      99:	b7 09 00 00 01 00 00 00	r9 = 1				  |	     101:	b7 09 00 00 01 00 00 00	r9 = 1
     100:	05 00 16 00 00 00 00 00	goto +22 <LBB0_18>		  |	     102:	b7 06 00 00 02 00 00 00	r6 = 2
									  |	     103:	05 00 17 00 00 00 00 00	goto +23 <LBB0_17>
...
     111:	85 00 00 00 7e 00 00 00	call 126			  |	     113:	b4 05 00 00 08 00 00 00	w5 = 8
; 				for (i = 1; i < len; i++)		  |	     114:	85 00 00 00 7e 00 00 00	call 126
     112:	07 09 00 00 01 00 00 00	r9 += 1				  |	; 			for (i = 1; i < len; i++) {
     113:	ad 89 09 00 00 00 00 00	if r9 < r8 goto +9 <LBB0_18>	  |	     115:	25 08 02 00 6d 00 00 00	if r8 > 109 goto +2 <LBB0_21>
									  >	     116:	07 09 00 00 01 00 00 00	r9 += 1
									  >	; 			for (i = 1; i < len; i++) {
									  >	     117:	ad 89 09 00 00 00 00 00	if r9 < r8 goto +9 <LBB0_17>
---8<---

quoted
+                                       BPF_SEQ_PRINTF(seq, "%c",
+                                                      unix_sk->addr->name->sun_path[i] ?:
+                                                      '@');
+               }
+       }
+
+       BPF_SEQ_PRINTF(seq, "\n");
+
+       return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
index 3af0998a0623..eef5646ddb19 100644
--- a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
+++ b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
@@ -5,6 +5,10 @@
 #define AF_INET                        2
 #define AF_INET6               10

+#define __SO_ACCEPTCON         (1 << 16)
+#define UNIX_HASH_SIZE         256
+#define UNIX_ABSTRACT(unix_sk) (unix_sk->addr->hash < UNIX_HASH_SIZE)
+
 #define SOL_TCP                        6
 #define TCP_CONGESTION         13
 #define TCP_CA_NAME_MAX                16
--
2.30.2

Re: [PATCH v5 bpf-next 3/4] selftest/bpf: Implement sample UNIX domain socket iterator program.

From: Andrii Nakryiko <hidden>
Date: 2021-08-14 00:26:19

On Fri, Aug 13, 2021 at 5:21 PM Kuniyuki Iwashima [off-list ref] wrote:
From:   Andrii Nakryiko <redacted>
Date:   Fri, 13 Aug 2021 16:25:53 -0700
quoted
On Thu, Aug 12, 2021 at 9:46 AM Kuniyuki Iwashima [off-list ref] wrote:
quoted
The iterator can output almost the same result compared to /proc/net/unix.
The header line is aligned, and the Inode column uses "%8lu" because "%5lu"
can be easily overflown.

  # cat /sys/fs/bpf/unix
  Num               RefCount Protocol Flags    Type St Inode    Path
It's totally my OCD, but why the column name is not aligned with
values? I mean the "Inode" column. It's left aligned, but values
(numbers) are right-aligned? I'd fix that while applying, but I can't
apply due to selftests failures, so please take a look.
Ah, honestly, I've felt something strange about the column... will fix it!

quoted
quoted
  ffff963c06689800: 00000002 00000000 00010000 0001 01    18697 private/defer
  ffff963c7c979c00: 00000002 00000000 00000000 0001 01   598245 @Hello@World@

  # cat /proc/net/unix
  Num       RefCount Protocol Flags    Type St Inode Path
  ffff963c06689800: 00000002 00000000 00010000 0001 01 18697 private/defer
  ffff963c7c979c00: 00000002 00000000 00000000 0001 01 598245 @Hello@World@

Note that this prog requires the patch ([0]) for LLVM code gen.  Thanks to
Yonghong Song for analysing and fixing.

[0] https://reviews.llvm.org/D107483

Signed-off-by: Kuniyuki Iwashima <redacted>
Acked-by: Yonghong Song <redacted>
---
This selftests breaks test_progs-no_alu32 ([0], the error log is super
long and can freeze browser; it looks like an infinite loop and BPF
verifier just keeps reporting it until it runs out of 1mln
instructions or something). Please check what's going on there, I
can't land it as it is right now.

  [0] https://github.com/kernel-patches/bpf/runs/3326071112?check_suite_focus=true#step:6:124288

quoted
 tools/testing/selftests/bpf/README.rst        | 38 +++++++++
 .../selftests/bpf/prog_tests/bpf_iter.c       | 16 ++++
 tools/testing/selftests/bpf/progs/bpf_iter.h  |  8 ++
 .../selftests/bpf/progs/bpf_iter_unix.c       | 77 +++++++++++++++++++
 .../selftests/bpf/progs/bpf_tracing_net.h     |  4 +
 5 files changed, 143 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/progs/bpf_iter_unix.c
[...]
quoted
+                       /* The name of the abstract UNIX domain socket starts
+                        * with '\0' and can contain '\0'.  The null bytes
+                        * should be escaped as done in unix_seq_show().
+                        */
+                       int i, len;
+
no_alu32 variant probably isn't happy about using int for this, it
probably does << 32, >> 32 dance and loses track of actual value in
the loop. You can try using u64 instead.
Sorry, I missed the no_alu32 test.
Changing int to __u64 fixed the error, thanks!

quoted
quoted
+                       len = unix_sk->addr->len - sizeof(short);
+
+                       BPF_SEQ_PRINTF(seq, " @");
+
+                       /* unix_mkname() tests this upper bound. */
+                       if (len < sizeof(struct sockaddr_un))
+                               for (i = 1; i < len; i++)
if you move above if inside the loop to break out of the loop, does it
change how Clang generates code?

for (i = 1; i < len i++) {
    if (i >= sizeof(struct sockaddr_un))
        break;
    BPF_SEQ_PRINTF(...);
}
Yes, but there seems little defference.
Which is preferable?

---8<---
before (for inside if) <- -> after (if inside loop)
      96:       07 08 00 00 fe ff ff ff r8 += -2                          |     ;                       for (i = 1; i < len; i++) {
;                       if (len < sizeof(struct sockaddr_un))             |           97:       bf 81 00 00 00 00 00 00 r1 = r8
      97:       25 08 10 00 6d 00 00 00 if r8 > 109 goto +16 <LBB0_21>    |           98:       07 01 00 00 fc ff ff ff r1 += -4
;                               for (i = 1; i < len; i++)                 |           99:       25 01 12 00 6b 00 00 00 if r1 > 107 goto +18 <LBB0_21>
      98:       a5 08 0f 00 02 00 00 00 if r8 < 2 goto +15 <LBB0_21>      |          100:       07 08 00 00 fe ff ff ff r8 += -2
      99:       b7 09 00 00 01 00 00 00 r9 = 1                            |          101:       b7 09 00 00 01 00 00 00 r9 = 1
     100:       05 00 16 00 00 00 00 00 goto +22 <LBB0_18>                |          102:       b7 06 00 00 02 00 00 00 r6 = 2
                                                                          |          103:       05 00 17 00 00 00 00 00 goto +23 <LBB0_17>
...
     111:       85 00 00 00 7e 00 00 00 call 126                          |          113:       b4 05 00 00 08 00 00 00 w5 = 8
;                               for (i = 1; i < len; i++)                 |          114:       85 00 00 00 7e 00 00 00 call 126
     112:       07 09 00 00 01 00 00 00 r9 += 1                           |     ;                       for (i = 1; i < len; i++) {
     113:       ad 89 09 00 00 00 00 00 if r9 < r8 goto +9 <LBB0_18>      |          115:       25 08 02 00 6d 00 00 00 if r8 > 109 goto +2 <LBB0_21>
                                                                          >          116:       07 09 00 00 01 00 00 00 r9 += 1
                                                                          >     ;                       for (i = 1; i < len; i++) {
                                                                          >          117:       ad 89 09 00 00 00 00 00 if r9 < r8 goto +9 <LBB0_17>
---8<---
Have you tried running the variant I proposed on Clang without
Yonghong's recent fix? I wonder if it works without that fix (not that
there is anything wrong about the fix, but if we can avoid depending
on it, it would be great).
quoted
quoted
+                                       BPF_SEQ_PRINTF(seq, "%c",
+                                                      unix_sk->addr->name->sun_path[i] ?:
+                                                      '@');
+               }
+       }
+
+       BPF_SEQ_PRINTF(seq, "\n");
+
+       return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
index 3af0998a0623..eef5646ddb19 100644
--- a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
+++ b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
@@ -5,6 +5,10 @@
 #define AF_INET                        2
 #define AF_INET6               10

+#define __SO_ACCEPTCON         (1 << 16)
+#define UNIX_HASH_SIZE         256
+#define UNIX_ABSTRACT(unix_sk) (unix_sk->addr->hash < UNIX_HASH_SIZE)
+
 #define SOL_TCP                        6
 #define TCP_CONGESTION         13
 #define TCP_CA_NAME_MAX                16
--
2.30.2

Re: [PATCH v5 bpf-next 4/4] selftest/bpf: Extend the bpf_snprintf() test for "%c".

From: Kuniyuki Iwashima <hidden>
Date: 2021-08-14 00:37:18

From:   Andrii Nakryiko <redacted>
Date:   Fri, 13 Aug 2021 16:30:29 -0700
On Fri, Aug 13, 2021 at 4:28 PM Andrii Nakryiko
[off-list ref] wrote:
quoted
On Thu, Aug 12, 2021 at 9:47 AM Kuniyuki Iwashima [off-list ref] wrote:
quoted
This patch adds a "positive" pattern for "%c", which intentionally uses a
__u32 value (0x64636261, "dbca") to print a single character "a".  If the
implementation went wrong, other 3 bytes might show up as the part of the
latter "%+05s".

Also, this patch adds two "negative" patterns for wide character.

Signed-off-by: Kuniyuki Iwashima <redacted>
---
 tools/testing/selftests/bpf/prog_tests/snprintf.c | 4 +++-
 tools/testing/selftests/bpf/progs/test_snprintf.c | 7 ++++---
 2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/snprintf.c b/tools/testing/selftests/bpf/prog_tests/snprintf.c
index dffbcaa1ec98..f77d7def7fed 100644
--- a/tools/testing/selftests/bpf/prog_tests/snprintf.c
+++ b/tools/testing/selftests/bpf/prog_tests/snprintf.c
@@ -19,7 +19,7 @@
 #define EXP_ADDR_OUT "0000000000000000 ffff00000add4e55 "
 #define EXP_ADDR_RET sizeof(EXP_ADDR_OUT "unknownhashedptr")

-#define EXP_STR_OUT  "str1 longstr"
+#define EXP_STR_OUT  "str1         a longstr"
 #define EXP_STR_RET  sizeof(EXP_STR_OUT)

 #define EXP_OVER_OUT "%over"
@@ -114,6 +114,8 @@ void test_snprintf_negative(void)
        ASSERT_ERR(load_single_snprintf("%"), "invalid specifier 3");
        ASSERT_ERR(load_single_snprintf("%12345678"), "invalid specifier 4");
        ASSERT_ERR(load_single_snprintf("%--------"), "invalid specifier 5");
+       ASSERT_ERR(load_single_snprintf("%lc"), "invalid specifier 6");
+       ASSERT_ERR(load_single_snprintf("%llc"), "invalid specifier 7");
        ASSERT_ERR(load_single_snprintf("\x80"), "non ascii character");
        ASSERT_ERR(load_single_snprintf("\x1"), "non printable character");
 }
diff --git a/tools/testing/selftests/bpf/progs/test_snprintf.c b/tools/testing/selftests/bpf/progs/test_snprintf.c
index e2ad26150f9b..afc2c583125b 100644
--- a/tools/testing/selftests/bpf/progs/test_snprintf.c
+++ b/tools/testing/selftests/bpf/progs/test_snprintf.c
@@ -40,6 +40,7 @@ int handler(const void *ctx)
        /* Convenient values to pretty-print */
        const __u8 ex_ipv4[] = {127, 0, 0, 1};
        const __u8 ex_ipv6[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+       const __u32 chr1 = 0x64636261; /* dcba */
        static const char str1[] = "str1";
        static const char longstr[] = "longstr";
@@ -59,9 +60,9 @@ int handler(const void *ctx)
        /* Kernel pointers */
        addr_ret = BPF_SNPRINTF(addr_out, sizeof(addr_out), "%pK %px %p",
                                0, 0xFFFF00000ADD4E55, 0xFFFF00000ADD4E55);
-       /* Strings embedding */
-       str_ret  = BPF_SNPRINTF(str_out, sizeof(str_out), "%s %+05s",
-                               str1, longstr);
+       /* Strings and single-byte character embedding */
+       str_ret  = BPF_SNPRINTF(str_out, sizeof(str_out), "%s % 9c %+05s",
+                               str1, chr1, longstr);
Can you also add tests for %+2c, %-3c, %04c, %0c? Think outside the box ;)
Sure.

quoted
Why this hackery with __u32? You are making an endianness assumption
(it will break on big-endian), and you'd never write real code like
that. Just pass 'a', what's wrong with that?
In my first implementation of "%c" support, I tried to support "%lc" and
"%llc" also and reused the later int code.  Then just testing 'a' was ok,
but it was wrong with the 0x64636261, three bytes of which showed up as
part of the next %s.  So, I thought it would be better to test with int.
But exactly it breaks the big-endian case, I'll just pass 'a'.

quoted
quoted
        /* Overflow */
        over_ret = BPF_SNPRINTF(over_out, sizeof(over_out), "%%overflow");
        /* Padding of fixed width numbers */
--
2.30.2

Re: [PATCH v5 bpf-next 3/4] selftest/bpf: Implement sample UNIX domain socket iterator program.

From: Kuniyuki Iwashima <hidden>
Date: 2021-08-14 01:01:02

From:   Andrii Nakryiko <redacted>
Date:   Fri, 13 Aug 2021 17:26:05 -0700
On Fri, Aug 13, 2021 at 5:21 PM Kuniyuki Iwashima [off-list ref] wrote:
quoted
From:   Andrii Nakryiko <redacted>
Date:   Fri, 13 Aug 2021 16:25:53 -0700
quoted
On Thu, Aug 12, 2021 at 9:46 AM Kuniyuki Iwashima [off-list ref] wrote:
quoted
The iterator can output almost the same result compared to /proc/net/unix.
The header line is aligned, and the Inode column uses "%8lu" because "%5lu"
can be easily overflown.

  # cat /sys/fs/bpf/unix
  Num               RefCount Protocol Flags    Type St Inode    Path
It's totally my OCD, but why the column name is not aligned with
values? I mean the "Inode" column. It's left aligned, but values
(numbers) are right-aligned? I'd fix that while applying, but I can't
apply due to selftests failures, so please take a look.
Ah, honestly, I've felt something strange about the column... will fix it!

quoted
quoted
  ffff963c06689800: 00000002 00000000 00010000 0001 01    18697 private/defer
  ffff963c7c979c00: 00000002 00000000 00000000 0001 01   598245 @Hello@World@

  # cat /proc/net/unix
  Num       RefCount Protocol Flags    Type St Inode Path
  ffff963c06689800: 00000002 00000000 00010000 0001 01 18697 private/defer
  ffff963c7c979c00: 00000002 00000000 00000000 0001 01 598245 @Hello@World@

Note that this prog requires the patch ([0]) for LLVM code gen.  Thanks to
Yonghong Song for analysing and fixing.

[0] https://reviews.llvm.org/D107483

Signed-off-by: Kuniyuki Iwashima <redacted>
Acked-by: Yonghong Song <redacted>
---
This selftests breaks test_progs-no_alu32 ([0], the error log is super
long and can freeze browser; it looks like an infinite loop and BPF
verifier just keeps reporting it until it runs out of 1mln
instructions or something). Please check what's going on there, I
can't land it as it is right now.

  [0] https://github.com/kernel-patches/bpf/runs/3326071112?check_suite_focus=true#step:6:124288

quoted
 tools/testing/selftests/bpf/README.rst        | 38 +++++++++
 .../selftests/bpf/prog_tests/bpf_iter.c       | 16 ++++
 tools/testing/selftests/bpf/progs/bpf_iter.h  |  8 ++
 .../selftests/bpf/progs/bpf_iter_unix.c       | 77 +++++++++++++++++++
 .../selftests/bpf/progs/bpf_tracing_net.h     |  4 +
 5 files changed, 143 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/progs/bpf_iter_unix.c
[...]
quoted
+                       /* The name of the abstract UNIX domain socket starts
+                        * with '\0' and can contain '\0'.  The null bytes
+                        * should be escaped as done in unix_seq_show().
+                        */
+                       int i, len;
+
no_alu32 variant probably isn't happy about using int for this, it
probably does << 32, >> 32 dance and loses track of actual value in
the loop. You can try using u64 instead.
Sorry, I missed the no_alu32 test.
Changing int to __u64 fixed the error, thanks!

quoted
quoted
+                       len = unix_sk->addr->len - sizeof(short);
+
+                       BPF_SEQ_PRINTF(seq, " @");
+
+                       /* unix_mkname() tests this upper bound. */
+                       if (len < sizeof(struct sockaddr_un))
+                               for (i = 1; i < len; i++)
if you move above if inside the loop to break out of the loop, does it
change how Clang generates code?

for (i = 1; i < len i++) {
    if (i >= sizeof(struct sockaddr_un))
        break;
    BPF_SEQ_PRINTF(...);
}
Yes, but there seems little defference.
Which is preferable?

---8<---
before (for inside if) <- -> after (if inside loop)
      96:       07 08 00 00 fe ff ff ff r8 += -2                          |     ;                       for (i = 1; i < len; i++) {
;                       if (len < sizeof(struct sockaddr_un))             |           97:       bf 81 00 00 00 00 00 00 r1 = r8
      97:       25 08 10 00 6d 00 00 00 if r8 > 109 goto +16 <LBB0_21>    |           98:       07 01 00 00 fc ff ff ff r1 += -4
;                               for (i = 1; i < len; i++)                 |           99:       25 01 12 00 6b 00 00 00 if r1 > 107 goto +18 <LBB0_21>
      98:       a5 08 0f 00 02 00 00 00 if r8 < 2 goto +15 <LBB0_21>      |          100:       07 08 00 00 fe ff ff ff r8 += -2
      99:       b7 09 00 00 01 00 00 00 r9 = 1                            |          101:       b7 09 00 00 01 00 00 00 r9 = 1
     100:       05 00 16 00 00 00 00 00 goto +22 <LBB0_18>                |          102:       b7 06 00 00 02 00 00 00 r6 = 2
                                                                          |          103:       05 00 17 00 00 00 00 00 goto +23 <LBB0_17>
...
     111:       85 00 00 00 7e 00 00 00 call 126                          |          113:       b4 05 00 00 08 00 00 00 w5 = 8
;                               for (i = 1; i < len; i++)                 |          114:       85 00 00 00 7e 00 00 00 call 126
     112:       07 09 00 00 01 00 00 00 r9 += 1                           |     ;                       for (i = 1; i < len; i++) {
     113:       ad 89 09 00 00 00 00 00 if r9 < r8 goto +9 <LBB0_18>      |          115:       25 08 02 00 6d 00 00 00 if r8 > 109 goto +2 <LBB0_21>
                                                                          >          116:       07 09 00 00 01 00 00 00 r9 += 1
                                                                          >     ;                       for (i = 1; i < len; i++) {
                                                                          >          117:       ad 89 09 00 00 00 00 00 if r9 < r8 goto +9 <LBB0_17>
---8<---
Have you tried running the variant I proposed on Clang without
Yonghong's recent fix? I wonder if it works without that fix (not that
there is anything wrong about the fix, but if we can avoid depending
on it, it would be great).
It was with the fix.

I rebuilt LLVM without the fix, then the if-inside-for code worked well :)
There was no transformation from '<' to '!='.

I'll drop the change in README and respin with your suggestion soon.

---8<---
; 			for (i = 1; i < len; i++) {
      97:	bf 81 00 00 00 00 00 00	r1 = r8
      98:	07 01 00 00 fc ff ff ff	r1 += -4
      99:	25 01 12 00 6b 00 00 00	if r1 > 107 goto +18 <LBB0_21>
     100:	07 08 00 00 fe ff ff ff	r8 += -2
     101:	b7 09 00 00 01 00 00 00	r9 = 1
     102:	b7 06 00 00 02 00 00 00	r6 = 2
     103:	05 00 17 00 00 00 00 00	goto +23 <LBB0_17>
...
; 			for (i = 1; i < len; i++) {
     115:	25 08 02 00 6d 00 00 00	if r8 > 109 goto +2 <LBB0_21>
     116:	07 09 00 00 01 00 00 00	r9 += 1
; 			for (i = 1; i < len; i++) {
     117:	ad 89 09 00 00 00 00 00	if r9 < r8 goto +9 <LBB0_17>
---8<---

quoted
quoted
quoted
+                                       BPF_SEQ_PRINTF(seq, "%c",
+                                                      unix_sk->addr->name->sun_path[i] ?:
+                                                      '@');
+               }
+       }
+
+       BPF_SEQ_PRINTF(seq, "\n");
+
+       return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
index 3af0998a0623..eef5646ddb19 100644
--- a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
+++ b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
@@ -5,6 +5,10 @@
 #define AF_INET                        2
 #define AF_INET6               10

+#define __SO_ACCEPTCON         (1 << 16)
+#define UNIX_HASH_SIZE         256
+#define UNIX_ABSTRACT(unix_sk) (unix_sk->addr->hash < UNIX_HASH_SIZE)
+
 #define SOL_TCP                        6
 #define TCP_CONGESTION         13
 #define TCP_CA_NAME_MAX                16
--
2.30.2

Re: [PATCH v5 bpf-next 3/4] selftest/bpf: Implement sample UNIX domain socket iterator program.

From: Yonghong Song <hidden>
Date: 2021-08-15 18:11:29


On 8/13/21 5:21 PM, Kuniyuki Iwashima wrote:
From:   Andrii Nakryiko <redacted>
Date:   Fri, 13 Aug 2021 16:25:53 -0700
quoted
On Thu, Aug 12, 2021 at 9:46 AM Kuniyuki Iwashima [off-list ref] wrote:
quoted
The iterator can output almost the same result compared to /proc/net/unix.
The header line is aligned, and the Inode column uses "%8lu" because "%5lu"
can be easily overflown.

   # cat /sys/fs/bpf/unix
   Num               RefCount Protocol Flags    Type St Inode    Path
It's totally my OCD, but why the column name is not aligned with
values? I mean the "Inode" column. It's left aligned, but values
(numbers) are right-aligned? I'd fix that while applying, but I can't
apply due to selftests failures, so please take a look.
Ah, honestly, I've felt something strange about the column... will fix it!

quoted
quoted
   ffff963c06689800: 00000002 00000000 00010000 0001 01    18697 private/defer
   ffff963c7c979c00: 00000002 00000000 00000000 0001 01   598245 @Hello@World@

   # cat /proc/net/unix
   Num       RefCount Protocol Flags    Type St Inode Path
   ffff963c06689800: 00000002 00000000 00010000 0001 01 18697 private/defer
   ffff963c7c979c00: 00000002 00000000 00000000 0001 01 598245 @Hello@World@

Note that this prog requires the patch ([0]) for LLVM code gen.  Thanks to
Yonghong Song for analysing and fixing.

[0] https://reviews.llvm.org/D107483

Signed-off-by: Kuniyuki Iwashima <redacted>
Acked-by: Yonghong Song <redacted>
---
This selftests breaks test_progs-no_alu32 ([0], the error log is super
long and can freeze browser; it looks like an infinite loop and BPF
verifier just keeps reporting it until it runs out of 1mln
instructions or something). Please check what's going on there, I
can't land it as it is right now.

   [0] https://github.com/kernel-patches/bpf/runs/3326071112?check_suite_focus=true#step:6:124288

quoted
  tools/testing/selftests/bpf/README.rst        | 38 +++++++++
  .../selftests/bpf/prog_tests/bpf_iter.c       | 16 ++++
  tools/testing/selftests/bpf/progs/bpf_iter.h  |  8 ++
  .../selftests/bpf/progs/bpf_iter_unix.c       | 77 +++++++++++++++++++
  .../selftests/bpf/progs/bpf_tracing_net.h     |  4 +
  5 files changed, 143 insertions(+)
  create mode 100644 tools/testing/selftests/bpf/progs/bpf_iter_unix.c
[...]
quoted
+                       /* The name of the abstract UNIX domain socket starts
+                        * with '\0' and can contain '\0'.  The null bytes
+                        * should be escaped as done in unix_seq_show().
+                        */
+                       int i, len;
+
no_alu32 variant probably isn't happy about using int for this, it
probably does << 32, >> 32 dance and loses track of actual value in
the loop. You can try using u64 instead.
Sorry, I missed the no_alu32 test.
Changing int to __u64 fixed the error, thanks!
Indeed for no_alu32, the index has << 32 and >> 32, which makes
verifier *equivalent* register tracking not effective, see below:

       96:       r1 = r8 

       97:       r1 <<= 32 

       98:       r2 = r1 

       99:       r2 >>= 32 

      100:       if r2 > 109 goto +19 <LBB0_21> 

      101:       r1 s>>= 32 

      102:       if r1 s< 2 goto +17 <LBB0_21> 

      103:       r9 = 1 

      104:       r8 <<= 32 

      105:       r8 >>= 32

Because these shifting, r1/r2/r8 equivalence cannot be
easily established, so verifier ends with conservative
r8 and cannot verify program successfully.

Using __u64 for 'i' and 'len', the upper bound is directly
tested:
       98:       if r8 > 109 goto +16 <LBB0_21> 

       99:       if r8 < 2 goto +15 <LBB0_21>
and verifier is very happy with this.
quoted
quoted
+                       len = unix_sk->addr->len - sizeof(short);
+
+                       BPF_SEQ_PRINTF(seq, " @");
+
+                       /* unix_mkname() tests this upper bound. */
+                       if (len < sizeof(struct sockaddr_un))
+                               for (i = 1; i < len; i++)
if you move above if inside the loop to break out of the loop, does it
change how Clang generates code?

for (i = 1; i < len i++) {
     if (i >= sizeof(struct sockaddr_un))
         break;
     BPF_SEQ_PRINTF(...);
}
Yes, but there seems little defference.
Which is preferable?

---8<---
before (for inside if) <- -> after (if inside loop)
       96:	07 08 00 00 fe ff ff ff	r8 += -2			  |	; 			for (i = 1; i < len; i++) {
; 			if (len < sizeof(struct sockaddr_un))		  |	      97:	bf 81 00 00 00 00 00 00	r1 = r8
       97:	25 08 10 00 6d 00 00 00	if r8 > 109 goto +16 <LBB0_21>	  |	      98:	07 01 00 00 fc ff ff ff	r1 += -4
; 				for (i = 1; i < len; i++)		  |	      99:	25 01 12 00 6b 00 00 00	if r1 > 107 goto +18 <LBB0_21>
       98:	a5 08 0f 00 02 00 00 00	if r8 < 2 goto +15 <LBB0_21>	  |	     100:	07 08 00 00 fe ff ff ff	r8 += -2
       99:	b7 09 00 00 01 00 00 00	r9 = 1				  |	     101:	b7 09 00 00 01 00 00 00	r9 = 1
      100:	05 00 16 00 00 00 00 00	goto +22 <LBB0_18>		  |	     102:	b7 06 00 00 02 00 00 00	r6 = 2
									  |	     103:	05 00 17 00 00 00 00 00	goto +23 <LBB0_17>
...
      111:	85 00 00 00 7e 00 00 00	call 126			  |	     113:	b4 05 00 00 08 00 00 00	w5 = 8
; 				for (i = 1; i < len; i++)		  |	     114:	85 00 00 00 7e 00 00 00	call 126
      112:	07 09 00 00 01 00 00 00	r9 += 1				  |	; 			for (i = 1; i < len; i++) {
      113:	ad 89 09 00 00 00 00 00	if r9 < r8 goto +9 <LBB0_18>	  |	     115:	25 08 02 00 6d 00 00 00	if r8 > 109 goto +2 <LBB0_21>
									  >	     116:	07 09 00 00 01 00 00 00	r9 += 1
									  >	; 			for (i = 1; i < len; i++) {
									  >	     117:	ad 89 09 00 00 00 00 00	if r9 < r8 goto +9 <LBB0_17>
---8<---

quoted
quoted
+                                       BPF_SEQ_PRINTF(seq, "%c",
+                                                      unix_sk->addr->name->sun_path[i] ?:
+                                                      '@');
+               }
+       }
+
+       BPF_SEQ_PRINTF(seq, "\n");
+
+       return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
index 3af0998a0623..eef5646ddb19 100644
--- a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
+++ b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
@@ -5,6 +5,10 @@
  #define AF_INET                        2
  #define AF_INET6               10

+#define __SO_ACCEPTCON         (1 << 16)
+#define UNIX_HASH_SIZE         256
+#define UNIX_ABSTRACT(unix_sk) (unix_sk->addr->hash < UNIX_HASH_SIZE)
+
  #define SOL_TCP                        6
  #define TCP_CONGESTION         13
  #define TCP_CA_NAME_MAX                16
--
2.30.2

Re: [PATCH v5 bpf-next 3/4] selftest/bpf: Implement sample UNIX domain socket iterator program.

From: Kuniyuki Iwashima <hidden>
Date: 2021-08-16 12:45:34

From:   Yonghong Song <redacted>
Date:   Sun, 15 Aug 2021 11:10:49 -0700
On 8/13/21 5:21 PM, Kuniyuki Iwashima wrote:
quoted
From:   Andrii Nakryiko <redacted>
Date:   Fri, 13 Aug 2021 16:25:53 -0700
quoted
On Thu, Aug 12, 2021 at 9:46 AM Kuniyuki Iwashima [off-list ref] wrote:
quoted
The iterator can output almost the same result compared to /proc/net/unix.
The header line is aligned, and the Inode column uses "%8lu" because "%5lu"
can be easily overflown.

   # cat /sys/fs/bpf/unix
   Num               RefCount Protocol Flags    Type St Inode    Path
It's totally my OCD, but why the column name is not aligned with
values? I mean the "Inode" column. It's left aligned, but values
(numbers) are right-aligned? I'd fix that while applying, but I can't
apply due to selftests failures, so please take a look.
Ah, honestly, I've felt something strange about the column... will fix it!

quoted
quoted
   ffff963c06689800: 00000002 00000000 00010000 0001 01    18697 private/defer
   ffff963c7c979c00: 00000002 00000000 00000000 0001 01   598245 @Hello@World@

   # cat /proc/net/unix
   Num       RefCount Protocol Flags    Type St Inode Path
   ffff963c06689800: 00000002 00000000 00010000 0001 01 18697 private/defer
   ffff963c7c979c00: 00000002 00000000 00000000 0001 01 598245 @Hello@World@

Note that this prog requires the patch ([0]) for LLVM code gen.  Thanks to
Yonghong Song for analysing and fixing.

[0] https://reviews.llvm.org/D107483

Signed-off-by: Kuniyuki Iwashima <redacted>
Acked-by: Yonghong Song <redacted>
---
This selftests breaks test_progs-no_alu32 ([0], the error log is super
long and can freeze browser; it looks like an infinite loop and BPF
verifier just keeps reporting it until it runs out of 1mln
instructions or something). Please check what's going on there, I
can't land it as it is right now.

   [0] https://github.com/kernel-patches/bpf/runs/3326071112?check_suite_focus=true#step:6:124288

quoted
  tools/testing/selftests/bpf/README.rst        | 38 +++++++++
  .../selftests/bpf/prog_tests/bpf_iter.c       | 16 ++++
  tools/testing/selftests/bpf/progs/bpf_iter.h  |  8 ++
  .../selftests/bpf/progs/bpf_iter_unix.c       | 77 +++++++++++++++++++
  .../selftests/bpf/progs/bpf_tracing_net.h     |  4 +
  5 files changed, 143 insertions(+)
  create mode 100644 tools/testing/selftests/bpf/progs/bpf_iter_unix.c
[...]
quoted
+                       /* The name of the abstract UNIX domain socket starts
+                        * with '\0' and can contain '\0'.  The null bytes
+                        * should be escaped as done in unix_seq_show().
+                        */
+                       int i, len;
+
no_alu32 variant probably isn't happy about using int for this, it
probably does << 32, >> 32 dance and loses track of actual value in
the loop. You can try using u64 instead.
Sorry, I missed the no_alu32 test.
Changing int to __u64 fixed the error, thanks!
Indeed for no_alu32, the index has << 32 and >> 32, which makes
verifier *equivalent* register tracking not effective, see below:

       96:       r1 = r8 

       97:       r1 <<= 32 

       98:       r2 = r1 

       99:       r2 >>= 32 

      100:       if r2 > 109 goto +19 <LBB0_21> 

      101:       r1 s>>= 32 

      102:       if r1 s< 2 goto +17 <LBB0_21> 

      103:       r9 = 1 

      104:       r8 <<= 32 

      105:       r8 >>= 32

Because these shifting, r1/r2/r8 equivalence cannot be
easily established, so verifier ends with conservative
r8 and cannot verify program successfully.

Using __u64 for 'i' and 'len', the upper bound is directly
tested:
       98:       if r8 > 109 goto +16 <LBB0_21> 

       99:       if r8 < 2 goto +15 <LBB0_21>
and verifier is very happy with this.
Thanks for explanation!

I understand that the shift dance is to mimic the overflow of int because
actually 64-bit register is allocated to 'i' and 32-bit operations cannot
be used in no_alu32 test, so using __64 to remove the dance resolves it.

quoted
quoted
quoted
+                       len = unix_sk->addr->len - sizeof(short);
+
+                       BPF_SEQ_PRINTF(seq, " @");
+
+                       /* unix_mkname() tests this upper bound. */
+                       if (len < sizeof(struct sockaddr_un))
+                               for (i = 1; i < len; i++)
if you move above if inside the loop to break out of the loop, does it
change how Clang generates code?

for (i = 1; i < len i++) {
     if (i >= sizeof(struct sockaddr_un))
         break;
     BPF_SEQ_PRINTF(...);
}
Yes, but there seems little defference.
Which is preferable?

---8<---
before (for inside if) <- -> after (if inside loop)
       96:	07 08 00 00 fe ff ff ff	r8 += -2			  |	; 			for (i = 1; i < len; i++) {
; 			if (len < sizeof(struct sockaddr_un))		  |	      97:	bf 81 00 00 00 00 00 00	r1 = r8
       97:	25 08 10 00 6d 00 00 00	if r8 > 109 goto +16 <LBB0_21>	  |	      98:	07 01 00 00 fc ff ff ff	r1 += -4
; 				for (i = 1; i < len; i++)		  |	      99:	25 01 12 00 6b 00 00 00	if r1 > 107 goto +18 <LBB0_21>
       98:	a5 08 0f 00 02 00 00 00	if r8 < 2 goto +15 <LBB0_21>	  |	     100:	07 08 00 00 fe ff ff ff	r8 += -2
       99:	b7 09 00 00 01 00 00 00	r9 = 1				  |	     101:	b7 09 00 00 01 00 00 00	r9 = 1
      100:	05 00 16 00 00 00 00 00	goto +22 <LBB0_18>		  |	     102:	b7 06 00 00 02 00 00 00	r6 = 2
									  |	     103:	05 00 17 00 00 00 00 00	goto +23 <LBB0_17>
...
      111:	85 00 00 00 7e 00 00 00	call 126			  |	     113:	b4 05 00 00 08 00 00 00	w5 = 8
; 				for (i = 1; i < len; i++)		  |	     114:	85 00 00 00 7e 00 00 00	call 126
      112:	07 09 00 00 01 00 00 00	r9 += 1				  |	; 			for (i = 1; i < len; i++) {
      113:	ad 89 09 00 00 00 00 00	if r9 < r8 goto +9 <LBB0_18>	  |	     115:	25 08 02 00 6d 00 00 00	if r8 > 109 goto +2 <LBB0_21>
									  >	     116:	07 09 00 00 01 00 00 00	r9 += 1
									  >	; 			for (i = 1; i < len; i++) {
									  >	     117:	ad 89 09 00 00 00 00 00	if r9 < r8 goto +9 <LBB0_17>
---8<---

quoted
quoted
+                                       BPF_SEQ_PRINTF(seq, "%c",
+                                                      unix_sk->addr->name->sun_path[i] ?:
+                                                      '@');
+               }
+       }
+
+       BPF_SEQ_PRINTF(seq, "\n");
+
+       return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
index 3af0998a0623..eef5646ddb19 100644
--- a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
+++ b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
@@ -5,6 +5,10 @@
  #define AF_INET                        2
  #define AF_INET6               10

+#define __SO_ACCEPTCON         (1 << 16)
+#define UNIX_HASH_SIZE         256
+#define UNIX_ABSTRACT(unix_sk) (unix_sk->addr->hash < UNIX_HASH_SIZE)
+
  #define SOL_TCP                        6
  #define TCP_CONGESTION         13
  #define TCP_CA_NAME_MAX                16
--
2.30.2
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help