forked from mirrors/linux
		
	bpf, sockmap: Test shutdown() correctly exits epoll and recv()=0
When session gracefully shutdowns epoll needs to wake up and any recv() readers should return 0 not the -EAGAIN they previously returned. Note we use epoll instead of select to test the epoll wake on shutdown event as well. Signed-off-by: John Fastabend <john.fastabend@gmail.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com> Link: https://lore.kernel.org/bpf/20230523025618.113937-12-john.fastabend@gmail.com
This commit is contained in:
		
							parent
							
								
									298970c8af
								
							
						
					
					
						commit
						1fa1fe8ff1
					
				
					 2 changed files with 94 additions and 0 deletions
				
			
		|  | @ -2,6 +2,7 @@ | |||
| // Copyright (c) 2020 Cloudflare
 | ||||
| #include <error.h> | ||||
| #include <netinet/tcp.h> | ||||
| #include <sys/epoll.h> | ||||
| 
 | ||||
| #include "test_progs.h" | ||||
| #include "test_skmsg_load_helpers.skel.h" | ||||
|  | @ -9,8 +10,11 @@ | |||
| #include "test_sockmap_invalid_update.skel.h" | ||||
| #include "test_sockmap_skb_verdict_attach.skel.h" | ||||
| #include "test_sockmap_progs_query.skel.h" | ||||
| #include "test_sockmap_pass_prog.skel.h" | ||||
| #include "bpf_iter_sockmap.skel.h" | ||||
| 
 | ||||
| #include "sockmap_helpers.h" | ||||
| 
 | ||||
| #define TCP_REPAIR		19	/* TCP sock is under repair right now */ | ||||
| 
 | ||||
| #define TCP_REPAIR_ON		1 | ||||
|  | @ -350,6 +354,62 @@ static void test_sockmap_progs_query(enum bpf_attach_type attach_type) | |||
| 	test_sockmap_progs_query__destroy(skel); | ||||
| } | ||||
| 
 | ||||
| #define MAX_EVENTS 10 | ||||
| static void test_sockmap_skb_verdict_shutdown(void) | ||||
| { | ||||
| 	struct epoll_event ev, events[MAX_EVENTS]; | ||||
| 	int n, err, map, verdict, s, c1, p1; | ||||
| 	struct test_sockmap_pass_prog *skel; | ||||
| 	int epollfd; | ||||
| 	int zero = 0; | ||||
| 	char b; | ||||
| 
 | ||||
| 	skel = test_sockmap_pass_prog__open_and_load(); | ||||
| 	if (!ASSERT_OK_PTR(skel, "open_and_load")) | ||||
| 		return; | ||||
| 
 | ||||
| 	verdict = bpf_program__fd(skel->progs.prog_skb_verdict); | ||||
| 	map = bpf_map__fd(skel->maps.sock_map_rx); | ||||
| 
 | ||||
| 	err = bpf_prog_attach(verdict, map, BPF_SK_SKB_STREAM_VERDICT, 0); | ||||
| 	if (!ASSERT_OK(err, "bpf_prog_attach")) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	s = socket_loopback(AF_INET, SOCK_STREAM); | ||||
| 	if (s < 0) | ||||
| 		goto out; | ||||
| 	err = create_pair(s, AF_INET, SOCK_STREAM, &c1, &p1); | ||||
| 	if (err < 0) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	err = bpf_map_update_elem(map, &zero, &c1, BPF_NOEXIST); | ||||
| 	if (err < 0) | ||||
| 		goto out_close; | ||||
| 
 | ||||
| 	shutdown(p1, SHUT_WR); | ||||
| 
 | ||||
| 	ev.events = EPOLLIN; | ||||
| 	ev.data.fd = c1; | ||||
| 
 | ||||
| 	epollfd = epoll_create1(0); | ||||
| 	if (!ASSERT_GT(epollfd, -1, "epoll_create(0)")) | ||||
| 		goto out_close; | ||||
| 	err = epoll_ctl(epollfd, EPOLL_CTL_ADD, c1, &ev); | ||||
| 	if (!ASSERT_OK(err, "epoll_ctl(EPOLL_CTL_ADD)")) | ||||
| 		goto out_close; | ||||
| 	err = epoll_wait(epollfd, events, MAX_EVENTS, -1); | ||||
| 	if (!ASSERT_EQ(err, 1, "epoll_wait(fd)")) | ||||
| 		goto out_close; | ||||
| 
 | ||||
| 	n = recv(c1, &b, 1, SOCK_NONBLOCK); | ||||
| 	ASSERT_EQ(n, 0, "recv_timeout(fin)"); | ||||
| out_close: | ||||
| 	close(c1); | ||||
| 	close(p1); | ||||
| out: | ||||
| 	test_sockmap_pass_prog__destroy(skel); | ||||
| } | ||||
| 
 | ||||
| void test_sockmap_basic(void) | ||||
| { | ||||
| 	if (test__start_subtest("sockmap create_update_free")) | ||||
|  | @ -384,4 +444,6 @@ void test_sockmap_basic(void) | |||
| 		test_sockmap_progs_query(BPF_SK_SKB_STREAM_VERDICT); | ||||
| 	if (test__start_subtest("sockmap skb_verdict progs query")) | ||||
| 		test_sockmap_progs_query(BPF_SK_SKB_VERDICT); | ||||
| 	if (test__start_subtest("sockmap skb_verdict shutdown")) | ||||
| 		test_sockmap_skb_verdict_shutdown(); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										32
									
								
								tools/testing/selftests/bpf/progs/test_sockmap_pass_prog.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								tools/testing/selftests/bpf/progs/test_sockmap_pass_prog.c
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| #include <linux/bpf.h> | ||||
| #include <bpf/bpf_helpers.h> | ||||
| #include <bpf/bpf_endian.h> | ||||
| 
 | ||||
| struct { | ||||
| 	__uint(type, BPF_MAP_TYPE_SOCKMAP); | ||||
| 	__uint(max_entries, 20); | ||||
| 	__type(key, int); | ||||
| 	__type(value, int); | ||||
| } sock_map_rx SEC(".maps"); | ||||
| 
 | ||||
| struct { | ||||
| 	__uint(type, BPF_MAP_TYPE_SOCKMAP); | ||||
| 	__uint(max_entries, 20); | ||||
| 	__type(key, int); | ||||
| 	__type(value, int); | ||||
| } sock_map_tx SEC(".maps"); | ||||
| 
 | ||||
| struct { | ||||
| 	__uint(type, BPF_MAP_TYPE_SOCKMAP); | ||||
| 	__uint(max_entries, 20); | ||||
| 	__type(key, int); | ||||
| 	__type(value, int); | ||||
| } sock_map_msg SEC(".maps"); | ||||
| 
 | ||||
| SEC("sk_skb") | ||||
| int prog_skb_verdict(struct __sk_buff *skb) | ||||
| { | ||||
| 	return SK_PASS; | ||||
| } | ||||
| 
 | ||||
| char _license[] SEC("license") = "GPL"; | ||||
		Loading…
	
		Reference in a new issue
	
	 John Fastabend
						John Fastabend