OSDN Git Service

samples/bpf: Fix sockex3 error: Missing BPF prog type
authorRong Tao <rongtao@cestc.cn>
Sat, 5 Nov 2022 06:48:00 +0000 (14:48 +0800)
committerAndrii Nakryiko <andrii@kernel.org>
Tue, 8 Nov 2022 01:13:35 +0000 (17:13 -0800)
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
samples/bpf/sockex3_kern.c
samples/bpf/sockex3_user.c

index b363503..822c132 100644 (file)
 #define IP_MF          0x2000
 #define IP_OFFSET      0x1FFF
 
-#define PROG(F) SEC("socket/"__stringify(F)) int bpf_func_##F
-
-struct {
-       __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
-       __uint(key_size, sizeof(u32));
-       __uint(value_size, sizeof(u32));
-       __uint(max_entries, 8);
-} jmp_table SEC(".maps");
-
 #define PARSE_VLAN 1
 #define PARSE_MPLS 2
 #define PARSE_IP 3
 #define PARSE_IPV6 4
 
-/* Protocol dispatch routine. It tail-calls next BPF program depending
- * on eth proto. Note, we could have used ...
- *
- *   bpf_tail_call(skb, &jmp_table, proto);
- *
- * ... but it would need large prog_array and cannot be optimised given
- * the map key is not static.
- */
-static inline void parse_eth_proto(struct __sk_buff *skb, u32 proto)
-{
-       switch (proto) {
-       case ETH_P_8021Q:
-       case ETH_P_8021AD:
-               bpf_tail_call(skb, &jmp_table, PARSE_VLAN);
-               break;
-       case ETH_P_MPLS_UC:
-       case ETH_P_MPLS_MC:
-               bpf_tail_call(skb, &jmp_table, PARSE_MPLS);
-               break;
-       case ETH_P_IP:
-               bpf_tail_call(skb, &jmp_table, PARSE_IP);
-               break;
-       case ETH_P_IPV6:
-               bpf_tail_call(skb, &jmp_table, PARSE_IPV6);
-               break;
-       }
-}
-
 struct vlan_hdr {
        __be16 h_vlan_TCI;
        __be16 h_vlan_encapsulated_proto;
@@ -74,6 +37,8 @@ struct flow_key_record {
        __u32 ip_proto;
 };
 
+static inline void parse_eth_proto(struct __sk_buff *skb, u32 proto);
+
 static inline int ip_is_fragment(struct __sk_buff *ctx, __u64 nhoff)
 {
        return load_half(ctx, nhoff + offsetof(struct iphdr, frag_off))
@@ -189,7 +154,8 @@ static __always_inline void parse_ip_proto(struct __sk_buff *skb,
        }
 }
 
-PROG(PARSE_IP)(struct __sk_buff *skb)
+SEC("socket")
+int bpf_func_ip(struct __sk_buff *skb)
 {
        struct globals *g = this_cpu_globals();
        __u32 nhoff, verlen, ip_proto;
@@ -217,7 +183,8 @@ PROG(PARSE_IP)(struct __sk_buff *skb)
        return 0;
 }
 
-PROG(PARSE_IPV6)(struct __sk_buff *skb)
+SEC("socket")
+int bpf_func_ipv6(struct __sk_buff *skb)
 {
        struct globals *g = this_cpu_globals();
        __u32 nhoff, ip_proto;
@@ -240,7 +207,8 @@ PROG(PARSE_IPV6)(struct __sk_buff *skb)
        return 0;
 }
 
-PROG(PARSE_VLAN)(struct __sk_buff *skb)
+SEC("socket")
+int bpf_func_vlan(struct __sk_buff *skb)
 {
        __u32 nhoff, proto;
 
@@ -256,7 +224,8 @@ PROG(PARSE_VLAN)(struct __sk_buff *skb)
        return 0;
 }
 
-PROG(PARSE_MPLS)(struct __sk_buff *skb)
+SEC("socket")
+int bpf_func_mpls(struct __sk_buff *skb)
 {
        __u32 nhoff, label;
 
@@ -279,7 +248,49 @@ PROG(PARSE_MPLS)(struct __sk_buff *skb)
        return 0;
 }
 
-SEC("socket/0")
+struct {
+       __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
+       __uint(key_size, sizeof(u32));
+       __uint(max_entries, 8);
+       __array(values, u32 (void *));
+} prog_array_init SEC(".maps") = {
+       .values = {
+               [PARSE_VLAN] = (void *)&bpf_func_vlan,
+               [PARSE_IP]   = (void *)&bpf_func_ip,
+               [PARSE_IPV6] = (void *)&bpf_func_ipv6,
+               [PARSE_MPLS] = (void *)&bpf_func_mpls,
+       },
+};
+
+/* Protocol dispatch routine. It tail-calls next BPF program depending
+ * on eth proto. Note, we could have used ...
+ *
+ *   bpf_tail_call(skb, &prog_array_init, proto);
+ *
+ * ... but it would need large prog_array and cannot be optimised given
+ * the map key is not static.
+ */
+static inline void parse_eth_proto(struct __sk_buff *skb, u32 proto)
+{
+       switch (proto) {
+       case ETH_P_8021Q:
+       case ETH_P_8021AD:
+               bpf_tail_call(skb, &prog_array_init, PARSE_VLAN);
+               break;
+       case ETH_P_MPLS_UC:
+       case ETH_P_MPLS_MC:
+               bpf_tail_call(skb, &prog_array_init, PARSE_MPLS);
+               break;
+       case ETH_P_IP:
+               bpf_tail_call(skb, &prog_array_init, PARSE_IP);
+               break;
+       case ETH_P_IPV6:
+               bpf_tail_call(skb, &prog_array_init, PARSE_IPV6);
+               break;
+       }
+}
+
+SEC("socket")
 int main_prog(struct __sk_buff *skb)
 {
        __u32 nhoff = ETH_HLEN;
index cd6fa79..56044ac 100644 (file)
@@ -24,10 +24,9 @@ struct pair {
 
 int main(int argc, char **argv)
 {
-       int i, sock, key, fd, main_prog_fd, jmp_table_fd, hash_map_fd;
+       int i, sock, fd, main_prog_fd, hash_map_fd;
        struct bpf_program *prog;
        struct bpf_object *obj;
-       const char *section;
        char filename[256];
        FILE *f;
 
@@ -45,26 +44,24 @@ int main(int argc, char **argv)
                goto cleanup;
        }
 
-       jmp_table_fd = bpf_object__find_map_fd_by_name(obj, "jmp_table");
        hash_map_fd = bpf_object__find_map_fd_by_name(obj, "hash_map");
-       if (jmp_table_fd < 0 || hash_map_fd < 0) {
+       if (hash_map_fd < 0) {
                fprintf(stderr, "ERROR: finding a map in obj file failed\n");
                goto cleanup;
        }
 
+       /* find BPF main program */
+       main_prog_fd = 0;
        bpf_object__for_each_program(prog, obj) {
                fd = bpf_program__fd(prog);
 
-               section = bpf_program__section_name(prog);
-               if (sscanf(section, "socket/%d", &key) != 1) {
-                       fprintf(stderr, "ERROR: finding prog failed\n");
-                       goto cleanup;
-               }
-
-               if (key == 0)
+               if (!strcmp(bpf_program__name(prog), "main_prog"))
                        main_prog_fd = fd;
-               else
-                       bpf_map_update_elem(jmp_table_fd, &key, &fd, BPF_ANY);
+       }
+
+       if (main_prog_fd == 0) {
+               fprintf(stderr, "ERROR: can't find main_prog\n");
+               goto cleanup;
        }
 
        sock = open_raw_sock("lo");