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(®_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