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], 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; 18 LIBBPF_OPTS(bpf_test_run_opts, topts, 19 .data_in = &pkt_v4, 20 .data_size_in = sizeof(pkt_v4), 21 .data_out = buf, 22 .data_size_out = sizeof(buf), 23 .repeat = 1, 24 ); 25 26 /* Fill test values to be used */ 27 for (i = 0; i < MAP_SIZE; i++) 28 vals[i] = rand(); 29 30 if (type == QUEUE) 31 strncpy(file, "./test_queue_map.o", sizeof(file)); 32 else if (type == STACK) 33 strncpy(file, "./test_stack_map.o", sizeof(file)); 34 else 35 return; 36 37 err = bpf_prog_test_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd); 38 if (CHECK_FAIL(err)) 39 return; 40 41 map_in_fd = bpf_find_map(__func__, obj, "map_in"); 42 if (map_in_fd < 0) 43 goto out; 44 45 map_out_fd = bpf_find_map(__func__, obj, "map_out"); 46 if (map_out_fd < 0) 47 goto out; 48 49 /* Push 32 elements to the input map */ 50 for (i = 0; i < MAP_SIZE; i++) { 51 err = bpf_map_update_elem(map_in_fd, NULL, &vals[i], 0); 52 if (CHECK_FAIL(err)) 53 goto out; 54 } 55 56 /* The eBPF program pushes iph.saddr in the output map, 57 * pops the input map and saves this value in iph.daddr 58 */ 59 for (i = 0; i < MAP_SIZE; i++) { 60 if (type == QUEUE) { 61 val = vals[i]; 62 pkt_v4.iph.saddr = vals[i] * 5; 63 } else if (type == STACK) { 64 val = vals[MAP_SIZE - 1 - i]; 65 pkt_v4.iph.saddr = vals[MAP_SIZE - 1 - i] * 5; 66 } 67 68 topts.data_size_out = sizeof(buf); 69 err = bpf_prog_test_run_opts(prog_fd, &topts); 70 if (err || topts.retval || 71 topts.data_size_out != sizeof(pkt_v4)) 72 break; 73 memcpy(&iph, buf + sizeof(struct ethhdr), sizeof(iph)); 74 if (iph.daddr != val) 75 break; 76 } 77 78 ASSERT_OK(err, "bpf_map_pop_elem"); 79 ASSERT_OK(topts.retval, "bpf_map_pop_elem test retval"); 80 ASSERT_EQ(topts.data_size_out, sizeof(pkt_v4), 81 "bpf_map_pop_elem data_size_out"); 82 ASSERT_EQ(iph.daddr, val, "bpf_map_pop_elem iph.daddr"); 83 84 /* Queue is empty, program should return TC_ACT_SHOT */ 85 topts.data_size_out = sizeof(buf); 86 err = bpf_prog_test_run_opts(prog_fd, &topts); 87 ASSERT_OK(err, "check-queue-stack-map-empty"); 88 ASSERT_EQ(topts.retval, 2 /* TC_ACT_SHOT */, 89 "check-queue-stack-map-empty test retval"); 90 ASSERT_EQ(topts.data_size_out, sizeof(pkt_v4), 91 "check-queue-stack-map-empty data_size_out"); 92 93 /* Check that the program pushed elements correctly */ 94 for (i = 0; i < MAP_SIZE; i++) { 95 err = bpf_map_lookup_and_delete_elem(map_out_fd, NULL, &val); 96 ASSERT_OK(err, "bpf_map_lookup_and_delete_elem"); 97 ASSERT_EQ(val, vals[i] * 5, "bpf_map_push_elem val"); 98 } 99 out: 100 pkt_v4.iph.saddr = 0; 101 bpf_object__close(obj); 102 } 103 104 void test_queue_stack_map(void) 105 { 106 test_queue_stack_map_by_type(QUEUE); 107 test_queue_stack_map_by_type(STACK); 108 } 109