sdf@xxxxxxxxxx writes: >> +``BPF_MAP_TYPE_HASH`` and ``BPF_MAP_TYPE_PERCPU_HASH`` provide general >> +purpose hash map storage. Both the key and the value can be structs, >> +allowing for composite keys and values. The maximum number of entries is >> +defined in max_entries and is limited to 2^32. The kernel is responsible > > Do we really need to mention 2^32 limit here? It really depends on > the key/value sizes, right? > > Instead, might be worth talking about how/when this memory is allocated and > mention BPF_F_NO_PREALLOC? Good suggestion. I'll incorporate this into v2. >> +.. c:function:: >> + long bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u60 >> flags) > > s/u60/u64/ Good catch, thanks. >> +Kernel >> +------ >> + >> +.. code-block:: c >> + >> + #include <linux/bpf.h> >> + #include <bpf/bpf_helpers.h> >> + >> + struct key { >> + __u32 srcip; >> + }; >> + >> + struct value { >> + __u64 packets; >> + __u64 bytes; >> + }; >> + >> + struct { >> + __uint(type, BPF_MAP_TYPE_LRU_HASH); >> + __uint(max_entries, 32); >> + __type(key, struct key); >> + __type(value, struct value); >> + } packet_stats SEC(".maps"); >> + >> + static inline void count_by_srcip(__u32 srcip, int bytes) >> + { >> + struct key key = { >> + .srcip = srcip >> + }; >> + struct value *value = bpf_map_lookup_elem(&packet_stats, &key); >> + if (value) { >> + __sync_fetch_and_add(&value->packets, 1); >> + __sync_fetch_and_add(&value->bytes, bytes); >> + } else { >> + struct value newval = { 1, bytes }; >> + bpf_map_update_elem(&packet_stats, &key, &newval, BPF_NOEXIST); >> + } >> + } >> + >> +Userspace >> +--------- >> + >> +.. code-block:: c >> + >> + #include <bpf/libbpf.h> >> + #include <bpf/bpf.h> >> + >> + static void print_values(int map_fd) >> + { >> + struct key *cur_key = NULL; >> + struct key next_key; >> + int next; >> + do { >> + next = bpf_map_get_next_key(stats_fd, cur_key, &next_key); >> + if (next == -ENOENT) >> + break; >> + if (next < 0) { >> + fprintf(stderr, "bpf_map_get_next_key %d returned %s\n", >> stats_fd, strerror(-next)); >> + break; >> + } >> + >> + struct in_addr src_addr = { >> + .s_addr = next_key.srcip >> + }; >> + char *src_ip = inet_ntoa(src_addr); >> + >> + struct value value; >> + int ret = bpf_map_lookup_elem(stats_fd, &next_key, &value); >> + if (ret < 0) { >> + fprintf(stderr, "Failed to lookup elem with key %s: %s\n", >> src_ip, strerror(-ret)); >> + break; >> + } >> + printf("%s: %lld packets, %lld bytes\n", src_ip, value.packets, >> value.bytes); >> + cur_key = &next_key; >> + } while (next == 0); >> + } > > Instead of adding c code, maybe add pointers to specific file within > tools/testing/selftests/bpf/progs ? That's what we've done for > prog_cgroup_sockopt; the actual tests are a bit more maintained than > the doc :-) I tried to cut the examples to the minimum that was still complete enough to show use in context. Happy to try cutting the examples down to a sequence of shorter snippets and and links to samples/bpf and tools/testing/selftests/bpf/progs. I'll need to reference samples/bpf because there are no bpf_map_get_next_key examples in tools/testing/selftests/bpf/progs. Donald.