xref: /linux/tools/testing/selftests/bpf/prog_tests/queue_stack_map.c (revision a98f670e41a99f53acb1fb33cee9c6abbb2e6f23)
1  // SPDX-License-Identifier: GPL-2.0
2  #include <test_progs.h>
3  #include <network_helpers.h>
4  
5  enum {
6  	QUEUE,
7  	STACK,
8  };
9  
10  static void test_queue_stack_map_by_type(int type)
11  {
12  	const int MAP_SIZE = 32;
13  	__u32 vals[MAP_SIZE], duration, retval, size, val;
14  	int i, err, prog_fd, map_in_fd, map_out_fd;
15  	char file[32], buf[128];
16  	struct bpf_object *obj;
17  	struct iphdr *iph = (void *)buf + sizeof(struct ethhdr);
18  
19  	/* Fill test values to be used */
20  	for (i = 0; i < MAP_SIZE; i++)
21  		vals[i] = rand();
22  
23  	if (type == QUEUE)
24  		strncpy(file, "./test_queue_map.o", sizeof(file));
25  	else if (type == STACK)
26  		strncpy(file, "./test_stack_map.o", sizeof(file));
27  	else
28  		return;
29  
30  	err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
31  	if (CHECK_FAIL(err))
32  		return;
33  
34  	map_in_fd = bpf_find_map(__func__, obj, "map_in");
35  	if (map_in_fd < 0)
36  		goto out;
37  
38  	map_out_fd = bpf_find_map(__func__, obj, "map_out");
39  	if (map_out_fd < 0)
40  		goto out;
41  
42  	/* Push 32 elements to the input map */
43  	for (i = 0; i < MAP_SIZE; i++) {
44  		err = bpf_map_update_elem(map_in_fd, NULL, &vals[i], 0);
45  		if (CHECK_FAIL(err))
46  			goto out;
47  	}
48  
49  	/* The eBPF program pushes iph.saddr in the output map,
50  	 * pops the input map and saves this value in iph.daddr
51  	 */
52  	for (i = 0; i < MAP_SIZE; i++) {
53  		if (type == QUEUE) {
54  			val = vals[i];
55  			pkt_v4.iph.saddr = vals[i] * 5;
56  		} else if (type == STACK) {
57  			val = vals[MAP_SIZE - 1 - i];
58  			pkt_v4.iph.saddr = vals[MAP_SIZE - 1 - i] * 5;
59  		}
60  
61  		err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4),
62  					buf, &size, &retval, &duration);
63  		if (err || retval || size != sizeof(pkt_v4) ||
64  		    iph->daddr != val)
65  			break;
66  	}
67  
68  	CHECK(err || retval || size != sizeof(pkt_v4) || iph->daddr != val,
69  	      "bpf_map_pop_elem",
70  	      "err %d errno %d retval %d size %d iph->daddr %u\n",
71  	      err, errno, retval, size, iph->daddr);
72  
73  	/* Queue is empty, program should return TC_ACT_SHOT */
74  	err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4),
75  				buf, &size, &retval, &duration);
76  	CHECK(err || retval != 2 /* TC_ACT_SHOT */|| size != sizeof(pkt_v4),
77  	      "check-queue-stack-map-empty",
78  	      "err %d errno %d retval %d size %d\n",
79  	      err, errno, retval, size);
80  
81  	/* Check that the program pushed elements correctly */
82  	for (i = 0; i < MAP_SIZE; i++) {
83  		err = bpf_map_lookup_and_delete_elem(map_out_fd, NULL, &val);
84  		if (err || val != vals[i] * 5)
85  			break;
86  	}
87  
88  	CHECK(i != MAP_SIZE && (err || val != vals[i] * 5),
89  	      "bpf_map_push_elem", "err %d value %u\n", err, val);
90  
91  out:
92  	pkt_v4.iph.saddr = 0;
93  	bpf_object__close(obj);
94  }
95  
96  void test_queue_stack_map(void)
97  {
98  	test_queue_stack_map_by_type(QUEUE);
99  	test_queue_stack_map_by_type(STACK);
100  }
101