[bpf-next] samples/bpf: Fix sockex3 error: missing BPF prog type

Message ID tencent_EBA3C18864069E42175946973C2ACBAF5408@qq.com
State New
Headers
Series [bpf-next] samples/bpf: Fix sockex3 error: missing BPF prog type |

Commit Message

Rong Tao Nov. 5, 2022, 6:48 a.m. UTC
  From: Rong Tao <rongtao@cestc.cn>

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>
---
 samples/bpf/sockex3_kern.c | 95 ++++++++++++++++++++++----------------
 samples/bpf/sockex3_user.c | 23 ++++-----
 2 files changed, 64 insertions(+), 54 deletions(-)
  

Comments

Andrii Nakryiko Nov. 8, 2022, 1:14 a.m. UTC | #1
On Fri, Nov 4, 2022 at 11:48 PM Rong Tao <rtoax@foxmail.com> wrote:
>
> From: Rong Tao <rongtao@cestc.cn>
>
> 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>
> ---
>  samples/bpf/sockex3_kern.c | 95 ++++++++++++++++++++++----------------
>  samples/bpf/sockex3_user.c | 23 ++++-----
>  2 files changed, 64 insertions(+), 54 deletions(-)
>
> diff --git a/samples/bpf/sockex3_kern.c b/samples/bpf/sockex3_kern.c
> index b363503357e5..26d916834865 100644
> --- a/samples/bpf/sockex3_kern.c
> +++ b/samples/bpf/sockex3_kern.c
> @@ -17,47 +17,12 @@
>  #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;
> -       }
> -}
> +#define PROG_SOCKET_FILTER     SEC("socket")

I dropped this and made SEC("socket") annotations explicit everywhere.
Applied to bpf-next, thank.

>
>  struct vlan_hdr {
>         __be16 h_vlan_TCI;
> @@ -74,6 +39,8 @@ struct flow_key_record {
>         __u32 ip_proto;
>  };
>

[...]
  
patchwork-bot+netdevbpf@kernel.org Nov. 8, 2022, 1:20 a.m. UTC | #2
Hello:

This patch was applied to bpf/bpf-next.git (master)
by Andrii Nakryiko <andrii@kernel.org>:

On Sat,  5 Nov 2022 14:48:00 +0800 you wrote:
> From: Rong Tao <rongtao@cestc.cn>
> 
> 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.
> 
> [...]

Here is the summary with links:
  - [bpf-next] samples/bpf: Fix sockex3 error: missing BPF prog type
    https://git.kernel.org/bpf/bpf-next/c/e5659e4e19e4

You are awesome, thank you!
  

Patch

diff --git a/samples/bpf/sockex3_kern.c b/samples/bpf/sockex3_kern.c
index b363503357e5..26d916834865 100644
--- a/samples/bpf/sockex3_kern.c
+++ b/samples/bpf/sockex3_kern.c
@@ -17,47 +17,12 @@ 
 #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;
-	}
-}
+#define PROG_SOCKET_FILTER	SEC("socket")
 
 struct vlan_hdr {
 	__be16 h_vlan_TCI;
@@ -74,6 +39,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 +156,8 @@  static __always_inline void parse_ip_proto(struct __sk_buff *skb,
 	}
 }
 
-PROG(PARSE_IP)(struct __sk_buff *skb)
+PROG_SOCKET_FILTER
+int bpf_func_ip(struct __sk_buff *skb)
 {
 	struct globals *g = this_cpu_globals();
 	__u32 nhoff, verlen, ip_proto;
@@ -217,7 +185,8 @@  PROG(PARSE_IP)(struct __sk_buff *skb)
 	return 0;
 }
 
-PROG(PARSE_IPV6)(struct __sk_buff *skb)
+PROG_SOCKET_FILTER
+int bpf_func_ipv6(struct __sk_buff *skb)
 {
 	struct globals *g = this_cpu_globals();
 	__u32 nhoff, ip_proto;
@@ -240,7 +209,8 @@  PROG(PARSE_IPV6)(struct __sk_buff *skb)
 	return 0;
 }
 
-PROG(PARSE_VLAN)(struct __sk_buff *skb)
+PROG_SOCKET_FILTER
+int bpf_func_vlan(struct __sk_buff *skb)
 {
 	__u32 nhoff, proto;
 
@@ -256,7 +226,8 @@  PROG(PARSE_VLAN)(struct __sk_buff *skb)
 	return 0;
 }
 
-PROG(PARSE_MPLS)(struct __sk_buff *skb)
+PROG_SOCKET_FILTER
+int bpf_func_mpls(struct __sk_buff *skb)
 {
 	__u32 nhoff, label;
 
@@ -279,7 +250,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;
+	}
+}
+
+PROG_SOCKET_FILTER
 int main_prog(struct __sk_buff *skb)
 {
 	__u32 nhoff = ETH_HLEN;
diff --git a/samples/bpf/sockex3_user.c b/samples/bpf/sockex3_user.c
index cd6fa79df900..56044acbd25d 100644
--- a/samples/bpf/sockex3_user.c
+++ b/samples/bpf/sockex3_user.c
@@ -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");