Skip to contentSkip to conversation

Various fixes for sockmap and reuseport tests

PATCH Superseded Lorenz Bauer 5 participants 26 messages Jan 23, 2020 – Jan 24, 2020

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

cover Various fixes for sockmap and reuseport tests

I noticed some rough edges while running the sockmap and reuseport tests in a virtme environment. It only has a single CPU, and the root filesystem is mounted read-only.

The cause for patch #2 is either the VM being slow because it only has a single CPU. Patches #3-4 helped me narrow down the problem, so they are probably useful for others as well.

Lorenz Bauer (4):
selftests: bpf: use a temporary file in test_sockmap
selftests: bpf: ignore RST packets for reuseport tests
selftests: bpf: make reuseport test output more legible
selftests: bpf: reset global state between reuseport test runs

 .../bpf/prog_tests/select_reuseport.c         | 44 ++++++++++++++++---
 .../bpf/progs/test_select_reuseport_kern.c    |  6 +++
 tools/testing/selftests/bpf/test_sockmap.c    | 15 +++----
 3 files changed, 50 insertions(+), 15 deletions(-)
Signature · 1 line
2.20.1
#1 lore raw

PATCH 1/4 selftests: bpf: use a temporary file in test_sockmap

Use a proper temporary file for sendpage tests. This means that running the tests doesn't clutter the working directory, and allows running the test on read-only filesystems.

---
 tools/testing/selftests/bpf/test_sockmap.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)
tools/testing/selftests/bpf/test_sockmap.c +5 -10
index 4a851513c842..779e11da979c 100644
@@ -331,7 +331,7 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
 	FILE *file;
 	int i, fp;
 
-	file = fopen(".sendpage_tst.tmp", "w+");
+	file = tmpfile();
 	if (!file) {
 		perror("create file for sendpage");
 		return 1;
@@ -340,13 +340,8 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
 		fwrite(&k, sizeof(char), 1, file);
 	fflush(file);
 	fseek(file, 0, SEEK_SET);
-	fclose(file);
 
-	fp = open(".sendpage_tst.tmp", O_RDONLY);
-	if (fp < 0) {
-		perror("reopen file for sendpage");
-		return 1;
-	}
+	fp = fileno(file);
 
 	clock_gettime(CLOCK_MONOTONIC, &s->start);
 	for (i = 0; i < cnt; i++) {
@@ -354,11 +349,11 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
 
 		if (!drop && sent < 0) {
 			perror("send loop error");
-			close(fp);
+			fclose(file);
 			return sent;
 		} else if (drop && sent >= 0) {
 			printf("sendpage loop error expected: %i\n", sent);
-			close(fp);
+			fclose(file);
 			return -EIO;
 		}
 
@@ -366,7 +361,7 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
 			s->bytes_sent += sent;
 	}
 	clock_gettime(CLOCK_MONOTONIC, &s->end);
-	close(fp);
+	fclose(file);
 	return 0;
 }
 
Signature · 1 line
2.20.1
#2 lore raw

Re: [PATCH bpf 1/4] selftests: bpf: use a temporary file in test_sockmap

Quoted 24 lines · Lorenz Bauer

Use a proper temporary file for sendpage tests. This means that running the tests doesn't clutter the working directory, and allows running the test on read-only filesystems.

---
 tools/testing/selftests/bpf/test_sockmap.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)
tools/testing/selftests/bpf/test_sockmap.c +1 -1
index 4a851513c842..779e11da979c 100644
@@ -331,7 +331,7 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
 	FILE *file;
 	int i, fp;
 
