Commit e5659e4e authored by Rong Tao's avatar Rong Tao Committed by Andrii Nakryiko

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

since commit 450b167f("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: default avatarRong Tao <rongtao@cestc.cn>
Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/tencent_EBA3C18864069E42175946973C2ACBAF5408@qq.com
parent e8f50c4f
...@@ -17,48 +17,11 @@ ...@@ -17,48 +17,11 @@
#define IP_MF 0x2000 #define IP_MF 0x2000
#define IP_OFFSET 0x1FFF #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_VLAN 1
#define PARSE_MPLS 2 #define PARSE_MPLS 2
#define PARSE_IP 3 #define PARSE_IP 3
#define PARSE_IPV6 4 #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 { struct vlan_hdr {
__be16 h_vlan_TCI; __be16 h_vlan_TCI;
__be16 h_vlan_encapsulated_proto; __be16 h_vlan_encapsulated_proto;
...@@ -74,6 +37,8 @@ struct flow_key_record { ...@@ -74,6 +37,8 @@ struct flow_key_record {
__u32 ip_proto; __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) static inline int ip_is_fragment(struct __sk_buff *ctx, __u64 nhoff)
{ {
return load_half(ctx, nhoff + offsetof(struct iphdr, frag_off)) 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, ...@@ -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(); struct globals *g = this_cpu_globals();
__u32 nhoff, verlen, ip_proto; __u32 nhoff, verlen, ip_proto;
...@@ -217,7 +183,8 @@ PROG(PARSE_IP)(struct __sk_buff *skb) ...@@ -217,7 +183,8 @@ PROG(PARSE_IP)(struct __sk_buff *skb)
return 0; 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(); struct globals *g = this_cpu_globals();
__u32 nhoff, ip_proto; __u32 nhoff, ip_proto;
...@@ -240,7 +207,8 @@ PROG(PARSE_IPV6)(struct __sk_buff *skb) ...@@ -240,7 +207,8 @@ PROG(PARSE_IPV6)(struct __sk_buff *skb)
return 0; return 0;
} }
PROG(PARSE_VLAN)(struct __sk_buff *skb) SEC("socket")
int bpf_func_vlan(struct __sk_buff *skb)
{ {
__u32 nhoff, proto; __u32 nhoff, proto;
...@@ -256,7 +224,8 @@ PROG(PARSE_VLAN)(struct __sk_buff *skb) ...@@ -256,7 +224,8 @@ PROG(PARSE_VLAN)(struct __sk_buff *skb)
return 0; return 0;
} }
PROG(PARSE_MPLS)(struct __sk_buff *skb) SEC("socket")
int bpf_func_mpls(struct __sk_buff *skb)
{ {
__u32 nhoff, label; __u32 nhoff, label;
...@@ -279,7 +248,49 @@ PROG(PARSE_MPLS)(struct __sk_buff *skb) ...@@ -279,7 +248,49 @@ PROG(PARSE_MPLS)(struct __sk_buff *skb)
return 0; 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) int main_prog(struct __sk_buff *skb)
{ {
__u32 nhoff = ETH_HLEN; __u32 nhoff = ETH_HLEN;
......
...@@ -24,10 +24,9 @@ struct pair { ...@@ -24,10 +24,9 @@ struct pair {
int main(int argc, char **argv) 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_program *prog;
struct bpf_object *obj; struct bpf_object *obj;
const char *section;
char filename[256]; char filename[256];
FILE *f; FILE *f;
...@@ -45,26 +44,24 @@ int main(int argc, char **argv) ...@@ -45,26 +44,24 @@ int main(int argc, char **argv)
goto cleanup; 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"); 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"); fprintf(stderr, "ERROR: finding a map in obj file failed\n");
goto cleanup; goto cleanup;
} }
/* find BPF main program */
main_prog_fd = 0;
bpf_object__for_each_program(prog, obj) { bpf_object__for_each_program(prog, obj) {
fd = bpf_program__fd(prog); fd = bpf_program__fd(prog);
section = bpf_program__section_name(prog); if (!strcmp(bpf_program__name(prog), "main_prog"))
if (sscanf(section, "socket/%d", &key) != 1) {
fprintf(stderr, "ERROR: finding prog failed\n");
goto cleanup;
}
if (key == 0)
main_prog_fd = fd; 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"); sock = open_raw_sock("lo");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment