test_btf_map_in_map.c (3690B)
1/* SPDX-License-Identifier: GPL-2.0 */ 2/* Copyright (c) 2020 Facebook */ 3#include <linux/bpf.h> 4#include <bpf/bpf_helpers.h> 5 6struct inner_map { 7 __uint(type, BPF_MAP_TYPE_ARRAY); 8 __uint(max_entries, 1); 9 __type(key, int); 10 __type(value, int); 11} inner_map1 SEC(".maps"), 12 inner_map2 SEC(".maps"); 13 14struct inner_map_sz2 { 15 __uint(type, BPF_MAP_TYPE_ARRAY); 16 __uint(max_entries, 2); 17 __type(key, int); 18 __type(value, int); 19} inner_map_sz2 SEC(".maps"); 20 21struct outer_arr { 22 __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); 23 __uint(max_entries, 3); 24 __type(key, int); 25 __type(value, int); 26 /* it's possible to use anonymous struct as inner map definition here */ 27 __array(values, struct { 28 __uint(type, BPF_MAP_TYPE_ARRAY); 29 /* changing max_entries to 2 will fail during load 30 * due to incompatibility with inner_map definition */ 31 __uint(max_entries, 1); 32 __type(key, int); 33 __type(value, int); 34 }); 35} outer_arr SEC(".maps") = { 36 /* (void *) cast is necessary because we didn't use `struct inner_map` 37 * in __inner(values, ...) 38 * Actually, a conscious effort is required to screw up initialization 39 * of inner map slots, which is a great thing! 40 */ 41 .values = { (void *)&inner_map1, 0, (void *)&inner_map2 }, 42}; 43 44struct inner_map_sz3 { 45 __uint(type, BPF_MAP_TYPE_ARRAY); 46 __uint(map_flags, BPF_F_INNER_MAP); 47 __uint(max_entries, 3); 48 __type(key, int); 49 __type(value, int); 50} inner_map3 SEC(".maps"), 51 inner_map4 SEC(".maps"); 52 53struct inner_map_sz4 { 54 __uint(type, BPF_MAP_TYPE_ARRAY); 55 __uint(map_flags, BPF_F_INNER_MAP); 56 __uint(max_entries, 5); 57 __type(key, int); 58 __type(value, int); 59} inner_map5 SEC(".maps"); 60 61struct outer_arr_dyn { 62 __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); 63 __uint(max_entries, 3); 64 __type(key, int); 65 __type(value, int); 66 __array(values, struct { 67 __uint(type, BPF_MAP_TYPE_ARRAY); 68 __uint(map_flags, BPF_F_INNER_MAP); 69 __uint(max_entries, 1); 70 __type(key, int); 71 __type(value, int); 72 }); 73} outer_arr_dyn SEC(".maps") = { 74 .values = { 75 [0] = (void *)&inner_map3, 76 [1] = (void *)&inner_map4, 77 [2] = (void *)&inner_map5, 78 }, 79}; 80 81struct outer_hash { 82 __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); 83 __uint(max_entries, 5); 84 __type(key, int); 85 /* Here everything works flawlessly due to reuse of struct inner_map 86 * and compiler will complain at the attempt to use non-inner_map 87 * references below. This is great experience. 88 */ 89 __array(values, struct inner_map); 90} outer_hash SEC(".maps") = { 91 .values = { 92 [0] = &inner_map2, 93 [4] = &inner_map1, 94 }, 95}; 96 97struct sockarr_sz1 { 98 __uint(type, BPF_MAP_TYPE_REUSEPORT_SOCKARRAY); 99 __uint(max_entries, 1); 100 __type(key, int); 101 __type(value, int); 102} sockarr_sz1 SEC(".maps"); 103 104struct sockarr_sz2 { 105 __uint(type, BPF_MAP_TYPE_REUSEPORT_SOCKARRAY); 106 __uint(max_entries, 2); 107 __type(key, int); 108 __type(value, int); 109} sockarr_sz2 SEC(".maps"); 110 111struct outer_sockarr_sz1 { 112 __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); 113 __uint(max_entries, 1); 114 __type(key, int); 115 __type(value, int); 116 __array(values, struct sockarr_sz1); 117} outer_sockarr SEC(".maps") = { 118 .values = { (void *)&sockarr_sz1 }, 119}; 120 121int input = 0; 122 123SEC("raw_tp/sys_enter") 124int handle__sys_enter(void *ctx) 125{ 126 struct inner_map *inner_map; 127 int key = 0, val; 128 129 inner_map = bpf_map_lookup_elem(&outer_arr, &key); 130 if (!inner_map) 131 return 1; 132 val = input; 133 bpf_map_update_elem(inner_map, &key, &val, 0); 134 135 inner_map = bpf_map_lookup_elem(&outer_hash, &key); 136 if (!inner_map) 137 return 1; 138 val = input + 1; 139 bpf_map_update_elem(inner_map, &key, &val, 0); 140 141 inner_map = bpf_map_lookup_elem(&outer_arr_dyn, &key); 142 if (!inner_map) 143 return 1; 144 val = input + 2; 145 bpf_map_update_elem(inner_map, &key, &val, 0); 146 147 return 0; 148} 149 150char _license[] SEC("license") = "GPL";