2018-05-14 10:00:18 -07:00
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2017-2018 Covalent IO, Inc. http://covalent.io */
# include <stddef.h>
# include <string.h>
# include <linux/bpf.h>
# include <linux/if_ether.h>
# include <linux/if_packet.h>
# include <linux/ip.h>
# include <linux/ipv6.h>
# include <linux/in.h>
# include <linux/udp.h>
# include <linux/tcp.h>
# include <linux/pkt_cls.h>
# include <sys/socket.h>
2020-01-20 14:06:45 +01:00
# include <bpf/bpf_helpers.h>
# include <bpf/bpf_endian.h>
2018-05-14 10:00:18 -07:00
/* Sockmap sample program connects a client and a backend together
* using cgroups .
*
* client : X < - - - > frontend : 80 client : X < - - - > backend : 80
*
* For simplicity we hard code values here and bind 1 : 1. The hard
* coded values are part of the setup in sockmap . sh script that
* is associated with this BPF program .
*
* The bpf_printk is verbose and prints information as connections
* are established and verdicts are decided .
*/
2019-07-05 08:50:12 -07:00
struct {
__uint ( type , TEST_MAP_TYPE ) ;
__uint ( max_entries , 20 ) ;
__uint ( key_size , sizeof ( int ) ) ;
__uint ( value_size , sizeof ( int ) ) ;
} sock_map SEC ( " .maps " ) ;
struct {
__uint ( type , TEST_MAP_TYPE ) ;
__uint ( max_entries , 20 ) ;
__uint ( key_size , sizeof ( int ) ) ;
__uint ( value_size , sizeof ( int ) ) ;
} sock_map_txmsg SEC ( " .maps " ) ;
struct {
__uint ( type , TEST_MAP_TYPE ) ;
__uint ( max_entries , 20 ) ;
__uint ( key_size , sizeof ( int ) ) ;
__uint ( value_size , sizeof ( int ) ) ;
} sock_map_redir SEC ( " .maps " ) ;
struct {
__uint ( type , BPF_MAP_TYPE_ARRAY ) ;
__uint ( max_entries , 1 ) ;
__type ( key , int ) ;
__type ( value , int ) ;
} sock_apply_bytes SEC ( " .maps " ) ;
struct {
__uint ( type , BPF_MAP_TYPE_ARRAY ) ;
__uint ( max_entries , 1 ) ;
__type ( key , int ) ;
__type ( value , int ) ;
} sock_cork_bytes SEC ( " .maps " ) ;
struct {
__uint ( type , BPF_MAP_TYPE_ARRAY ) ;
__uint ( max_entries , 6 ) ;
__type ( key , int ) ;
__type ( value , int ) ;
} sock_bytes SEC ( " .maps " ) ;
struct {
__uint ( type , BPF_MAP_TYPE_ARRAY ) ;
__uint ( max_entries , 1 ) ;
__type ( key , int ) ;
__type ( value , int ) ;
} sock_redir_flags SEC ( " .maps " ) ;
struct {
__uint ( type , BPF_MAP_TYPE_ARRAY ) ;
2020-06-25 16:13:38 -07:00
__uint ( max_entries , 3 ) ;
2019-07-05 08:50:12 -07:00
__type ( key , int ) ;
__type ( value , int ) ;
} sock_skb_opts SEC ( " .maps " ) ;
2018-05-14 10:00:18 -07:00
2020-05-29 16:07:19 -07:00
struct {
__uint ( type , TEST_MAP_TYPE ) ;
__uint ( max_entries , 20 ) ;
__uint ( key_size , sizeof ( int ) ) ;
__uint ( value_size , sizeof ( int ) ) ;
} tls_sock_map SEC ( " .maps " ) ;
2018-05-14 10:00:18 -07:00
SEC ( " sk_skb1 " )
int bpf_prog1 ( struct __sk_buff * skb )
{
2020-06-25 16:13:38 -07:00
int * f , two = 2 ;
f = bpf_map_lookup_elem ( & sock_skb_opts , & two ) ;
if ( f & & * f ) {
return * f ;
}
2018-05-14 10:00:18 -07:00
return skb - > len ;
}
SEC ( " sk_skb2 " )
int bpf_prog2 ( struct __sk_buff * skb )
{
__u32 lport = skb - > local_port ;
__u32 rport = skb - > remote_port ;
int len , * f , ret , zero = 0 ;
__u64 flags = 0 ;
if ( lport = = 10000 )
ret = 10 ;
else
ret = 1 ;
len = ( __u32 ) skb - > data_end - ( __u32 ) skb - > data ;
f = bpf_map_lookup_elem ( & sock_skb_opts , & zero ) ;
if ( f & & * f ) {
ret = 3 ;
flags = * f ;
}
# ifdef SOCKMAP
return bpf_sk_redirect_map ( skb , & sock_map , ret , flags ) ;
# else
return bpf_sk_redirect_hash ( skb , & sock_map , & ret , flags ) ;
# endif
}
2020-10-01 18:10:09 -07:00
static inline void bpf_write_pass ( struct __sk_buff * skb , int offset )
2020-05-29 16:07:19 -07:00
{
2020-10-01 18:10:09 -07:00
int err = bpf_skb_pull_data ( skb , 6 + offset ) ;
2020-05-29 16:07:19 -07:00
void * data_end ;
char * c ;
if ( err )
2020-10-01 18:10:09 -07:00
return ;
2020-05-29 16:07:19 -07:00
c = ( char * ) ( long ) skb - > data ;
data_end = ( void * ) ( long ) skb - > data_end ;
2020-10-01 18:10:09 -07:00
if ( c + 5 + offset < data_end )
memcpy ( c + offset , " PASS " , 4 ) ;
}
SEC ( " sk_skb3 " )
int bpf_prog3 ( struct __sk_buff * skb )
{
int err , * f , ret = SK_PASS ;
const int one = 1 ;
2020-05-29 16:07:19 -07:00
f = bpf_map_lookup_elem ( & sock_skb_opts , & one ) ;
if ( f & & * f ) {
__u64 flags = 0 ;
ret = 0 ;
flags = * f ;
2020-10-01 18:10:09 -07:00
err = bpf_skb_adjust_room ( skb , - 13 , 0 , 0 ) ;
if ( err )
return SK_DROP ;
err = bpf_skb_adjust_room ( skb , 4 , 0 , 0 ) ;
if ( err )
return SK_DROP ;
bpf_write_pass ( skb , 0 ) ;
2020-05-29 16:07:19 -07:00
# ifdef SOCKMAP
return bpf_sk_redirect_map ( skb , & tls_sock_map , ret , flags ) ;
# else
return bpf_sk_redirect_hash ( skb , & tls_sock_map , & ret , flags ) ;
# endif
}
f = bpf_map_lookup_elem ( & sock_skb_opts , & one ) ;
if ( f & & * f )
ret = SK_DROP ;
2020-10-01 18:10:09 -07:00
err = bpf_skb_adjust_room ( skb , 4 , 0 , 0 ) ;
if ( err )
return SK_DROP ;
bpf_write_pass ( skb , 13 ) ;
2020-05-29 16:07:19 -07:00
tls_out :
return ret ;
}
2018-05-14 10:00:18 -07:00
SEC ( " sockops " )
int bpf_sockmap ( struct bpf_sock_ops * skops )
{
__u32 lport , rport ;
int op , err = 0 , index , key , ret ;
op = ( int ) skops - > op ;
switch ( op ) {
case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB :
lport = skops - > local_port ;
rport = skops - > remote_port ;
if ( lport = = 10000 ) {
ret = 1 ;
# ifdef SOCKMAP
err = bpf_sock_map_update ( skops , & sock_map , & ret ,
BPF_NOEXIST ) ;
# else
err = bpf_sock_hash_update ( skops , & sock_map , & ret ,
BPF_NOEXIST ) ;
# endif
}
break ;
case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB :
lport = skops - > local_port ;
rport = skops - > remote_port ;
if ( bpf_ntohl ( rport ) = = 10001 ) {
ret = 10 ;
# ifdef SOCKMAP
err = bpf_sock_map_update ( skops , & sock_map , & ret ,
BPF_NOEXIST ) ;
# else
err = bpf_sock_hash_update ( skops , & sock_map , & ret ,
BPF_NOEXIST ) ;
# endif
}
break ;
default :
break ;
}
return 0 ;
}
SEC ( " sk_msg1 " )
int bpf_prog4 ( struct sk_msg_md * msg )
{
2018-11-26 14:16:19 -08:00
int * bytes , zero = 0 , one = 1 , two = 2 , three = 3 , four = 4 , five = 5 ;
2022-02-11 18:43:36 +01:00
int * start , * end , * start_push , * end_push , * start_pop , * pop , err = 0 ;
2018-05-14 10:00:18 -07:00
bytes = bpf_map_lookup_elem ( & sock_apply_bytes , & zero ) ;
if ( bytes )
bpf_msg_apply_bytes ( msg , * bytes ) ;
bytes = bpf_map_lookup_elem ( & sock_cork_bytes , & zero ) ;
if ( bytes )
bpf_msg_cork_bytes ( msg , * bytes ) ;
2018-10-19 19:56:51 -07:00
start = bpf_map_lookup_elem ( & sock_bytes , & zero ) ;
end = bpf_map_lookup_elem ( & sock_bytes , & one ) ;
2018-05-14 10:00:18 -07:00
if ( start & & end )
bpf_msg_pull_data ( msg , * start , * end , 0 ) ;
2018-10-19 19:56:51 -07:00
start_push = bpf_map_lookup_elem ( & sock_bytes , & two ) ;
end_push = bpf_map_lookup_elem ( & sock_bytes , & three ) ;
2022-02-11 18:43:36 +01:00
if ( start_push & & end_push ) {
err = bpf_msg_push_data ( msg , * start_push , * end_push , 0 ) ;
if ( err )
return SK_DROP ;
}
2018-11-26 14:16:19 -08:00
start_pop = bpf_map_lookup_elem ( & sock_bytes , & four ) ;
pop = bpf_map_lookup_elem ( & sock_bytes , & five ) ;
if ( start_pop & & pop )
bpf_msg_pop_data ( msg , * start_pop , * pop , 0 ) ;
2018-05-14 10:00:18 -07:00
return SK_PASS ;
}
SEC ( " sk_msg2 " )
int bpf_prog6 ( struct sk_msg_md * msg )
{
2018-11-26 14:16:19 -08:00
int zero = 0 , one = 1 , two = 2 , three = 3 , four = 4 , five = 5 , key = 0 ;
int * bytes , * start , * end , * start_push , * end_push , * start_pop , * pop , * f ;
2022-02-11 18:43:36 +01:00
int err = 0 ;
2018-05-14 10:00:18 -07:00
__u64 flags = 0 ;
bytes = bpf_map_lookup_elem ( & sock_apply_bytes , & zero ) ;
if ( bytes )
bpf_msg_apply_bytes ( msg , * bytes ) ;
bytes = bpf_map_lookup_elem ( & sock_cork_bytes , & zero ) ;
if ( bytes )
bpf_msg_cork_bytes ( msg , * bytes ) ;
2018-10-19 19:56:51 -07:00
start = bpf_map_lookup_elem ( & sock_bytes , & zero ) ;
end = bpf_map_lookup_elem ( & sock_bytes , & one ) ;
2018-05-14 10:00:18 -07:00
if ( start & & end )
bpf_msg_pull_data ( msg , * start , * end , 0 ) ;
2018-10-19 19:56:51 -07:00
start_push = bpf_map_lookup_elem ( & sock_bytes , & two ) ;
end_push = bpf_map_lookup_elem ( & sock_bytes , & three ) ;
2022-02-11 18:43:36 +01:00
if ( start_push & & end_push ) {
err = bpf_msg_push_data ( msg , * start_push , * end_push , 0 ) ;
if ( err )
return SK_DROP ;
}
2018-10-19 19:56:51 -07:00
2018-11-26 14:16:19 -08:00
start_pop = bpf_map_lookup_elem ( & sock_bytes , & four ) ;
pop = bpf_map_lookup_elem ( & sock_bytes , & five ) ;
if ( start_pop & & pop )
bpf_msg_pop_data ( msg , * start_pop , * pop , 0 ) ;
2018-05-14 10:00:18 -07:00
f = bpf_map_lookup_elem ( & sock_redir_flags , & zero ) ;
if ( f & & * f ) {
key = 2 ;
flags = * f ;
}
# ifdef SOCKMAP
return bpf_msg_redirect_map ( msg , & sock_map_redir , key , flags ) ;
# else
return bpf_msg_redirect_hash ( msg , & sock_map_redir , & key , flags ) ;
# endif
}
2020-05-13 12:13:27 -07:00
SEC ( " sk_msg3 " )
2018-05-14 10:00:18 -07:00
int bpf_prog8 ( struct sk_msg_md * msg )
{
void * data_end = ( void * ) ( long ) msg - > data_end ;
void * data = ( void * ) ( long ) msg - > data ;
int ret = 0 , * bytes , zero = 0 ;
bytes = bpf_map_lookup_elem ( & sock_apply_bytes , & zero ) ;
if ( bytes ) {
ret = bpf_msg_apply_bytes ( msg , * bytes ) ;
if ( ret )
return SK_DROP ;
} else {
return SK_DROP ;
}
return SK_PASS ;
}
2020-05-13 12:13:27 -07:00
SEC ( " sk_msg4 " )
2018-05-14 10:00:18 -07:00
int bpf_prog9 ( struct sk_msg_md * msg )
{
void * data_end = ( void * ) ( long ) msg - > data_end ;
void * data = ( void * ) ( long ) msg - > data ;
int ret = 0 , * bytes , zero = 0 ;
bytes = bpf_map_lookup_elem ( & sock_cork_bytes , & zero ) ;
if ( bytes ) {
if ( ( ( __u64 ) data_end - ( __u64 ) data ) > = * bytes )
return SK_PASS ;
ret = bpf_msg_cork_bytes ( msg , * bytes ) ;
if ( ret )
return SK_DROP ;
}
return SK_PASS ;
}
2020-05-13 12:13:27 -07:00
SEC ( " sk_msg5 " )
2018-05-14 10:00:18 -07:00
int bpf_prog10 ( struct sk_msg_md * msg )
{
2018-11-26 14:16:19 -08:00
int * bytes , * start , * end , * start_push , * end_push , * start_pop , * pop ;
2022-02-11 18:43:36 +01:00
int zero = 0 , one = 1 , two = 2 , three = 3 , four = 4 , five = 5 , err = 0 ;
2018-05-14 10:00:18 -07:00
bytes = bpf_map_lookup_elem ( & sock_apply_bytes , & zero ) ;
if ( bytes )
bpf_msg_apply_bytes ( msg , * bytes ) ;
bytes = bpf_map_lookup_elem ( & sock_cork_bytes , & zero ) ;
if ( bytes )
bpf_msg_cork_bytes ( msg , * bytes ) ;
2018-10-19 19:56:51 -07:00
start = bpf_map_lookup_elem ( & sock_bytes , & zero ) ;
end = bpf_map_lookup_elem ( & sock_bytes , & one ) ;
2018-05-14 10:00:18 -07:00
if ( start & & end )
bpf_msg_pull_data ( msg , * start , * end , 0 ) ;
2018-10-19 19:56:51 -07:00
start_push = bpf_map_lookup_elem ( & sock_bytes , & two ) ;
end_push = bpf_map_lookup_elem ( & sock_bytes , & three ) ;
2022-02-11 18:43:36 +01:00
if ( start_push & & end_push ) {
err = bpf_msg_push_data ( msg , * start_push , * end_push , 0 ) ;
if ( err )
return SK_PASS ;
}
2018-11-26 14:16:19 -08:00
start_pop = bpf_map_lookup_elem ( & sock_bytes , & four ) ;
pop = bpf_map_lookup_elem ( & sock_bytes , & five ) ;
if ( start_pop & & pop )
bpf_msg_pop_data ( msg , * start_pop , * pop , 0 ) ;
2018-05-14 10:00:18 -07:00
return SK_DROP ;
}
char _license [ ] SEC ( " license " ) = " GPL " ;