github.com/dylandreimerink/gobpfld@v0.6.1-0.20220205171531-e79c330ad608/cmd/examples/xdp_stats/bpf/basic03_map_counter.c (about) 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #include <linux/bpf.h> 3 4 /* 5 * bpf_map_lookup_elem 6 * 7 * Perform a lookup in *map* for an entry associated to *key*. 8 * 9 * Returns 10 * Map value associated to *key*, or **NULL** if no entry was 11 * found. 12 */ 13 static void *(*bpf_map_lookup_elem)(void *map, const void *key) = (void *) 1; 14 15 #define SEC(NAME) __attribute__((section(NAME), used)) 16 17 struct bpf_map_def { 18 unsigned int type; 19 unsigned int key_size; 20 unsigned int value_size; 21 unsigned int max_entries; 22 unsigned int map_flags; 23 }; 24 25 26 /* This is the data record stored in the map */ 27 struct datarec { 28 __u64 rx_packets; 29 /* Assignment#1: Add byte counters */ 30 }; 31 32 /* Lesson#1: See how a map is defined. 33 * - Here an array with XDP_ACTION_MAX (max_)entries are created. 34 * - The idea is to keep stats per (enum) xdp_action 35 */ 36 struct bpf_map_def SEC("maps") xdp_stats_map = { 37 .type = BPF_MAP_TYPE_ARRAY, 38 .key_size = sizeof(__u32), 39 .value_size = sizeof(struct datarec), 40 .max_entries = XDP_REDIRECT+1, 41 }; 42 43 /* LLVM maps __sync_fetch_and_add() as a built-in function to the BPF atomic add 44 * instruction (that is BPF_STX | BPF_XADD | BPF_W for word sizes) 45 */ 46 #ifndef lock_xadd 47 #define lock_xadd(ptr, val) ((void) __sync_fetch_and_add(ptr, val)) 48 #endif 49 50 SEC("xdp") 51 int xdp_stats1_func(struct xdp_md *ctx) 52 { 53 // void *data_end = (void *)(long)ctx->data_end; 54 // void *data = (void *)(long)ctx->data; 55 struct datarec *rec; 56 __u32 key = XDP_PASS; /* XDP_PASS = 2 */ 57 58 /* Lookup in kernel BPF-side return pointer to actual data record */ 59 rec = bpf_map_lookup_elem(&xdp_stats_map, &key); 60 /* BPF kernel-side verifier will reject program if the NULL pointer 61 * check isn't performed here. Even-though this is a static array where 62 * we know key lookup XDP_PASS always will succeed. 63 */ 64 if (!rec) 65 return XDP_ABORTED; 66 67 /* Multiple CPUs can access data record. Thus, the accounting needs to 68 * use an atomic operation. 69 */ 70 lock_xadd(&rec->rx_packets, 1); 71 /* Assignment#1: Add byte counters 72 * - Hint look at struct xdp_md *ctx (copied below) 73 * 74 * Assignment#3: Avoid the atomic operation 75 * - Hint there is a map type named BPF_MAP_TYPE_PERCPU_ARRAY 76 */ 77 78 return XDP_PASS; 79 } 80 81 char _license[] SEC("license") = "GPL"; 82 83 /* Copied from: $KERNEL/include/uapi/linux/bpf.h 84 * 85 * User return codes for XDP prog type. 86 * A valid XDP program must return one of these defined values. All other 87 * return codes are reserved for future use. Unknown return codes will 88 * result in packet drops and a warning via bpf_warn_invalid_xdp_action(). 89 * 90 enum xdp_action { 91 XDP_ABORTED = 0, 92 XDP_DROP, 93 XDP_PASS, 94 XDP_TX, 95 XDP_REDIRECT, 96 }; 97 98 * user accessible metadata for XDP packet hook 99 * new fields must be added to the end of this structure 100 * 101 struct xdp_md { 102 // (Note: type __u32 is NOT the real-type) 103 __u32 data; 104 __u32 data_end; 105 __u32 data_meta; 106 // Below access go through struct xdp_rxq_info 107 __u32 ingress_ifindex; // rxq->dev->ifindex 108 __u32 rx_queue_index; // rxq->queue_index 109 }; 110 */