2019-03-23 15:51:00 -07:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
# include <stdint.h>
# include <string.h>
# include <linux/stddef.h>
# include <linux/bpf.h>
2020-01-20 14:06:45 +01:00
# include <bpf/bpf_helpers.h>
2019-03-23 15:51:00 -07:00
/* Max supported length of a string with unsigned long in base 10 (pow2 - 1). */
# define MAX_ULONG_STR_LEN 0xF
/* Max supported length of sysctl value string (pow2). */
# define MAX_VALUE_STR_LEN 0x40
2019-06-10 17:56:51 -07:00
# ifndef ARRAY_SIZE
# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
# endif
2020-09-10 13:27:18 -07:00
const char tcp_mem_name [ ] = " net/ipv4/tcp_mem " ;
2019-03-23 15:51:00 -07:00
static __always_inline int is_tcp_mem ( struct bpf_sysctl * ctx )
{
unsigned char i ;
2020-09-10 13:27:18 -07:00
char name [ sizeof ( tcp_mem_name ) ] ;
2019-03-23 15:51:00 -07:00
int ret ;
memset ( name , 0 , sizeof ( name ) ) ;
ret = bpf_sysctl_get_name ( ctx , name , sizeof ( name ) , 0 ) ;
if ( ret < 0 | | ret ! = sizeof ( tcp_mem_name ) - 1 )
return 0 ;
# pragma clang loop unroll(full)
for ( i = 0 ; i < sizeof ( tcp_mem_name ) ; + + i )
if ( name [ i ] ! = tcp_mem_name [ i ] )
return 0 ;
return 1 ;
}
SEC ( " cgroup/sysctl " )
int sysctl_tcp_mem ( struct bpf_sysctl * ctx )
{
unsigned long tcp_mem [ 3 ] = { 0 , 0 , 0 } ;
char value [ MAX_VALUE_STR_LEN ] ;
unsigned char i , off = 0 ;
2020-04-28 15:30:48 -07:00
volatile int ret ;
2019-03-23 15:51:00 -07:00
if ( ctx - > write )
return 0 ;
if ( ! is_tcp_mem ( ctx ) )
return 0 ;
ret = bpf_sysctl_get_current_value ( ctx , value , MAX_VALUE_STR_LEN ) ;
if ( ret < 0 | | ret > = MAX_VALUE_STR_LEN )
return 0 ;
# pragma clang loop unroll(full)
for ( i = 0 ; i < ARRAY_SIZE ( tcp_mem ) ; + + i ) {
ret = bpf_strtoul ( value + off , MAX_ULONG_STR_LEN , 0 ,
tcp_mem + i ) ;
if ( ret < = 0 | | ret > MAX_ULONG_STR_LEN )
return 0 ;
off + = ret & MAX_ULONG_STR_LEN ;
}
return tcp_mem [ 0 ] < tcp_mem [ 1 ] & & tcp_mem [ 1 ] < tcp_mem [ 2 ] ;
}
char _license [ ] SEC ( " license " ) = " GPL " ;