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

samples/bpf: Fix sockex3 error: Missing BPF prog type

since commit 450b167fb9be("libbpf: clean up SEC() handling"),
sec_def_matches() does not recognize "socket/xxx" as "socket", therefore,
the BPF program type is not recognized.

Instead of sockex3_user.c parsing section names to get the BPF program fd.
We use the program array map to assign a static index to each BPF program
(get inspired by selftests/bpf progs/test_prog_array_init.c).
Therefore, use SEC("socket") as section name instead of SEC("socket/xxx"),
so that the BPF program is parsed to SOCKET_FILTER type. The "missing BPF
prog type" problem is solved.

How to reproduce this error:
$ cd samples/bpf
$ sudo ./sockex3
libbpf: prog 'bpf_func_PARSE_IP': missing BPF prog type, check ELF section name 'socket/3'
libbpf: prog 'bpf_func_PARSE_IP': failed to load: -22
libbpf: failed to load object './sockex3_kern.o'
ERROR: loading BPF object file failed

Signed-off-by: Rong Tao <rongtao@cestc.cn>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/tencent_EBA3C18864069E42175946973C2ACBAF5408@qq.com

authored by

Rong Tao and committed by
Andrii Nakryiko
e5659e4e e8f50c4f

+63 -55
+53 -42
samples/bpf/sockex3_kern.c
··· 17 17 #define IP_MF 0x2000 18 18 #define IP_OFFSET 0x1FFF 19 19 20 - #define PROG(F) SEC("socket/"__stringify(F)) int bpf_func_##F 21 - 22 - struct { 23 - __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 24 - __uint(key_size, sizeof(u32)); 25 - __uint(value_size, sizeof(u32)); 26 - __uint(max_entries, 8); 27 - } jmp_table SEC(".maps"); 28 - 29 20 #define PARSE_VLAN 1 30 21 #define PARSE_MPLS 2 31 22 #define PARSE_IP 3 32 23 #define PARSE_IPV6 4 33 - 34 - /* Protocol dispatch routine. It tail-calls next BPF program depending 35 - * on eth proto. Note, we could have used ... 36 - * 37 - * bpf_tail_call(skb, &jmp_table, proto); 38 - * 39 - * ... but it would need large prog_array and cannot be optimised given 40 - * the map key is not static. 41 - */ 42 - static inline void parse_eth_proto(struct __sk_buff *skb, u32 proto) 43 - { 44 - switch (proto) { 45 - case ETH_P_8021Q: 46 - case ETH_P_8021AD: 47 - bpf_tail_call(skb, &jmp_table, PARSE_VLAN); 48 - break; 49 - case ETH_P_MPLS_UC: 50 - case ETH_P_MPLS_MC: 51 - bpf_tail_call(skb, &jmp_table, PARSE_MPLS); 52 - break; 53 - case ETH_P_IP: 54 - bpf_tail_call(skb, &jmp_table, PARSE_IP); 55 - break; 56 - case ETH_P_IPV6: 57 - bpf_tail_call(skb, &jmp_table, PARSE_IPV6); 58 - break; 59 - } 60 - } 61 24 62 25 struct vlan_hdr { 63 26 __be16 h_vlan_TCI; ··· 36 73 }; 37 74 __u32 ip_proto; 38 75 }; 76 + 77 + static inline void parse_eth_proto(struct __sk_buff *skb, u32 proto); 39 78 40 79 static inline int ip_is_fragment(struct __sk_buff *ctx, __u64 nhoff) 41 80 { ··· 154 189 } 155 190 } 156 191 157 - PROG(PARSE_IP)(struct __sk_buff *skb) 192 + SEC("socket") 193 + int bpf_func_ip(struct __sk_buff *skb) 158 194 { 159 195 struct globals *g = this_cpu_globals(); 160 196 __u32 nhoff, verlen, ip_proto; ··· 183 217 return 0; 184 218 } 185 219 186 - PROG(PARSE_IPV6)(struct __sk_buff *skb) 220 + SEC("socket") 221 + int bpf_func_ipv6(struct __sk_buff *skb) 187 222 { 188 223 struct globals *g = this_cpu_globals(); 189 224 __u32 nhoff, ip_proto; ··· 207 240 return 0; 208 241 } 209 242 210 - PROG(PARSE_VLAN)(struct __sk_buff *skb) 243 + SEC("socket") 244 + int bpf_func_vlan(struct __sk_buff *skb) 211 245 { 212 246 __u32 nhoff, proto; 213 247 ··· 224 256 return 0; 225 257 } 226 258 227 - PROG(PARSE_MPLS)(struct __sk_buff *skb) 259 + SEC("socket") 260 + int bpf_func_mpls(struct __sk_buff *skb) 228 261 { 229 262 __u32 nhoff, label; 230 263 ··· 248 279 return 0; 249 280 } 250 281 251 - SEC("socket/0") 282 + struct { 283 + __uint(type, BPF_MAP_TYPE_PROG_ARRAY); 284 + __uint(key_size, sizeof(u32)); 285 + __uint(max_entries, 8); 286 + __array(values, u32 (void *)); 287 + } prog_array_init SEC(".maps") = { 288 + .values = { 289 + [PARSE_VLAN] = (void *)&bpf_func_vlan, 290 + [PARSE_IP] = (void *)&bpf_func_ip, 291 + [PARSE_IPV6] = (void *)&bpf_func_ipv6, 292 + [PARSE_MPLS] = (void *)&bpf_func_mpls, 293 + }, 294 + }; 295 + 296 + /* Protocol dispatch routine. It tail-calls next BPF program depending 297 + * on eth proto. Note, we could have used ... 298 + * 299 + * bpf_tail_call(skb, &prog_array_init, proto); 300 + * 301 + * ... but it would need large prog_array and cannot be optimised given 302 + * the map key is not static. 303 + */ 304 + static inline void parse_eth_proto(struct __sk_buff *skb, u32 proto) 305 + { 306 + switch (proto) { 307 + case ETH_P_8021Q: 308 + case ETH_P_8021AD: 309 + bpf_tail_call(skb, &prog_array_init, PARSE_VLAN); 310 + break; 311 + case ETH_P_MPLS_UC: 312 + case ETH_P_MPLS_MC: 313 + bpf_tail_call(skb, &prog_array_init, PARSE_MPLS); 314 + break; 315 + case ETH_P_IP: 316 + bpf_tail_call(skb, &prog_array_init, PARSE_IP); 317 + break; 318 + case ETH_P_IPV6: 319 + bpf_tail_call(skb, &prog_array_init, PARSE_IPV6); 320 + break; 321 + } 322 + } 323 + 324 + SEC("socket") 252 325 int main_prog(struct __sk_buff *skb) 253 326 { 254 327 __u32 nhoff = ETH_HLEN;
+10 -13
samples/bpf/sockex3_user.c
··· 24 24 25 25 int main(int argc, char **argv) 26 26 { 27 - int i, sock, key, fd, main_prog_fd, jmp_table_fd, hash_map_fd; 27 + int i, sock, fd, main_prog_fd, hash_map_fd; 28 28 struct bpf_program *prog; 29 29 struct bpf_object *obj; 30 - const char *section; 31 30 char filename[256]; 32 31 FILE *f; 33 32 ··· 44 45 goto cleanup; 45 46 } 46 47 47 - jmp_table_fd = bpf_object__find_map_fd_by_name(obj, "jmp_table"); 48 48 hash_map_fd = bpf_object__find_map_fd_by_name(obj, "hash_map"); 49 - if (jmp_table_fd < 0 || hash_map_fd < 0) { 49 + if (hash_map_fd < 0) { 50 50 fprintf(stderr, "ERROR: finding a map in obj file failed\n"); 51 51 goto cleanup; 52 52 } 53 53 54 + /* find BPF main program */ 55 + main_prog_fd = 0; 54 56 bpf_object__for_each_program(prog, obj) { 55 57 fd = bpf_program__fd(prog); 56 58 57 - section = bpf_program__section_name(prog); 58 - if (sscanf(section, "socket/%d", &key) != 1) { 59 - fprintf(stderr, "ERROR: finding prog failed\n"); 60 - goto cleanup; 61 - } 62 - 63 - if (key == 0) 59 + if (!strcmp(bpf_program__name(prog), "main_prog")) 64 60 main_prog_fd = fd; 65 - else 66 - bpf_map_update_elem(jmp_table_fd, &key, &fd, BPF_ANY); 61 + } 62 + 63 + if (main_prog_fd == 0) { 64 + fprintf(stderr, "ERROR: can't find main_prog\n"); 65 + goto cleanup; 67 66 } 68 67 69 68 sock = open_raw_sock("lo");