2020-02-17 12:15:30 +00:00
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2020 Cloudflare
/*
* Tests for sockmap / sockhash holding kTLS sockets .
*/
2022-06-23 11:12:31 +02:00
# include <netinet/tcp.h>
2020-02-17 12:15:30 +00:00
# include "test_progs.h"
# define MAX_TEST_NAME 80
2020-02-19 12:55:14 -08:00
# define TCP_ULP 31
2020-02-17 12:15:30 +00:00
static int tcp_server ( int family )
{
int err , s ;
s = socket ( family , SOCK_STREAM , 0 ) ;
if ( CHECK_FAIL ( s = = - 1 ) ) {
perror ( " socket " ) ;
return - 1 ;
}
err = listen ( s , SOMAXCONN ) ;
if ( CHECK_FAIL ( err ) ) {
perror ( " listen " ) ;
return - 1 ;
}
return s ;
}
static int disconnect ( int fd )
{
struct sockaddr unspec = { AF_UNSPEC } ;
return connect ( fd , & unspec , sizeof ( unspec ) ) ;
}
/* Disconnect (unhash) a kTLS socket after removing it from sockmap. */
static void test_sockmap_ktls_disconnect_after_delete ( int family , int map )
{
struct sockaddr_storage addr = { 0 } ;
socklen_t len = sizeof ( addr ) ;
int err , cli , srv , zero = 0 ;
srv = tcp_server ( family ) ;
if ( srv = = - 1 )
return ;
err = getsockname ( srv , ( struct sockaddr * ) & addr , & len ) ;
if ( CHECK_FAIL ( err ) ) {
perror ( " getsockopt " ) ;
goto close_srv ;
}
cli = socket ( family , SOCK_STREAM , 0 ) ;
if ( CHECK_FAIL ( cli = = - 1 ) ) {
perror ( " socket " ) ;
goto close_srv ;
}
err = connect ( cli , ( struct sockaddr * ) & addr , len ) ;
if ( CHECK_FAIL ( err ) ) {
perror ( " connect " ) ;
goto close_cli ;
}
err = bpf_map_update_elem ( map , & zero , & cli , 0 ) ;
if ( CHECK_FAIL ( err ) ) {
perror ( " bpf_map_update_elem " ) ;
goto close_cli ;
}
err = setsockopt ( cli , IPPROTO_TCP , TCP_ULP , " tls " , strlen ( " tls " ) ) ;
if ( CHECK_FAIL ( err ) ) {
perror ( " setsockopt(TCP_ULP) " ) ;
goto close_cli ;
}
err = bpf_map_delete_elem ( map , & zero ) ;
if ( CHECK_FAIL ( err ) ) {
perror ( " bpf_map_delete_elem " ) ;
goto close_cli ;
}
err = disconnect ( cli ) ;
if ( CHECK_FAIL ( err ) )
perror ( " disconnect " ) ;
close_cli :
close ( cli ) ;
close_srv :
close ( srv ) ;
}
2022-06-23 11:12:31 +02:00
static void test_sockmap_ktls_update_fails_when_sock_has_ulp ( int family , int map )
{
struct sockaddr_storage addr = { } ;
socklen_t len = sizeof ( addr ) ;
struct sockaddr_in6 * v6 ;
struct sockaddr_in * v4 ;
int err , s , zero = 0 ;
switch ( family ) {
case AF_INET :
v4 = ( struct sockaddr_in * ) & addr ;
v4 - > sin_family = AF_INET ;
break ;
case AF_INET6 :
v6 = ( struct sockaddr_in6 * ) & addr ;
v6 - > sin6_family = AF_INET6 ;
break ;
default :
PRINT_FAIL ( " unsupported socket family %d " , family ) ;
return ;
}
s = socket ( family , SOCK_STREAM , 0 ) ;
if ( ! ASSERT_GE ( s , 0 , " socket " ) )
return ;
err = bind ( s , ( struct sockaddr * ) & addr , len ) ;
if ( ! ASSERT_OK ( err , " bind " ) )
goto close ;
err = getsockname ( s , ( struct sockaddr * ) & addr , & len ) ;
if ( ! ASSERT_OK ( err , " getsockname " ) )
goto close ;
err = connect ( s , ( struct sockaddr * ) & addr , len ) ;
if ( ! ASSERT_OK ( err , " connect " ) )
goto close ;
/* save sk->sk_prot and set it to tls_prots */
err = setsockopt ( s , IPPROTO_TCP , TCP_ULP , " tls " , strlen ( " tls " ) ) ;
if ( ! ASSERT_OK ( err , " setsockopt(TCP_ULP) " ) )
goto close ;
/* sockmap update should not affect saved sk_prot */
err = bpf_map_update_elem ( map , & zero , & s , BPF_ANY ) ;
if ( ! ASSERT_ERR ( err , " sockmap update elem " ) )
goto close ;
/* call sk->sk_prot->setsockopt to dispatch to saved sk_prot */
err = setsockopt ( s , IPPROTO_TCP , TCP_NODELAY , & zero , sizeof ( zero ) ) ;
ASSERT_OK ( err , " setsockopt(TCP_NODELAY) " ) ;
close :
close ( s ) ;
}
static const char * fmt_test_name ( const char * subtest_name , int family ,
enum bpf_map_type map_type )
{
const char * map_type_str = BPF_MAP_TYPE_SOCKMAP ? " SOCKMAP " : " SOCKHASH " ;
const char * family_str = AF_INET ? " IPv4 " : " IPv6 " ;
static char test_name [ MAX_TEST_NAME ] ;
snprintf ( test_name , MAX_TEST_NAME ,
" sockmap_ktls %s %s %s " ,
subtest_name , family_str , map_type_str ) ;
return test_name ;
}
2020-02-17 12:15:30 +00:00
static void run_tests ( int family , enum bpf_map_type map_type )
{
int map ;
2021-11-24 11:32:33 -08:00
map = bpf_map_create ( map_type , NULL , sizeof ( int ) , sizeof ( int ) , 1 , NULL ) ;
2021-05-24 20:59:32 -07:00
if ( CHECK_FAIL ( map < 0 ) ) {
2020-02-17 12:15:30 +00:00
perror ( " bpf_map_create " ) ;
return ;
}
2022-06-23 11:12:31 +02:00
if ( test__start_subtest ( fmt_test_name ( " disconnect_after_delete " , family , map_type ) ) )
test_sockmap_ktls_disconnect_after_delete ( family , map ) ;
if ( test__start_subtest ( fmt_test_name ( " update_fails_when_sock_has_ulp " , family , map_type ) ) )
test_sockmap_ktls_update_fails_when_sock_has_ulp ( family , map ) ;
2020-02-17 12:15:30 +00:00
close ( map ) ;
}
void test_sockmap_ktls ( void )
{
run_tests ( AF_INET , BPF_MAP_TYPE_SOCKMAP ) ;
run_tests ( AF_INET , BPF_MAP_TYPE_SOCKHASH ) ;
run_tests ( AF_INET6 , BPF_MAP_TYPE_SOCKMAP ) ;
run_tests ( AF_INET6 , BPF_MAP_TYPE_SOCKHASH ) ;
}