1 // SPDX-License-Identifier: GPL-2.0 2 3 #define _GNU_SOURCE 4 #include <sched.h> 5 6 #include <test_progs.h> 7 #include "rhash_timer.skel.h" 8 9 #define MAX_ATTEMPTS 256 10 #define RCU_SYNC_INTERVAL 64 11 12 static int pin_to_first_cpu(cpu_set_t *old_mask) 13 { 14 cpu_set_t new_mask; 15 int cpu; 16 17 if (sched_getaffinity(0, sizeof(*old_mask), old_mask)) 18 return -errno; 19 20 for (cpu = 0; cpu < CPU_SETSIZE; cpu++) 21 if (CPU_ISSET(cpu, old_mask)) 22 break; 23 if (cpu == CPU_SETSIZE) 24 return -EINVAL; 25 26 CPU_ZERO(&new_mask); 27 CPU_SET(cpu, &new_mask); 28 if (sched_setaffinity(0, sizeof(new_mask), &new_mask)) 29 return -errno; 30 return 0; 31 } 32 33 static int update_timer_map(int map_fd, __u64 key) 34 { 35 __u64 value[3] = {}; 36 37 return bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST); 38 } 39 40 static int run_prog(int prog_fd, struct bpf_test_run_opts *opts) 41 { 42 int err; 43 44 err = bpf_prog_test_run_opts(prog_fd, opts); 45 if (err) 46 return err; 47 return opts->retval; 48 } 49 50 void test_rhash_timer(void) 51 { 52 LIBBPF_OPTS(bpf_test_run_opts, opts); 53 struct rhash_timer *skel = NULL; 54 cpu_set_t old_mask; 55 int map_fd = -1, arm_fd, cancel_fd; 56 bool affinity_set = false; 57 __u64 key = 1; 58 int attempt, err; 59 60 err = pin_to_first_cpu(&old_mask); 61 if (!ASSERT_OK(err, "pin_to_first_cpu")) 62 return; 63 affinity_set = true; 64 65 skel = rhash_timer__open_and_load(); 66 if (!ASSERT_OK_PTR(skel, "open_and_load")) 67 goto out; 68 69 map_fd = bpf_map__fd(skel->maps.timer_map); 70 if (!ASSERT_GE(map_fd, 0, "timer_map fd")) 71 goto out; 72 arm_fd = bpf_program__fd(skel->progs.arm_deleted_timer); 73 if (!ASSERT_GE(arm_fd, 0, "arm_deleted_timer fd")) 74 goto out; 75 cancel_fd = bpf_program__fd(skel->progs.cancel_recycled_timer); 76 if (!ASSERT_GE(cancel_fd, 0, "cancel_recycled_timer fd")) 77 goto out; 78 79 err = update_timer_map(map_fd, key); 80 if (!ASSERT_OK(err, "seed_timer_map")) 81 goto out; 82 83 for (attempt = 0; attempt < MAX_ATTEMPTS; attempt++) { 84 err = run_prog(arm_fd, &opts); 85 if (err) { 86 ASSERT_OK(err, "arm_deleted_timer"); 87 goto out; 88 } 89 if (skel->bss->armed != attempt + 1) { 90 ASSERT_EQ(skel->bss->armed, attempt + 1, "armed"); 91 goto out; 92 } 93 if (skel->bss->timer_init_err) { 94 ASSERT_OK(skel->bss->timer_init_err, "timer_init_err"); 95 goto out; 96 } 97 if (skel->bss->timer_set_callback_err) { 98 ASSERT_OK(skel->bss->timer_set_callback_err, 99 "timer_set_callback_err"); 100 goto out; 101 } 102 if (skel->bss->timer_start_err) { 103 ASSERT_OK(skel->bss->timer_start_err, "timer_start_err"); 104 goto out; 105 } 106 107 if ((attempt + 1) % RCU_SYNC_INTERVAL == 0) { 108 err = kern_sync_rcu(); 109 if (err) { 110 ASSERT_OK(err, "kern_sync_rcu"); 111 goto out; 112 } 113 } 114 115 err = update_timer_map(map_fd, ++key); 116 if (err) { 117 ASSERT_OK(err, "replace_timer_map"); 118 goto out; 119 } 120 121 err = run_prog(cancel_fd, &opts); 122 if (err) { 123 ASSERT_OK(err, "cancel_recycled_timer"); 124 goto out; 125 } 126 if (skel->bss->timer_cancel_err) { 127 ASSERT_OK(skel->bss->timer_cancel_err, "timer_cancel_err"); 128 goto out; 129 } 130 if (skel->bss->cancelled) 131 break; 132 } 133 134 ASSERT_GT(skel->bss->cancelled, 0, "preserved timer"); 135 out: 136 if (map_fd >= 0) 137 bpf_map_delete_elem(map_fd, &key); 138 rhash_timer__destroy(skel); 139 if (affinity_set) 140 sched_setaffinity(0, sizeof(old_mask), &old_mask); 141 } 142