Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* Copyright (c) 2020 Tessares SA <http://www.tessares.net> */
0003 
0004 #include <test_progs.h>
0005 #include "test_map_init.skel.h"
0006 
0007 #define TEST_VALUE 0x1234
0008 #define FILL_VALUE 0xdeadbeef
0009 
0010 static int nr_cpus;
0011 static int duration;
0012 
0013 typedef unsigned long long map_key_t;
0014 typedef unsigned long long map_value_t;
0015 typedef struct {
0016     map_value_t v; /* padding */
0017 } __bpf_percpu_val_align pcpu_map_value_t;
0018 
0019 
0020 static int map_populate(int map_fd, int num)
0021 {
0022     pcpu_map_value_t value[nr_cpus];
0023     int i, err;
0024     map_key_t key;
0025 
0026     for (i = 0; i < nr_cpus; i++)
0027         bpf_percpu(value, i) = FILL_VALUE;
0028 
0029     for (key = 1; key <= num; key++) {
0030         err = bpf_map_update_elem(map_fd, &key, value, BPF_NOEXIST);
0031         if (!ASSERT_OK(err, "bpf_map_update_elem"))
0032             return -1;
0033     }
0034 
0035     return 0;
0036 }
0037 
0038 static struct test_map_init *setup(enum bpf_map_type map_type, int map_sz,
0039                 int *map_fd, int populate)
0040 {
0041     struct test_map_init *skel;
0042     int err;
0043 
0044     skel = test_map_init__open();
0045     if (!ASSERT_OK_PTR(skel, "skel_open"))
0046         return NULL;
0047 
0048     err = bpf_map__set_type(skel->maps.hashmap1, map_type);
0049     if (!ASSERT_OK(err, "bpf_map__set_type"))
0050         goto error;
0051 
0052     err = bpf_map__set_max_entries(skel->maps.hashmap1, map_sz);
0053     if (!ASSERT_OK(err, "bpf_map__set_max_entries"))
0054         goto error;
0055 
0056     err = test_map_init__load(skel);
0057     if (!ASSERT_OK(err, "skel_load"))
0058         goto error;
0059 
0060     *map_fd = bpf_map__fd(skel->maps.hashmap1);
0061     if (CHECK(*map_fd < 0, "bpf_map__fd", "failed\n"))
0062         goto error;
0063 
0064     err = map_populate(*map_fd, populate);
0065     if (!ASSERT_OK(err, "map_populate"))
0066         goto error_map;
0067 
0068     return skel;
0069 
0070 error_map:
0071     close(*map_fd);
0072 error:
0073     test_map_init__destroy(skel);
0074     return NULL;
0075 }
0076 
0077 /* executes bpf program that updates map with key, value */
0078 static int prog_run_insert_elem(struct test_map_init *skel, map_key_t key,
0079                 map_value_t value)
0080 {
0081     struct test_map_init__bss *bss;
0082 
0083     bss = skel->bss;
0084 
0085     bss->inKey = key;
0086     bss->inValue = value;
0087     bss->inPid = getpid();
0088 
0089     if (!ASSERT_OK(test_map_init__attach(skel), "skel_attach"))
0090         return -1;
0091 
0092     /* Let tracepoint trigger */
0093     syscall(__NR_getpgid);
0094 
0095     test_map_init__detach(skel);
0096 
0097     return 0;
0098 }
0099 
0100 static int check_values_one_cpu(pcpu_map_value_t *value, map_value_t expected)
0101 {
0102     int i, nzCnt = 0;
0103     map_value_t val;
0104 
0105     for (i = 0; i < nr_cpus; i++) {
0106         val = bpf_percpu(value, i);
0107         if (val) {
0108             if (CHECK(val != expected, "map value",
0109                   "unexpected for cpu %d: 0x%llx\n", i, val))
0110                 return -1;
0111             nzCnt++;
0112         }
0113     }
0114 
0115     if (CHECK(nzCnt != 1, "map value", "set for %d CPUs instead of 1!\n",
0116           nzCnt))
0117         return -1;
0118 
0119     return 0;
0120 }
0121 
0122 /* Add key=1 elem with values set for all CPUs
0123  * Delete elem key=1
0124  * Run bpf prog that inserts new key=1 elem with value=0x1234
0125  *   (bpf prog can only set value for current CPU)
0126  * Lookup Key=1 and check value is as expected for all CPUs:
0127  *   value set by bpf prog for one CPU, 0 for all others
0128  */
0129 static void test_pcpu_map_init(void)
0130 {
0131     pcpu_map_value_t value[nr_cpus];
0132     struct test_map_init *skel;
0133     int map_fd, err;
0134     map_key_t key;
0135 
0136     /* max 1 elem in map so insertion is forced to reuse freed entry */
0137     skel = setup(BPF_MAP_TYPE_PERCPU_HASH, 1, &map_fd, 1);
0138     if (!ASSERT_OK_PTR(skel, "prog_setup"))
0139         return;
0140 
0141     /* delete element so the entry can be re-used*/
0142     key = 1;
0143     err = bpf_map_delete_elem(map_fd, &key);
0144     if (!ASSERT_OK(err, "bpf_map_delete_elem"))
0145         goto cleanup;
0146 
0147     /* run bpf prog that inserts new elem, re-using the slot just freed */
0148     err = prog_run_insert_elem(skel, key, TEST_VALUE);
0149     if (!ASSERT_OK(err, "prog_run_insert_elem"))
0150         goto cleanup;
0151 
0152     /* check that key=1 was re-created by bpf prog */
0153     err = bpf_map_lookup_elem(map_fd, &key, value);
0154     if (!ASSERT_OK(err, "bpf_map_lookup_elem"))
0155         goto cleanup;
0156 
0157     /* and has expected values */
0158     check_values_one_cpu(value, TEST_VALUE);
0159 
0160 cleanup:
0161     test_map_init__destroy(skel);
0162 }
0163 
0164 /* Add key=1 and key=2 elems with values set for all CPUs
0165  * Run bpf prog that inserts new key=3 elem
0166  *   (only for current cpu; other cpus should have initial value = 0)
0167  * Lookup Key=1 and check value is as expected for all CPUs
0168  */
0169 static void test_pcpu_lru_map_init(void)
0170 {
0171     pcpu_map_value_t value[nr_cpus];
0172     struct test_map_init *skel;
0173     int map_fd, err;
0174     map_key_t key;
0175 
0176     /* Set up LRU map with 2 elements, values filled for all CPUs.
0177      * With these 2 elements, the LRU map is full
0178      */
0179     skel = setup(BPF_MAP_TYPE_LRU_PERCPU_HASH, 2, &map_fd, 2);
0180     if (!ASSERT_OK_PTR(skel, "prog_setup"))
0181         return;
0182 
0183     /* run bpf prog that inserts new key=3 element, re-using LRU slot */
0184     key = 3;
0185     err = prog_run_insert_elem(skel, key, TEST_VALUE);
0186     if (!ASSERT_OK(err, "prog_run_insert_elem"))
0187         goto cleanup;
0188 
0189     /* check that key=3 replaced one of earlier elements */
0190     err = bpf_map_lookup_elem(map_fd, &key, value);
0191     if (!ASSERT_OK(err, "bpf_map_lookup_elem"))
0192         goto cleanup;
0193 
0194     /* and has expected values */
0195     check_values_one_cpu(value, TEST_VALUE);
0196 
0197 cleanup:
0198     test_map_init__destroy(skel);
0199 }
0200 
0201 void test_map_init(void)
0202 {
0203     nr_cpus = bpf_num_possible_cpus();
0204     if (nr_cpus <= 1) {
0205         printf("%s:SKIP: >1 cpu needed for this test\n", __func__);
0206         test__skip();
0207         return;
0208     }
0209 
0210     if (test__start_subtest("pcpu_map_init"))
0211         test_pcpu_map_init();
0212     if (test__start_subtest("pcpu_lru_map_init"))
0213         test_pcpu_lru_map_init();
0214 }