xref: /linux/samples/bpf/test_map_in_map.bpf.c (revision 8dc80551)
1e04946f5SDaniel T. Lee /*
2e04946f5SDaniel T. Lee  * Copyright (c) 2017 Facebook
3e04946f5SDaniel T. Lee  *
4e04946f5SDaniel T. Lee  * This program is free software; you can redistribute it and/or
5e04946f5SDaniel T. Lee  * modify it under the terms of version 2 of the GNU General Public
6e04946f5SDaniel T. Lee  * License as published by the Free Software Foundation.
7e04946f5SDaniel T. Lee  */
8e04946f5SDaniel T. Lee #define KBUILD_MODNAME "foo"
9e04946f5SDaniel T. Lee #include "vmlinux.h"
10e04946f5SDaniel T. Lee #include <linux/version.h>
11e04946f5SDaniel T. Lee #include <bpf/bpf_helpers.h>
12e04946f5SDaniel T. Lee #include <bpf/bpf_tracing.h>
13e04946f5SDaniel T. Lee #include <bpf/bpf_core_read.h>
14e04946f5SDaniel T. Lee 
15e04946f5SDaniel T. Lee #define MAX_NR_PORTS 65536
16e04946f5SDaniel T. Lee 
17e04946f5SDaniel T. Lee #define EINVAL 22
18e04946f5SDaniel T. Lee #define ENOENT 2
19e04946f5SDaniel T. Lee 
20e04946f5SDaniel T. Lee /* map #0 */
21e04946f5SDaniel T. Lee struct inner_a {
22e04946f5SDaniel T. Lee 	__uint(type, BPF_MAP_TYPE_ARRAY);
23e04946f5SDaniel T. Lee 	__type(key, u32);
24e04946f5SDaniel T. Lee 	__type(value, int);
25e04946f5SDaniel T. Lee 	__uint(max_entries, MAX_NR_PORTS);
26e04946f5SDaniel T. Lee } port_a SEC(".maps");
27e04946f5SDaniel T. Lee 
28e04946f5SDaniel T. Lee /* map #1 */
29e04946f5SDaniel T. Lee struct inner_h {
30e04946f5SDaniel T. Lee 	__uint(type, BPF_MAP_TYPE_HASH);
31e04946f5SDaniel T. Lee 	__type(key, u32);
32e04946f5SDaniel T. Lee 	__type(value, int);
33e04946f5SDaniel T. Lee 	__uint(max_entries, 1);
34e04946f5SDaniel T. Lee } port_h SEC(".maps");
35e04946f5SDaniel T. Lee 
36e04946f5SDaniel T. Lee /* map #2 */
37e04946f5SDaniel T. Lee struct {
38e04946f5SDaniel T. Lee 	__uint(type, BPF_MAP_TYPE_HASH);
39e04946f5SDaniel T. Lee 	__type(key, u32);
40e04946f5SDaniel T. Lee 	__type(value, int);
41e04946f5SDaniel T. Lee 	__uint(max_entries, 1);
42e04946f5SDaniel T. Lee } reg_result_h SEC(".maps");
43e04946f5SDaniel T. Lee 
44e04946f5SDaniel T. Lee /* map #3 */
45e04946f5SDaniel T. Lee struct {
46e04946f5SDaniel T. Lee 	__uint(type, BPF_MAP_TYPE_HASH);
47e04946f5SDaniel T. Lee 	__type(key, u32);
48e04946f5SDaniel T. Lee 	__type(value, int);
49e04946f5SDaniel T. Lee 	__uint(max_entries, 1);
50e04946f5SDaniel T. Lee } inline_result_h SEC(".maps");
51e04946f5SDaniel T. Lee 
52e04946f5SDaniel T. Lee /* map #4 */ /* Test case #0 */
53e04946f5SDaniel T. Lee struct {
54e04946f5SDaniel T. Lee 	__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
55e04946f5SDaniel T. Lee 	__uint(max_entries, MAX_NR_PORTS);
56e04946f5SDaniel T. Lee 	__uint(key_size, sizeof(u32));
57e04946f5SDaniel T. Lee 	__array(values, struct inner_a); /* use inner_a as inner map */
58e04946f5SDaniel T. Lee } a_of_port_a SEC(".maps");
59e04946f5SDaniel T. Lee 
60e04946f5SDaniel T. Lee /* map #5 */ /* Test case #1 */
61e04946f5SDaniel T. Lee struct {
62e04946f5SDaniel T. Lee 	__uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
63e04946f5SDaniel T. Lee 	__uint(max_entries, 1);
64e04946f5SDaniel T. Lee 	__uint(key_size, sizeof(u32));
65e04946f5SDaniel T. Lee 	__array(values, struct inner_a); /* use inner_a as inner map */
66e04946f5SDaniel T. Lee } h_of_port_a SEC(".maps");
67e04946f5SDaniel T. Lee 
68e04946f5SDaniel T. Lee /* map #6 */ /* Test case #2 */
69e04946f5SDaniel T. Lee struct {
70e04946f5SDaniel T. Lee 	__uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
71e04946f5SDaniel T. Lee 	__uint(max_entries, 1);
72e04946f5SDaniel T. Lee 	__uint(key_size, sizeof(u32));
73e04946f5SDaniel T. Lee 	__array(values, struct inner_h); /* use inner_h as inner map */
74e04946f5SDaniel T. Lee } h_of_port_h SEC(".maps");
75e04946f5SDaniel T. Lee 
do_reg_lookup(void * inner_map,u32 port)76e04946f5SDaniel T. Lee static __always_inline int do_reg_lookup(void *inner_map, u32 port)
77e04946f5SDaniel T. Lee {
78e04946f5SDaniel T. Lee 	int *result;
79e04946f5SDaniel T. Lee 
80e04946f5SDaniel T. Lee 	result = bpf_map_lookup_elem(inner_map, &port);
81e04946f5SDaniel T. Lee 	return result ? *result : -ENOENT;
82e04946f5SDaniel T. Lee }
83e04946f5SDaniel T. Lee 
do_inline_array_lookup(void * inner_map,u32 port)84e04946f5SDaniel T. Lee static __always_inline int do_inline_array_lookup(void *inner_map, u32 port)
85e04946f5SDaniel T. Lee {
86e04946f5SDaniel T. Lee 	int *result;
87e04946f5SDaniel T. Lee 
88e04946f5SDaniel T. Lee 	if (inner_map != &port_a)
89e04946f5SDaniel T. Lee 		return -EINVAL;
90e04946f5SDaniel T. Lee 
91e04946f5SDaniel T. Lee 	result = bpf_map_lookup_elem(&port_a, &port);
92e04946f5SDaniel T. Lee 	return result ? *result : -ENOENT;
93e04946f5SDaniel T. Lee }
94e04946f5SDaniel T. Lee 
do_inline_hash_lookup(void * inner_map,u32 port)95e04946f5SDaniel T. Lee static __always_inline int do_inline_hash_lookup(void *inner_map, u32 port)
96e04946f5SDaniel T. Lee {
97e04946f5SDaniel T. Lee 	int *result;
98e04946f5SDaniel T. Lee 
99e04946f5SDaniel T. Lee 	if (inner_map != &port_h)
100e04946f5SDaniel T. Lee 		return -EINVAL;
101e04946f5SDaniel T. Lee 
102e04946f5SDaniel T. Lee 	result = bpf_map_lookup_elem(&port_h, &port);
103e04946f5SDaniel T. Lee 	return result ? *result : -ENOENT;
104e04946f5SDaniel T. Lee }
105e04946f5SDaniel T. Lee 
106*8dc80551SDaniel T. Lee SEC("ksyscall/connect")
BPF_KSYSCALL(trace_sys_connect,unsigned int fd,struct sockaddr_in6 * in6,int addrlen)107*8dc80551SDaniel T. Lee int BPF_KSYSCALL(trace_sys_connect, unsigned int fd, struct sockaddr_in6 *in6, int addrlen)
108e04946f5SDaniel T. Lee {
109e04946f5SDaniel T. Lee 	u16 test_case, port, dst6[8];
110*8dc80551SDaniel T. Lee 	int ret, inline_ret, ret_key = 0;
111e04946f5SDaniel T. Lee 	u32 port_key;
112e04946f5SDaniel T. Lee 	void *outer_map, *inner_map;
113e04946f5SDaniel T. Lee 	bool inline_hash = false;
114e04946f5SDaniel T. Lee 
115e04946f5SDaniel T. Lee 	if (addrlen != sizeof(*in6))
116e04946f5SDaniel T. Lee 		return 0;
117e04946f5SDaniel T. Lee 
118e04946f5SDaniel T. Lee 	ret = bpf_probe_read_user(dst6, sizeof(dst6), &in6->sin6_addr);
119e04946f5SDaniel T. Lee 	if (ret) {
120e04946f5SDaniel T. Lee 		inline_ret = ret;
121e04946f5SDaniel T. Lee 		goto done;
122e04946f5SDaniel T. Lee 	}
123e04946f5SDaniel T. Lee 
124e04946f5SDaniel T. Lee 	if (dst6[0] != 0xdead || dst6[1] != 0xbeef)
125e04946f5SDaniel T. Lee 		return 0;
126e04946f5SDaniel T. Lee 
127e04946f5SDaniel T. Lee 	test_case = dst6[7];
128e04946f5SDaniel T. Lee 
129e04946f5SDaniel T. Lee 	ret = bpf_probe_read_user(&port, sizeof(port), &in6->sin6_port);
130e04946f5SDaniel T. Lee 	if (ret) {
131e04946f5SDaniel T. Lee 		inline_ret = ret;
132e04946f5SDaniel T. Lee 		goto done;
133e04946f5SDaniel T. Lee 	}
134e04946f5SDaniel T. Lee 
135e04946f5SDaniel T. Lee 	port_key = port;
136e04946f5SDaniel T. Lee 
137e04946f5SDaniel T. Lee 	ret = -ENOENT;
138e04946f5SDaniel T. Lee 	if (test_case == 0) {
139e04946f5SDaniel T. Lee 		outer_map = &a_of_port_a;
140e04946f5SDaniel T. Lee 	} else if (test_case == 1) {
141e04946f5SDaniel T. Lee 		outer_map = &h_of_port_a;
142e04946f5SDaniel T. Lee 	} else if (test_case == 2) {
143e04946f5SDaniel T. Lee 		outer_map = &h_of_port_h;
144e04946f5SDaniel T. Lee 	} else {
145e04946f5SDaniel T. Lee 		ret = __LINE__;
146e04946f5SDaniel T. Lee 		inline_ret = ret;
147e04946f5SDaniel T. Lee 		goto done;
148e04946f5SDaniel T. Lee 	}
149e04946f5SDaniel T. Lee 
150e04946f5SDaniel T. Lee 	inner_map = bpf_map_lookup_elem(outer_map, &port_key);
151e04946f5SDaniel T. Lee 	if (!inner_map) {
152e04946f5SDaniel T. Lee 		ret = __LINE__;
153e04946f5SDaniel T. Lee 		inline_ret = ret;
154e04946f5SDaniel T. Lee 		goto done;
155e04946f5SDaniel T. Lee 	}
156e04946f5SDaniel T. Lee 
157e04946f5SDaniel T. Lee 	ret = do_reg_lookup(inner_map, port_key);
158e04946f5SDaniel T. Lee 
159e04946f5SDaniel T. Lee 	if (test_case == 0 || test_case == 1)
160e04946f5SDaniel T. Lee 		inline_ret = do_inline_array_lookup(inner_map, port_key);
161e04946f5SDaniel T. Lee 	else
162e04946f5SDaniel T. Lee 		inline_ret = do_inline_hash_lookup(inner_map, port_key);
163e04946f5SDaniel T. Lee 
164e04946f5SDaniel T. Lee done:
165e04946f5SDaniel T. Lee 	bpf_map_update_elem(&reg_result_h, &ret_key, &ret, BPF_ANY);
166e04946f5SDaniel T. Lee 	bpf_map_update_elem(&inline_result_h, &ret_key, &inline_ret, BPF_ANY);
167e04946f5SDaniel T. Lee 
168e04946f5SDaniel T. Lee 	return 0;
169e04946f5SDaniel T. Lee }
170e04946f5SDaniel T. Lee 
171e04946f5SDaniel T. Lee char _license[] SEC("license") = "GPL";
172e04946f5SDaniel T. Lee u32 _version SEC("version") = LINUX_VERSION_CODE;
173