1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2019 Facebook 3 4 #include <stdint.h> 5 #include <string.h> 6 7 #include <linux/stddef.h> 8 #include <linux/bpf.h> 9 10 #include "bpf_helpers.h" 11 #include "bpf_util.h" 12 13 /* Max supported length of a string with unsigned long in base 10 (pow2 - 1). */ 14 #define MAX_ULONG_STR_LEN 0xF 15 16 /* Max supported length of sysctl value string (pow2). */ 17 #define MAX_VALUE_STR_LEN 0x40 18 19 static __always_inline int is_tcp_mem(struct bpf_sysctl *ctx) 20 { 21 char tcp_mem_name[] = "net/ipv4/tcp_mem"; 22 unsigned char i; 23 char name[64]; 24 int ret; 25 26 memset(name, 0, sizeof(name)); 27 ret = bpf_sysctl_get_name(ctx, name, sizeof(name), 0); 28 if (ret < 0 || ret != sizeof(tcp_mem_name) - 1) 29 return 0; 30 31 #pragma clang loop unroll(full) 32 for (i = 0; i < sizeof(tcp_mem_name); ++i) 33 if (name[i] != tcp_mem_name[i]) 34 return 0; 35 36 return 1; 37 } 38 39 SEC("cgroup/sysctl") 40 int sysctl_tcp_mem(struct bpf_sysctl *ctx) 41 { 42 unsigned long tcp_mem[3] = {0, 0, 0}; 43 char value[MAX_VALUE_STR_LEN]; 44 unsigned char i, off = 0; 45 int ret; 46 47 if (ctx->write) 48 return 0; 49 50 if (!is_tcp_mem(ctx)) 51 return 0; 52 53 ret = bpf_sysctl_get_current_value(ctx, value, MAX_VALUE_STR_LEN); 54 if (ret < 0 || ret >= MAX_VALUE_STR_LEN) 55 return 0; 56 57 #pragma clang loop unroll(full) 58 for (i = 0; i < ARRAY_SIZE(tcp_mem); ++i) { 59 ret = bpf_strtoul(value + off, MAX_ULONG_STR_LEN, 0, 60 tcp_mem + i); 61 if (ret <= 0 || ret > MAX_ULONG_STR_LEN) 62 return 0; 63 off += ret & MAX_ULONG_STR_LEN; 64 } 65 66 67 return tcp_mem[0] < tcp_mem[1] && tcp_mem[1] < tcp_mem[2]; 68 } 69 70 char _license[] SEC("license") = "GPL"; 71