diff options
| author | Dmitry Torokhov <[email protected]> | 2023-05-01 15:20:08 -0700 | 
|---|---|---|
| committer | Dmitry Torokhov <[email protected]> | 2023-05-01 15:20:08 -0700 | 
| commit | 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e (patch) | |
| tree | d57f3a63479a07b4e0cece029886e76e04feb984 /samples/bpf/test_map_in_map.bpf.c | |
| parent | 5dc63e56a9cf8df0b59c234a505a1653f1bdf885 (diff) | |
| parent | 53bea86b5712c7491bb3dae12e271666df0a308c (diff) | |
Merge branch 'next' into for-linus
Prepare input updates for 6.4 merge window.
Diffstat (limited to 'samples/bpf/test_map_in_map.bpf.c')
| -rw-r--r-- | samples/bpf/test_map_in_map.bpf.c | 176 | 
1 files changed, 176 insertions, 0 deletions
diff --git a/samples/bpf/test_map_in_map.bpf.c b/samples/bpf/test_map_in_map.bpf.c new file mode 100644 index 000000000000..1883559e5977 --- /dev/null +++ b/samples/bpf/test_map_in_map.bpf.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2017 Facebook + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ +#define KBUILD_MODNAME "foo" +#include "vmlinux.h" +#include <linux/version.h> +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> +#include <bpf/bpf_core_read.h> + +#define MAX_NR_PORTS 65536 + +#define EINVAL 22 +#define ENOENT 2 + +/* map #0 */ +struct inner_a { +	__uint(type, BPF_MAP_TYPE_ARRAY); +	__type(key, u32); +	__type(value, int); +	__uint(max_entries, MAX_NR_PORTS); +} port_a SEC(".maps"); + +/* map #1 */ +struct inner_h { +	__uint(type, BPF_MAP_TYPE_HASH); +	__type(key, u32); +	__type(value, int); +	__uint(max_entries, 1); +} port_h SEC(".maps"); + +/* map #2 */ +struct { +	__uint(type, BPF_MAP_TYPE_HASH); +	__type(key, u32); +	__type(value, int); +	__uint(max_entries, 1); +} reg_result_h SEC(".maps"); + +/* map #3 */ +struct { +	__uint(type, BPF_MAP_TYPE_HASH); +	__type(key, u32); +	__type(value, int); +	__uint(max_entries, 1); +} inline_result_h SEC(".maps"); + +/* map #4 */ /* Test case #0 */ +struct { +	__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); +	__uint(max_entries, MAX_NR_PORTS); +	__uint(key_size, sizeof(u32)); +	__array(values, struct inner_a); /* use inner_a as inner map */ +} a_of_port_a SEC(".maps"); + +/* map #5 */ /* Test case #1 */ +struct { +	__uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); +	__uint(max_entries, 1); +	__uint(key_size, sizeof(u32)); +	__array(values, struct inner_a); /* use inner_a as inner map */ +} h_of_port_a SEC(".maps"); + +/* map #6 */ /* Test case #2 */ +struct { +	__uint(type, BPF_MAP_TYPE_HASH_OF_MAPS); +	__uint(max_entries, 1); +	__uint(key_size, sizeof(u32)); +	__array(values, struct inner_h); /* use inner_h as inner map */ +} h_of_port_h SEC(".maps"); + +static __always_inline int do_reg_lookup(void *inner_map, u32 port) +{ +	int *result; + +	result = bpf_map_lookup_elem(inner_map, &port); +	return result ? *result : -ENOENT; +} + +static __always_inline int do_inline_array_lookup(void *inner_map, u32 port) +{ +	int *result; + +	if (inner_map != &port_a) +		return -EINVAL; + +	result = bpf_map_lookup_elem(&port_a, &port); +	return result ? *result : -ENOENT; +} + +static __always_inline int do_inline_hash_lookup(void *inner_map, u32 port) +{ +	int *result; + +	if (inner_map != &port_h) +		return -EINVAL; + +	result = bpf_map_lookup_elem(&port_h, &port); +	return result ? *result : -ENOENT; +} + +SEC("kprobe/__sys_connect") +int trace_sys_connect(struct pt_regs *ctx) +{ +	struct sockaddr_in6 *in6; +	u16 test_case, port, dst6[8]; +	int addrlen, ret, inline_ret, ret_key = 0; +	u32 port_key; +	void *outer_map, *inner_map; +	bool inline_hash = false; + +	in6 = (struct sockaddr_in6 *)PT_REGS_PARM2_CORE(ctx); +	addrlen = (int)PT_REGS_PARM3_CORE(ctx); + +	if (addrlen != sizeof(*in6)) +		return 0; + +	ret = bpf_probe_read_user(dst6, sizeof(dst6), &in6->sin6_addr); +	if (ret) { +		inline_ret = ret; +		goto done; +	} + +	if (dst6[0] != 0xdead || dst6[1] != 0xbeef) +		return 0; + +	test_case = dst6[7]; + +	ret = bpf_probe_read_user(&port, sizeof(port), &in6->sin6_port); +	if (ret) { +		inline_ret = ret; +		goto done; +	} + +	port_key = port; + +	ret = -ENOENT; +	if (test_case == 0) { +		outer_map = &a_of_port_a; +	} else if (test_case == 1) { +		outer_map = &h_of_port_a; +	} else if (test_case == 2) { +		outer_map = &h_of_port_h; +	} else { +		ret = __LINE__; +		inline_ret = ret; +		goto done; +	} + +	inner_map = bpf_map_lookup_elem(outer_map, &port_key); +	if (!inner_map) { +		ret = __LINE__; +		inline_ret = ret; +		goto done; +	} + +	ret = do_reg_lookup(inner_map, port_key); + +	if (test_case == 0 || test_case == 1) +		inline_ret = do_inline_array_lookup(inner_map, port_key); +	else +		inline_ret = do_inline_hash_lookup(inner_map, port_key); + +done: +	bpf_map_update_elem(®_result_h, &ret_key, &ret, BPF_ANY); +	bpf_map_update_elem(&inline_result_h, &ret_key, &inline_ret, BPF_ANY); + +	return 0; +} + +char _license[] SEC("license") = "GPL"; +u32 _version SEC("version") = LINUX_VERSION_CODE;  |