Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'add support for batched ops in LPM trie'

Pedro Tammela says:

====================

The patch itself is straightforward thanks to the infrastructure that is
already in-place.

The tests follows the other '*_map_batch_ops' tests with minor tweaks.

v1 -> v2:
Fixes for checkpatch warnings
====================

Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+161
+3
kernel/bpf/lpm_trie.c
··· 726 726 .map_lookup_elem = trie_lookup_elem, 727 727 .map_update_elem = trie_update_elem, 728 728 .map_delete_elem = trie_delete_elem, 729 + .map_lookup_batch = generic_map_lookup_batch, 730 + .map_update_batch = generic_map_update_batch, 731 + .map_delete_batch = generic_map_delete_batch, 729 732 .map_check_btf = trie_check_btf, 730 733 .map_btf_name = "lpm_trie", 731 734 .map_btf_id = &trie_map_btf_id,
+158
tools/testing/selftests/bpf/map_tests/lpm_trie_map_batch_ops.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <arpa/inet.h> 4 + #include <linux/bpf.h> 5 + #include <netinet/in.h> 6 + #include <stdio.h> 7 + #include <errno.h> 8 + #include <string.h> 9 + #include <stdlib.h> 10 + 11 + #include <bpf/bpf.h> 12 + #include <bpf/libbpf.h> 13 + 14 + #include <test_maps.h> 15 + 16 + struct test_lpm_key { 17 + __u32 prefix; 18 + struct in_addr ipv4; 19 + }; 20 + 21 + static void map_batch_update(int map_fd, __u32 max_entries, 22 + struct test_lpm_key *keys, int *values) 23 + { 24 + __u32 i; 25 + int err; 26 + char buff[16] = { 0 }; 27 + DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts, 28 + .elem_flags = 0, 29 + .flags = 0, 30 + ); 31 + 32 + for (i = 0; i < max_entries; i++) { 33 + keys[i].prefix = 32; 34 + snprintf(buff, 16, "192.168.1.%d", i + 1); 35 + inet_pton(AF_INET, buff, &keys[i].ipv4); 36 + values[i] = i + 1; 37 + } 38 + 39 + err = bpf_map_update_batch(map_fd, keys, values, &max_entries, &opts); 40 + CHECK(err, "bpf_map_update_batch()", "error:%s\n", strerror(errno)); 41 + } 42 + 43 + static void map_batch_verify(int *visited, __u32 max_entries, 44 + struct test_lpm_key *keys, int *values) 45 + { 46 + char buff[16] = { 0 }; 47 + int lower_byte = 0; 48 + __u32 i; 49 + 50 + memset(visited, 0, max_entries * sizeof(*visited)); 51 + for (i = 0; i < max_entries; i++) { 52 + inet_ntop(AF_INET, &keys[i].ipv4, buff, 32); 53 + CHECK(sscanf(buff, "192.168.1.%d", &lower_byte) == EOF, 54 + "sscanf()", "error: i %d\n", i); 55 + CHECK(lower_byte != values[i], "key/value checking", 56 + "error: i %d key %s value %d\n", i, buff, values[i]); 57 + visited[i] = 1; 58 + } 59 + for (i = 0; i < max_entries; i++) { 60 + CHECK(visited[i] != 1, "visited checking", 61 + "error: keys array at index %d missing\n", i); 62 + } 63 + } 64 + 65 + void test_lpm_trie_map_batch_ops(void) 66 + { 67 + struct bpf_create_map_attr xattr = { 68 + .name = "lpm_trie_map", 69 + .map_type = BPF_MAP_TYPE_LPM_TRIE, 70 + .key_size = sizeof(struct test_lpm_key), 71 + .value_size = sizeof(int), 72 + .map_flags = BPF_F_NO_PREALLOC, 73 + }; 74 + struct test_lpm_key *keys, key; 75 + int map_fd, *values, *visited; 76 + __u32 step, count, total, total_success; 77 + const __u32 max_entries = 10; 78 + __u64 batch = 0; 79 + int err; 80 + DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts, 81 + .elem_flags = 0, 82 + .flags = 0, 83 + ); 84 + 85 + xattr.max_entries = max_entries; 86 + map_fd = bpf_create_map_xattr(&xattr); 87 + CHECK(map_fd == -1, "bpf_create_map_xattr()", "error:%s\n", 88 + strerror(errno)); 89 + 90 + keys = malloc(max_entries * sizeof(struct test_lpm_key)); 91 + values = malloc(max_entries * sizeof(int)); 92 + visited = malloc(max_entries * sizeof(int)); 93 + CHECK(!keys || !values || !visited, "malloc()", "error:%s\n", 94 + strerror(errno)); 95 + 96 + total_success = 0; 97 + for (step = 1; step < max_entries; step++) { 98 + map_batch_update(map_fd, max_entries, keys, values); 99 + map_batch_verify(visited, max_entries, keys, values); 100 + memset(keys, 0, max_entries * sizeof(*keys)); 101 + memset(values, 0, max_entries * sizeof(*values)); 102 + batch = 0; 103 + total = 0; 104 + /* iteratively lookup/delete elements with 'step' 105 + * elements each. 106 + */ 107 + count = step; 108 + while (true) { 109 + err = bpf_map_lookup_batch(map_fd, 110 + total ? &batch : NULL, &batch, 111 + keys + total, values + total, &count, &opts); 112 + 113 + CHECK((err && errno != ENOENT), "lookup with steps", 114 + "error: %s\n", strerror(errno)); 115 + 116 + total += count; 117 + if (err) 118 + break; 119 + } 120 + 121 + CHECK(total != max_entries, "lookup with steps", 122 + "total = %u, max_entries = %u\n", total, max_entries); 123 + 124 + map_batch_verify(visited, max_entries, keys, values); 125 + 126 + total = 0; 127 + count = step; 128 + while (total < max_entries) { 129 + if (max_entries - total < step) 130 + count = max_entries - total; 131 + err = bpf_map_delete_batch(map_fd, keys + total, &count, 132 + &opts); 133 + CHECK((err && errno != ENOENT), "delete batch", 134 + "error: %s\n", strerror(errno)); 135 + total += count; 136 + if (err) 137 + break; 138 + } 139 + CHECK(total != max_entries, "delete with steps", 140 + "total = %u, max_entries = %u\n", total, max_entries); 141 + 142 + /* check map is empty, errono == ENOENT */ 143 + err = bpf_map_get_next_key(map_fd, NULL, &key); 144 + CHECK(!err || errno != ENOENT, "bpf_map_get_next_key()", 145 + "error: %s\n", strerror(errno)); 146 + 147 + total_success++; 148 + } 149 + 150 + CHECK(total_success == 0, "check total_success", 151 + "unexpected failure\n"); 152 + 153 + printf("%s:PASS\n", __func__); 154 + 155 + free(keys); 156 + free(values); 157 + free(visited); 158 + }