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