-	file = fopen(".sendpage_tst.tmp", "w+");
+	file = tmpfile();
 	if (!file) {
 		perror("create file for sendpage");
 		return 1;
@@ -340,13 +340,8 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
 		fwrite(&k, sizeof(char), 1, file);

tools/testing/selftests/bpf/test_sockmap.c static int msg_loop_sendpage(int fd, int iov_length, int cnt, · line 344

Quoted 10 lines
tools/testing/selftests/bpf/test_sockmap.c +1 -6
 	fflush(file);
 	fseek(file, 0, SEEK_SET);
-	fclose(file);
 
-	fp = open(".sendpage_tst.tmp", O_RDONLY);
-	if (fp < 0) {
-		perror("reopen file for sendpage");
-		return 1;
-	}
+	fp = fileno(file);

It may be better to keep fp == -1 check here. It is not clear to me the original intention of reopen. I would defer to John for comment.

Quoted 3 lines
tools/testing/selftests/bpf/test_sockmap.c +0 -0
 	clock_gettime(CLOCK_MONOTONIC, &s->start);
 	for (i = 0; i < cnt; i++) {
#3 lore raw

Re: [PATCH bpf 1/4] selftests: bpf: use a temporary file in test_sockmap

Quoted 29 lines · Martin Lau
Quoted 28 lines · Lorenz Bauer

Use a proper temporary file for sendpage tests. This means that running the tests doesn't clutter the working directory, and allows running the test on read-only filesystems.

---
 tools/testing/selftests/bpf/test_sockmap.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)
tools/testing/selftests/bpf/test_sockmap.c +1 -2
index 4a851513c842..779e11da979c 100644
@@ -331,7 +331,7 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
 	FILE *file;
 	int i, fp;
 
-	file = fopen(".sendpage_tst.tmp", "w+");
+	file = tmpfile();
 	if (!file) {
 		perror("create file for sendpage");
 		return 1;
@@ -340,13 +340,8 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
 		fwrite(&k, sizeof(char), 1, file);
 	fflush(file);
 	fseek(file, 0, SEEK_SET);
-	fclose(file);
 
Quoted 10 lines

tools/testing/selftests/bpf/test_sockmap.c static int msg_loop_sendpage(int fd, int iov_length, int cnt, · line 344

Quoted 6 lines
tools/testing/selftests/bpf/test_sockmap.c +1 -5
-	fp = open(".sendpage_tst.tmp", O_RDONLY);
-	if (fp < 0) {
-		perror("reopen file for sendpage");
-		return 1;
-	}
+	fp = fileno(file);

It may be better to keep fp == -1 check here. It is not clear to me the original intention of reopen. I would defer to John for comment.

Seeing fileno shouldn't fail seems OK to me.

Quoted 3 lines
Quoted 3 lines
tools/testing/selftests/bpf/test_sockmap.c +0 -0
 	clock_gettime(CLOCK_MONOTONIC, &s->start);
 	for (i = 0; i < cnt; i++) {
#4 lore raw

Re: [PATCH bpf 1/4] selftests: bpf: use a temporary file in test_sockmap

In reply to Lorenz Bauer
Quoted 14 lines · Lorenz Bauer

Use a proper temporary file for sendpage tests. This means that running the tests doesn't clutter the working directory, and allows running the test on read-only filesystems.

---
 tools/testing/selftests/bpf/test_sockmap.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)
tools/testing/selftests/bpf/test_sockmap.c +0 -0
index 4a851513c842..779e11da979c 100644

tools/testing/selftests/bpf/test_sockmap.c static int msg_loop_sendpage(int fd, int iov_length, int cnt, · line 337

Quoted 8 lines
tools/testing/selftests/bpf/test_sockmap.c +1 -1
@@ -331,7 +331,7 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
 	FILE *file;
 	int i, fp;
 
-	file = fopen(".sendpage_tst.tmp", "w+");
+	file = tmpfile();
 	if (!file) {
 		perror("create file for sendpage");
 		return 1;

memfd_create() would be an alternative that doesn't clutter anything.

[...]

Acked-by on v1 1/4
#5 lore raw

RE: [PATCH bpf 1/4] selftests: bpf: use a temporary file in test_sockmap

In reply to Lorenz Bauer
Quoted 9 lines · Lorenz Bauer

Use a proper temporary file for sendpage tests. This means that running the tests doesn't clutter the working directory, and allows running the test on read-only filesystems.

---
 tools/testing/selftests/bpf/test_sockmap.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

Agree nice bit of cleanup. We should merge this in bpf-next though considering its late in the bpf tree.

#6 lore raw

PATCH 2/4 selftests: bpf: ignore RST packets for reuseport tests

In reply to Lorenz Bauer

The reuseport tests currently suffer from a race condition: RST packets count towards DROP_ERR_SKB_DATA, since they don't contain a valid struct cmd. Tests will spuriously fail depending on whether check_results is called before or after the RST is processed.

Exit the BPF program early if FIN is set.

---
 .../selftests/bpf/progs/test_select_reuseport_kern.c        | 6 ++++++
 1 file changed, 6 insertions(+)
tools/testing/selftests/bpf/progs/test_select_reuseport_kern.c +6 -0
index d69a1f2bbbfd..26e77dcc7e91 100644
@@ -113,6 +113,12 @@ int _select_by_skb_data(struct sk_reuseport_md *reuse_md)
 		data_check.skb_ports[0] = th->source;
 		data_check.skb_ports[1] = th->dest;
 
+		if (th->fin)
+			/* The connection is being torn down at the end of a
+			 * test. It can't contain a cmd, so return early.
+			 */
+			return SK_PASS;
+
 		if ((th->doff << 2) + sizeof(*cmd) > data_check.len)
 			GOTO_DONE(DROP_ERR_SKB_DATA);
 		if (bpf_skb_load_bytes(reuse_md, th->doff << 2, &cmd_copy,
Signature · 1 line
2.20.1
#7 lore raw

Re: [PATCH bpf 2/4] selftests: bpf: ignore RST packets for reuseport tests

Quoted 6 lines · Lorenz Bauer

The reuseport tests currently suffer from a race condition: RST packets count towards DROP_ERR_SKB_DATA, since they don't contain a valid struct cmd. Tests will spuriously fail depending on whether check_results is called before or after the RST is processed.

Exit the BPF program early if FIN is set.

Make sense.
Is it a RST or FIN? The earlier commit message said RST.

#8 lore raw

Re: [PATCH bpf 2/4] selftests: bpf: ignore RST packets for reuseport tests

Quoted 10 lines · Martin Lau
Quoted 6 lines · Lorenz Bauer

The reuseport tests currently suffer from a race condition: RST packets count towards DROP_ERR_SKB_DATA, since they don't contain a valid struct cmd. Tests will spuriously fail depending on whether check_results is called before or after the RST is processed.

Exit the BPF program early if FIN is set.

Make sense.
Is it a RST or FIN? The earlier commit message said RST.

FIN, sorry. I'll update in a follow up.

Signature · 4 lines
Lorenz Bauer  |  Systems Engineer
6th Floor, County Hall/The Riverside Building, SE1 7PB, UK

www.cloudflare.com
#9 lore raw

Re: [PATCH bpf 2/4] selftests: bpf: ignore RST packets for reuseport tests

In reply to Lorenz Bauer
Quoted 6 lines · Lorenz Bauer

The reuseport tests currently suffer from a race condition: RST packets count towards DROP_ERR_SKB_DATA, since they don't contain a valid struct cmd. Tests will spuriously fail depending on whether check_results is called before or after the RST is processed.

Exit the BPF program early if FIN is set.

btw, it needs a Fixes tag.

Patch 4 and Patch 1 also need a Fixes tag.

#10 lore raw

Re: [PATCH bpf 2/4] selftests: bpf: ignore RST packets for reuseport tests

Quoted 4 lines · Martin Lau

btw, it needs a Fixes tag.

Patch 4 and Patch 1 also need a Fixes tag.

This makes me wonder, should these go via bpf or bpf-next? Do I have to split the series then?

Signature · 4 lines
Lorenz Bauer  |  Systems Engineer
6th Floor, County Hall/The Riverside Building, SE1 7PB, UK

www.cloudflare.com
maintainer
#11 lore raw

Re: [PATCH bpf 2/4] selftests: bpf: ignore RST packets for reuseport tests

Quoted 8 lines · Lorenz Bauer
Quoted 4 lines · Martin Lau

btw, it needs a Fixes tag.

Patch 4 and Patch 1 also need a Fixes tag.

This makes me wonder, should these go via bpf or bpf-next? Do I have to split the series then?

Lets do all of these for bpf-next since timing is very close before v5.5 release. If needed, we can later have them picked up for 5.5 stable.

Thanks,
Daniel

Acked-by on v1 2/4
#12 lore raw

RE: [PATCH bpf 2/4] selftests: bpf: ignore RST packets for reuseport tests

In reply to Lorenz Bauer
Quoted 32 lines · Lorenz Bauer

The reuseport tests currently suffer from a race condition: RST packets count towards DROP_ERR_SKB_DATA, since they don't contain a valid struct cmd. Tests will spuriously fail depending on whether check_results is called before or after the RST is processed.

Exit the BPF program early if FIN is set.

---
 .../selftests/bpf/progs/test_select_reuseport_kern.c        | 6 ++++++
 1 file changed, 6 insertions(+)
tools/testing/selftests/bpf/progs/test_select_reuseport_kern.c +6 -0
index d69a1f2bbbfd..26e77dcc7e91 100644
@@ -113,6 +113,12 @@ int _select_by_skb_data(struct sk_reuseport_md *reuse_md)
 		data_check.skb_ports[0] = th->source;
 		data_check.skb_ports[1] = th->dest;
 
+		if (th->fin)
+			/* The connection is being torn down at the end of a
+			 * test. It can't contain a cmd, so return early.
+			 */
+			return SK_PASS;
+
 		if ((th->doff << 2) + sizeof(*cmd) > data_check.len)
 			GOTO_DONE(DROP_ERR_SKB_DATA);
 		if (bpf_skb_load_bytes(reuse_md, th->doff << 2, &cmd_copy,
Signature · 1 line
2.20.1
#13 lore raw

PATCH 3/4 selftests: bpf: make reuseport test output more legible

In reply to Lorenz Bauer

Include the name of the mismatching result in human readable format when reporting an error. The new output looks like the following:

unexpected result
result: [1, 0, 0, 0, 0, 0]
expected: [0, 0, 0, 0, 0, 0]
mismatch on DROP_ERR_INNER_MAP (bpf_prog_linum:153) check_results:FAIL:382

---
 .../bpf/prog_tests/select_reuseport.c         | 30 ++++++++++++++++---
 1 file changed, 26 insertions(+), 4 deletions(-)
tools/testing/selftests/bpf/prog_tests/select_reuseport.c +26 -4
index 2c37ae7dc214..09a536af139a 100644
@@ -316,6 +316,28 @@ static void check_data(int type, sa_family_t family, const struct cmd *cmd,
 		       expected.len, result.len, get_linum());
 }
 
+static const char *result_to_str(enum result res)
+{
+	switch (res) {
+	case DROP_ERR_INNER_MAP:
+		return "DROP_ERR_INNER_MAP";
+	case DROP_ERR_SKB_DATA:
+		return "DROP_ERR_SKB_DATA";
+	case DROP_ERR_SK_SELECT_REUSEPORT:
+		return "DROP_ERR_SK_SELECT_REUSEPORT";
+	case DROP_MISC:
+		return "DROP_MISC";
+	case PASS:
+		return "PASS";
+	case PASS_ERR_SK_SELECT_REUSEPORT:
+		return "PASS_ERR_SK_SELECT_REUSEPORT";
+	case NR_RESULTS:
+		return "NR_RESULTS";
+	default:
+		return "UNKNOWN";
+	}
+}
+
 static void check_results(void)
 {
 	__u32 results[NR_RESULTS];
@@ -351,10 +373,10 @@ static void check_results(void)
 		printf(", %u", expected_results[i]);
 	printf("]\n");
 
-	RET_IF(expected_results[broken] != results[broken],
-	       "unexpected result",
-	       "expected_results[%u] != results[%u] bpf_prog_linum:%ld\n",
-	       broken, broken, get_linum());
+	printf("mismatch on %s (bpf_prog_linum:%ld)\n", result_to_str(broken),
+	       get_linum());
+
+	CHECK_FAIL(true);
 }
 
 static int send_data(int type, sa_family_t family, void *data, size_t len,
Signature · 1 line
2.20.1
#14 lore raw

Re: [PATCH bpf 3/4] selftests: bpf: make reuseport test output more legible

Quoted 28 lines · Lorenz Bauer

Include the name of the mismatching result in human readable format when reporting an error. The new output looks like the following:

unexpected result
result: [1, 0, 0, 0, 0, 0]
expected: [0, 0, 0, 0, 0, 0]
mismatch on DROP_ERR_INNER_MAP (bpf_prog_linum:153) check_results:FAIL:382

---
 .../bpf/prog_tests/select_reuseport.c         | 30 ++++++++++++++++---
 1 file changed, 26 insertions(+), 4 deletions(-)
tools/testing/selftests/bpf/prog_tests/select_reuseport.c +6 -0
index 2c37ae7dc214..09a536af139a 100644
@@ -316,6 +316,28 @@ static void check_data(int type, sa_family_t family, const struct cmd *cmd,
 		       expected.len, result.len, get_linum());
 }
 
+static const char *result_to_str(enum result res)
+{
+	switch (res) {
+	case DROP_ERR_INNER_MAP:
+		return "DROP_ERR_INNER_MAP";
+	case DROP_ERR_SKB_DATA:

tools/testing/selftests/bpf/prog_tests/select_reuseport.c static void check_data(int type, sa_family_t family, const struct cmd *cmd, · line 334

Quoted 10 lines
tools/testing/selftests/bpf/prog_tests/select_reuseport.c +10 -0
+		return "DROP_ERR_SKB_DATA";
+	case DROP_ERR_SK_SELECT_REUSEPORT:
+		return "DROP_ERR_SK_SELECT_REUSEPORT";
+	case DROP_MISC:
+		return "DROP_MISC";
+	case PASS:
+		return "PASS";
+	case PASS_ERR_SK_SELECT_REUSEPORT:
+		return "PASS_ERR_SK_SELECT_REUSEPORT";
+	case NR_RESULTS:

This should return "UNKNOWN" also.

Quoted 6 lines
tools/testing/selftests/bpf/prog_tests/select_reuseport.c +6 -0
+		return "NR_RESULTS";
+	default:
+		return "UNKNOWN";
+	}
+}
+
Acked-by on v1 3/4
#15 lore raw

RE: [PATCH bpf 3/4] selftests: bpf: make reuseport test output more legible

In reply to Lorenz Bauer
Quoted 65 lines · Lorenz Bauer

Include the name of the mismatching result in human readable format when reporting an error. The new output looks like the following:

unexpected result
result: [1, 0, 0, 0, 0, 0]
expected: [0, 0, 0, 0, 0, 0]
mismatch on DROP_ERR_INNER_MAP (bpf_prog_linum:153) check_results:FAIL:382

---
 .../bpf/prog_tests/select_reuseport.c         | 30 ++++++++++++++++---
 1 file changed, 26 insertions(+), 4 deletions(-)
tools/testing/selftests/bpf/prog_tests/select_reuseport.c +26 -4
index 2c37ae7dc214..09a536af139a 100644
@@ -316,6 +316,28 @@ static void check_data(int type, sa_family_t family, const struct cmd *cmd,
 		       expected.len, result.len, get_linum());
 }
 
+static const char *result_to_str(enum result res)
+{
+	switch (res) {
+	case DROP_ERR_INNER_MAP:
+		return "DROP_ERR_INNER_MAP";
+	case DROP_ERR_SKB_DATA:
+		return "DROP_ERR_SKB_DATA";
+	case DROP_ERR_SK_SELECT_REUSEPORT:
+		return "DROP_ERR_SK_SELECT_REUSEPORT";
+	case DROP_MISC:
+		return "DROP_MISC";
+	case PASS:
+		return "PASS";
+	case PASS_ERR_SK_SELECT_REUSEPORT:
+		return "PASS_ERR_SK_SELECT_REUSEPORT";
+	case NR_RESULTS:
+		return "NR_RESULTS";
+	default:
+		return "UNKNOWN";
+	}
+}
+
 static void check_results(void)
 {
 	__u32 results[NR_RESULTS];
@@ -351,10 +373,10 @@ static void check_results(void)
 		printf(", %u", expected_results[i]);
 	printf("]\n");
 
-	RET_IF(expected_results[broken] != results[broken],
-	       "unexpected result",
-	       "expected_results[%u] != results[%u] bpf_prog_linum:%ld\n",
-	       broken, broken, get_linum());
+	printf("mismatch on %s (bpf_prog_linum:%ld)\n", result_to_str(broken),
+	       get_linum());
+
+	CHECK_FAIL(true);
 }
 
 static int send_data(int type, sa_family_t family, void *data, size_t len,
Signature · 1 line
2.20.1
#16 lore raw

PATCH 4/4 selftests: bpf: reset global state between reuseport test runs

In reply to Lorenz Bauer

Currently, there is a lot of false positives if a single reuseport test fails. This is because expected_results and the result map are not cleared.

Zero both after individual test runs, which fixes the mentioned false positives.

---
 .../selftests/bpf/prog_tests/select_reuseport.c    | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)
tools/testing/selftests/bpf/prog_tests/select_reuseport.c +13 -1
index 09a536af139a..0bab8b1ca1c3 100644
@@ -699,7 +699,19 @@ static void setup_per_test(int type, sa_family_t family, bool inany,
 
 static void cleanup_per_test(bool no_inner_map)
 {
-	int i, err;
+	int i, err, zero = 0;
+
+	memset(expected_results, 0, sizeof(expected_results));
+
+	for (i = 0; i < NR_RESULTS; i++) {
+		err = bpf_map_update_elem(result_map, &i, &zero, BPF_ANY);
+		RET_IF(err, "reset elem in result_map",
+		       "i:%u err:%d errno:%d\n", i, err, errno);
+	}
+
+	err = bpf_map_update_elem(linum_map, &zero, &zero, BPF_ANY);
+	RET_IF(err, "reset line number in linum_map", "err:%d errno:%d\n",
+	       err, errno);
 
 	for (i = 0; i < REUSEPORT_ARRAY_SIZE; i++)
 		close(sk_fds[i]);
Signature · 1 line
2.20.1
Acked-by on v1 4/4
#17 lore raw

Re: [PATCH bpf 4/4] selftests: bpf: reset global state between reuseport test runs

Quoted 2 lines · Lorenz Bauer

Currently, there is a lot of false positives if a single reuseport test fails. This is because expected_results and the result map are not cleared.

Ah, right. An earlier test failure has ripple effect on the following tests.

I notice another embarrassing typo. Can you also make this change in this fix?

-static enum result expected_results[NR_RESULTS];
+static __u32 expected_results[NR_RESULTS];

Quoted 3 lines

Zero both after individual test runs, which fixes the mentioned false positives.

Thanks for the fix!

#18 lore raw

v2 cover Various fixes for sockmap and reuseport tests

In reply to Lorenz Bauer

I've fixed the commit messages, added Fixes tags and am submitting to bpf-next instead of the bpf tree.

There is still the question whether patch #1 needs to preserve O_RDONLY, which John can hopefully answer.

Lorenz Bauer (4):
selftests: bpf: use a temporary file in test_sockmap
selftests: bpf: ignore FIN packets for reuseport tests
selftests: bpf: make reuseport test output more legible
selftests: bpf: reset global state between reuseport test runs

 .../bpf/prog_tests/select_reuseport.c         | 44 ++++++++++++++++---
 .../bpf/progs/test_select_reuseport_kern.c    |  6 +++
 tools/testing/selftests/bpf/test_sockmap.c    | 15 +++----
 3 files changed, 49 insertions(+), 16 deletions(-)
Signature · 1 line
2.20.1
#19 lore raw

PATCH v2 1/4 selftests: bpf: use a temporary file in test_sockmap

Use a proper temporary file for sendpage tests. This means that running the tests doesn't clutter the working directory, and allows running the test on read-only filesystems.

Fixes 16962b2404ac ("bpf: sockmap, add selftests")
---
 tools/testing/selftests/bpf/test_sockmap.c | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)
tools/testing/selftests/bpf/test_sockmap.c +5 -10
index 4a851513c842..779e11da979c 100644
@@ -331,7 +331,7 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
 	FILE *file;
 	int i, fp;
 
-	file = fopen(".sendpage_tst.tmp", "w+");
+	file = tmpfile();
 	if (!file) {
 		perror("create file for sendpage");
 		return 1;
@@ -340,13 +340,8 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
 		fwrite(&k, sizeof(char), 1, file);
 	fflush(file);
 	fseek(file, 0, SEEK_SET);
-	fclose(file);
 
-	fp = open(".sendpage_tst.tmp", O_RDONLY);
-	if (fp < 0) {
-		perror("reopen file for sendpage");
-		return 1;
-	}
+	fp = fileno(file);
 
 	clock_gettime(CLOCK_MONOTONIC, &s->start);
 	for (i = 0; i < cnt; i++) {
@@ -354,11 +349,11 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
 
 		if (!drop && sent < 0) {
 			perror("send loop error");
-			close(fp);
+			fclose(file);
 			return sent;
 		} else if (drop && sent >= 0) {
 			printf("sendpage loop error expected: %i\n", sent);
-			close(fp);
+			fclose(file);
 			return -EIO;
 		}
 
@@ -366,7 +361,7 @@ static int msg_loop_sendpage(int fd, int iov_length, int cnt,
 			s->bytes_sent += sent;
 	}
 	clock_gettime(CLOCK_MONOTONIC, &s->end);
-	close(fp);
+	fclose(file);
 	return 0;
 }
 
Signature · 1 line
2.20.1
#20 lore raw

PATCH v2 2/4 selftests: bpf: ignore FIN packets for reuseport tests

In reply to Lorenz Bauer

The reuseport tests currently suffer from a race condition: FIN packets count towards DROP_ERR_SKB_DATA, since they don't contain a valid struct cmd. Tests will spuriously fail depending on whether check_results is called before or after the FIN is processed.

Exit the BPF program early if FIN is set.

Fixes 91134d849a0e ("bpf: Test BPF_PROG_TYPE_SK_REUSEPORT")
---
 .../selftests/bpf/progs/test_select_reuseport_kern.c        | 6 ++++++
 1 file changed, 6 insertions(+)
tools/testing/selftests/bpf/progs/test_select_reuseport_kern.c +6 -0
index d69a1f2bbbfd..26e77dcc7e91 100644
@@ -113,6 +113,12 @@ int _select_by_skb_data(struct sk_reuseport_md *reuse_md)
 		data_check.skb_ports[0] = th->source;
 		data_check.skb_ports[1] = th->dest;
 
+		if (th->fin)
+			/* The connection is being torn down at the end of a
+			 * test. It can't contain a cmd, so return early.
+			 */
+			return SK_PASS;
+
 		if ((th->doff << 2) + sizeof(*cmd) > data_check.len)
 			GOTO_DONE(DROP_ERR_SKB_DATA);
 		if (bpf_skb_load_bytes(reuse_md, th->doff << 2, &cmd_copy,
Signature · 1 line
2.20.1
#21 lore raw

PATCH v2 3/4 selftests: bpf: make reuseport test output more legible

In reply to Lorenz Bauer

Include the name of the mismatching result in human readable format when reporting an error. The new output looks like the following:

unexpected result
result: [1, 0, 0, 0, 0, 0]
expected: [0, 0, 0, 0, 0, 0]
mismatch on DROP_ERR_INNER_MAP (bpf_prog_linum:153) check_results:FAIL:382

---
 .../bpf/prog_tests/select_reuseport.c         | 28 ++++++++++++++++---
 1 file changed, 24 insertions(+), 4 deletions(-)
tools/testing/selftests/bpf/prog_tests/select_reuseport.c +24 -4
index 2c37ae7dc214..e7e56929751c 100644
@@ -316,6 +316,26 @@ static void check_data(int type, sa_family_t family, const struct cmd *cmd,
 		       expected.len, result.len, get_linum());
 }
 
+static const char *result_to_str(enum result res)
+{
+	switch (res) {
+	case DROP_ERR_INNER_MAP:
+		return "DROP_ERR_INNER_MAP";
+	case DROP_ERR_SKB_DATA:
+		return "DROP_ERR_SKB_DATA";
+	case DROP_ERR_SK_SELECT_REUSEPORT:
+		return "DROP_ERR_SK_SELECT_REUSEPORT";
+	case DROP_MISC:
+		return "DROP_MISC";
+	case PASS:
+		return "PASS";
+	case PASS_ERR_SK_SELECT_REUSEPORT:
+		return "PASS_ERR_SK_SELECT_REUSEPORT";
+	default:
+		return "UNKNOWN";
+	}
+}
+
 static void check_results(void)
 {
 	__u32 results[NR_RESULTS];
@@ -351,10 +371,10 @@ static void check_results(void)
 		printf(", %u", expected_results[i]);
 	printf("]\n");
 
-	RET_IF(expected_results[broken] != results[broken],
-	       "unexpected result",
-	       "expected_results[%u] != results[%u] bpf_prog_linum:%ld\n",
-	       broken, broken, get_linum());
+	printf("mismatch on %s (bpf_prog_linum:%ld)\n", result_to_str(broken),
+	       get_linum());
+
+	CHECK_FAIL(true);
 }
 
 static int send_data(int type, sa_family_t family, void *data, size_t len,
Signature · 1 line
2.20.1
#22 lore raw

PATCH v2 4/4 selftests: bpf: reset global state between reuseport test runs

In reply to Lorenz Bauer

Currently, there is a lot of false positives if a single reuseport test fails. This is because expected_results and the result map are not cleared.

Zero both after individual test runs, which fixes the mentioned false positives.

Fixes 91134d849a0e ("bpf: Test BPF_PROG_TYPE_SK_REUSEPORT")
---
 .../selftests/bpf/prog_tests/select_reuseport.c  | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)
tools/testing/selftests/bpf/prog_tests/select_reuseport.c +14 -2
index e7e56929751c..098bcae5f827 100644
@@ -33,7 +33,7 @@
 #define REUSEPORT_ARRAY_SIZE 32
 
 static int result_map, tmp_index_ovr_map, linum_map, data_check_map;
-static enum result expected_results[NR_RESULTS];
+static __u32 expected_results[NR_RESULTS];
 static int sk_fds[REUSEPORT_ARRAY_SIZE];
 static int reuseport_array = -1, outer_map = -1;
 static int select_by_skb_data_prog;
@@ -697,7 +697,19 @@ static void setup_per_test(int type, sa_family_t family, bool inany,
 
 static void cleanup_per_test(bool no_inner_map)
 {
-	int i, err;
+	int i, err, zero = 0;
+
+	memset(expected_results, 0, sizeof(expected_results));
+
+	for (i = 0; i < NR_RESULTS; i++) {
+		err = bpf_map_update_elem(result_map, &i, &zero, BPF_ANY);
+		RET_IF(err, "reset elem in result_map",
+		       "i:%u err:%d errno:%d\n", i, err, errno);
+	}
+
+	err = bpf_map_update_elem(linum_map, &zero, &zero, BPF_ANY);
+	RET_IF(err, "reset line number in linum_map", "err:%d errno:%d\n",
+	       err, errno);
 
 	for (i = 0; i < REUSEPORT_ARRAY_SIZE; i++)
 		close(sk_fds[i]);
Signature · 1 line
2.20.1
Reviewed-by on the v2 series
#23 lore raw
In reply to Lorenz Bauer
Quoted 12 lines · Lorenz Bauer

I've fixed the commit messages, added Fixes tags and am submitting to bpf-next instead of the bpf tree.

There is still the question whether patch #1 needs to preserve O_RDONLY, which John can hopefully answer.

Lorenz Bauer (4):
selftests: bpf: use a temporary file in test_sockmap
selftests: bpf: ignore FIN packets for reuseport tests
selftests: bpf: make reuseport test output more legible
selftests: bpf: reset global state between reuseport test runs

Quoted 4 lines
 .../bpf/prog_tests/select_reuseport.c         | 44 ++++++++++++++++---
 .../bpf/progs/test_select_reuseport_kern.c    |  6 +++
 tools/testing/selftests/bpf/test_sockmap.c    | 15 +++----
 3 files changed, 49 insertions(+), 16 deletions(-)

For the series:

maintainer
#25 lore raw
Quoted 4 lines · Martin Lau
Quoted 2 lines · Lorenz Bauer

I've fixed the commit messages, added Fixes tags and am submitting to bpf-next instead of the bpf tree.

Series applied (and also added John's ACKs he just sent for the v1 set), thanks!