2021-07-20 22:43:01 +03:00
// SPDX-License-Identifier: GPL-2.0+
/*
* Author : Justin Iurman ( justin . iurman @ uliege . be )
*
2021-08-16 20:16:38 +03:00
* IOAM tester for IPv6 , see ioam6 . sh for details on each test case .
2021-07-20 22:43:01 +03:00
*/
2021-08-16 20:16:38 +03:00
# include <arpa/inet.h>
# include <errno.h>
# include <limits.h>
2021-07-20 22:43:01 +03:00
# include <linux/const.h>
# include <linux/if_ether.h>
# include <linux/ioam6.h>
# include <linux/ipv6.h>
# include <stdlib.h>
# include <string.h>
# include <unistd.h>
2021-08-16 20:16:38 +03:00
struct ioam_config {
2021-07-20 22:43:01 +03:00
__u32 id ;
__u64 wide ;
__u16 ingr_id ;
__u16 egr_id ;
__u32 ingr_wide ;
__u32 egr_wide ;
__u32 ns_data ;
__u64 ns_wide ;
__u32 sc_id ;
2021-08-16 20:16:38 +03:00
__u8 hlim ;
char * sc_data ;
2021-07-20 22:43:01 +03:00
} ;
2021-08-16 20:16:38 +03:00
/*
* Be careful if you modify structs below - everything MUST be kept synchronized
* with configurations inside ioam6 . sh and always reflect the same .
*/
static struct ioam_config node1 = {
. id = 1 ,
. wide = 11111111 ,
. ingr_id = 0xffff , /* default value */
. egr_id = 101 ,
. ingr_wide = 0xffffffff , /* default value */
. egr_wide = 101101 ,
. ns_data = 0xdeadbee0 ,
. ns_wide = 0xcafec0caf00dc0de ,
. sc_id = 777 ,
. sc_data = " something that will be 4n-aligned " ,
. hlim = 64 ,
2021-07-20 22:43:01 +03:00
} ;
2021-08-16 20:16:38 +03:00
static struct ioam_config node2 = {
. id = 2 ,
. wide = 22222222 ,
. ingr_id = 201 ,
. egr_id = 202 ,
. ingr_wide = 201201 ,
. egr_wide = 202202 ,
. ns_data = 0xdeadbee1 ,
. ns_wide = 0xcafec0caf11dc0de ,
. sc_id = 666 ,
. sc_data = " Hello there -Obi " ,
. hlim = 63 ,
} ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
static struct ioam_config node3 = {
. id = 3 ,
. wide = 33333333 ,
. ingr_id = 301 ,
. egr_id = 0xffff , /* default value */
. ingr_wide = 301301 ,
. egr_wide = 0xffffffff , /* default value */
. ns_data = 0xdeadbee2 ,
. ns_wide = 0xcafec0caf22dc0de ,
. sc_id = 0xffffff , /* default value */
. sc_data = NULL ,
. hlim = 62 ,
2021-07-20 22:43:01 +03:00
} ;
enum {
2021-08-16 20:16:38 +03:00
/**********
* OUTPUT *
* * * * * * * * * */
TEST_OUT_UNDEF_NS ,
TEST_OUT_NO_ROOM ,
TEST_OUT_BIT0 ,
TEST_OUT_BIT1 ,
TEST_OUT_BIT2 ,
TEST_OUT_BIT3 ,
TEST_OUT_BIT4 ,
TEST_OUT_BIT5 ,
TEST_OUT_BIT6 ,
TEST_OUT_BIT7 ,
TEST_OUT_BIT8 ,
TEST_OUT_BIT9 ,
TEST_OUT_BIT10 ,
TEST_OUT_BIT11 ,
TEST_OUT_BIT22 ,
TEST_OUT_FULL_SUPP_TRACE ,
/*********
* INPUT *
* * * * * * * * */
TEST_IN_UNDEF_NS ,
TEST_IN_NO_ROOM ,
TEST_IN_OFLAG ,
TEST_IN_BIT0 ,
TEST_IN_BIT1 ,
TEST_IN_BIT2 ,
TEST_IN_BIT3 ,
TEST_IN_BIT4 ,
TEST_IN_BIT5 ,
TEST_IN_BIT6 ,
TEST_IN_BIT7 ,
TEST_IN_BIT8 ,
TEST_IN_BIT9 ,
TEST_IN_BIT10 ,
TEST_IN_BIT11 ,
TEST_IN_BIT22 ,
TEST_IN_FULL_SUPP_TRACE ,
/**********
* GLOBAL *
* * * * * * * * * */
TEST_FWD_FULL_SUPP_TRACE ,
__TEST_MAX ,
2021-07-20 22:43:01 +03:00
} ;
2021-08-16 20:16:38 +03:00
static int check_ioam_header ( int tid , struct ioam6_trace_hdr * ioam6h ,
__u32 trace_type , __u16 ioam_ns )
{
if ( __be16_to_cpu ( ioam6h - > namespace_id ) ! = ioam_ns | |
__be32_to_cpu ( ioam6h - > type_be32 ) ! = ( trace_type < < 8 ) )
return 1 ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
switch ( tid ) {
case TEST_OUT_UNDEF_NS :
case TEST_IN_UNDEF_NS :
return ioam6h - > overflow | |
ioam6h - > nodelen ! = 1 | |
ioam6h - > remlen ! = 1 ;
case TEST_OUT_NO_ROOM :
case TEST_IN_NO_ROOM :
case TEST_IN_OFLAG :
return ! ioam6h - > overflow | |
ioam6h - > nodelen ! = 2 | |
ioam6h - > remlen ! = 1 ;
case TEST_OUT_BIT0 :
case TEST_IN_BIT0 :
case TEST_OUT_BIT1 :
case TEST_IN_BIT1 :
case TEST_OUT_BIT2 :
case TEST_IN_BIT2 :
case TEST_OUT_BIT3 :
case TEST_IN_BIT3 :
case TEST_OUT_BIT4 :
case TEST_IN_BIT4 :
case TEST_OUT_BIT5 :
case TEST_IN_BIT5 :
case TEST_OUT_BIT6 :
case TEST_IN_BIT6 :
case TEST_OUT_BIT7 :
case TEST_IN_BIT7 :
case TEST_OUT_BIT11 :
case TEST_IN_BIT11 :
return ioam6h - > overflow | |
ioam6h - > nodelen ! = 1 | |
ioam6h - > remlen ;
case TEST_OUT_BIT8 :
case TEST_IN_BIT8 :
case TEST_OUT_BIT9 :
case TEST_IN_BIT9 :
case TEST_OUT_BIT10 :
case TEST_IN_BIT10 :
return ioam6h - > overflow | |
ioam6h - > nodelen ! = 2 | |
ioam6h - > remlen ;
case TEST_OUT_BIT22 :
case TEST_IN_BIT22 :
return ioam6h - > overflow | |
ioam6h - > nodelen | |
ioam6h - > remlen ;
case TEST_OUT_FULL_SUPP_TRACE :
case TEST_IN_FULL_SUPP_TRACE :
case TEST_FWD_FULL_SUPP_TRACE :
return ioam6h - > overflow | |
ioam6h - > nodelen ! = 15 | |
ioam6h - > remlen ;
default :
break ;
}
return 1 ;
}
static int check_ioam6_data ( __u8 * * p , struct ioam6_trace_hdr * ioam6h ,
const struct ioam_config cnf )
2021-07-20 22:43:01 +03:00
{
2021-08-16 20:16:38 +03:00
unsigned int len ;
__u8 aligned ;
2021-07-20 22:43:01 +03:00
__u64 raw64 ;
__u32 raw32 ;
2021-08-16 20:16:38 +03:00
if ( ioam6h - > type . bit0 ) {
2021-07-20 22:43:01 +03:00
raw32 = __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ;
2021-08-16 20:16:38 +03:00
if ( cnf . hlim ! = ( raw32 > > 24 ) | | cnf . id ! = ( raw32 & 0xffffff ) )
2021-07-20 22:43:01 +03:00
return 1 ;
* p + = sizeof ( __u32 ) ;
}
2021-08-16 20:16:38 +03:00
if ( ioam6h - > type . bit1 ) {
2021-07-20 22:43:01 +03:00
raw32 = __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ;
2021-08-16 20:16:38 +03:00
if ( cnf . ingr_id ! = ( raw32 > > 16 ) | |
cnf . egr_id ! = ( raw32 & 0xffff ) )
2021-07-20 22:43:01 +03:00
return 1 ;
* p + = sizeof ( __u32 ) ;
}
2021-08-16 20:16:38 +03:00
if ( ioam6h - > type . bit2 )
2021-07-20 22:43:01 +03:00
* p + = sizeof ( __u32 ) ;
2021-08-16 20:16:38 +03:00
if ( ioam6h - > type . bit3 )
2021-07-20 22:43:01 +03:00
* p + = sizeof ( __u32 ) ;
2021-08-16 20:16:38 +03:00
if ( ioam6h - > type . bit4 ) {
2021-07-20 22:43:01 +03:00
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = 0xffffffff )
return 1 ;
* p + = sizeof ( __u32 ) ;
}
2021-08-16 20:16:38 +03:00
if ( ioam6h - > type . bit5 ) {
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = cnf . ns_data )
2021-07-20 22:43:01 +03:00
return 1 ;
* p + = sizeof ( __u32 ) ;
}
2022-01-21 20:34:49 +03:00
if ( ioam6h - > type . bit6 )
2021-07-20 22:43:01 +03:00
* p + = sizeof ( __u32 ) ;
2021-08-16 20:16:38 +03:00
if ( ioam6h - > type . bit7 ) {
2021-07-20 22:43:01 +03:00
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = 0xffffffff )
return 1 ;
* p + = sizeof ( __u32 ) ;
}
2021-08-16 20:16:38 +03:00
if ( ioam6h - > type . bit8 ) {
2021-07-20 22:43:01 +03:00
raw64 = __be64_to_cpu ( * ( ( __u64 * ) * p ) ) ;
2021-08-16 20:16:38 +03:00
if ( cnf . hlim ! = ( raw64 > > 56 ) | |
cnf . wide ! = ( raw64 & 0xffffffffffffff ) )
2021-07-20 22:43:01 +03:00
return 1 ;
* p + = sizeof ( __u64 ) ;
}
2021-08-16 20:16:38 +03:00
if ( ioam6h - > type . bit9 ) {
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = cnf . ingr_wide )
2021-07-20 22:43:01 +03:00
return 1 ;
* p + = sizeof ( __u32 ) ;
2021-08-16 20:16:38 +03:00
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = cnf . egr_wide )
2021-07-20 22:43:01 +03:00
return 1 ;
* p + = sizeof ( __u32 ) ;
}
2021-08-16 20:16:38 +03:00
if ( ioam6h - > type . bit10 ) {
if ( __be64_to_cpu ( * ( ( __u64 * ) * p ) ) ! = cnf . ns_wide )
2021-07-20 22:43:01 +03:00
return 1 ;
* p + = sizeof ( __u64 ) ;
}
2021-08-16 20:16:38 +03:00
if ( ioam6h - > type . bit11 ) {
2021-07-20 22:43:01 +03:00
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = 0xffffffff )
return 1 ;
* p + = sizeof ( __u32 ) ;
}
2021-10-11 21:04:12 +03:00
if ( ioam6h - > type . bit12 ) {
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = 0xffffffff )
return 1 ;
* p + = sizeof ( __u32 ) ;
}
if ( ioam6h - > type . bit13 ) {
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = 0xffffffff )
return 1 ;
* p + = sizeof ( __u32 ) ;
}
if ( ioam6h - > type . bit14 ) {
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = 0xffffffff )
return 1 ;
* p + = sizeof ( __u32 ) ;
}
if ( ioam6h - > type . bit15 ) {
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = 0xffffffff )
return 1 ;
* p + = sizeof ( __u32 ) ;
}
if ( ioam6h - > type . bit16 ) {
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = 0xffffffff )
return 1 ;
* p + = sizeof ( __u32 ) ;
}
if ( ioam6h - > type . bit17 ) {
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = 0xffffffff )
return 1 ;
* p + = sizeof ( __u32 ) ;
}
if ( ioam6h - > type . bit18 ) {
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = 0xffffffff )
return 1 ;
* p + = sizeof ( __u32 ) ;
}
if ( ioam6h - > type . bit19 ) {
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = 0xffffffff )
return 1 ;
* p + = sizeof ( __u32 ) ;
}
if ( ioam6h - > type . bit20 ) {
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = 0xffffffff )
return 1 ;
* p + = sizeof ( __u32 ) ;
}
if ( ioam6h - > type . bit21 ) {
if ( __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ! = 0xffffffff )
return 1 ;
* p + = sizeof ( __u32 ) ;
}
2021-08-16 20:16:38 +03:00
if ( ioam6h - > type . bit22 ) {
len = cnf . sc_data ? strlen ( cnf . sc_data ) : 0 ;
aligned = cnf . sc_data ? __ALIGN_KERNEL ( len , 4 ) : 0 ;
2021-07-20 22:43:01 +03:00
raw32 = __be32_to_cpu ( * ( ( __u32 * ) * p ) ) ;
2021-08-16 20:16:38 +03:00
if ( aligned ! = ( raw32 > > 24 ) * 4 | |
cnf . sc_id ! = ( raw32 & 0xffffff ) )
2021-07-20 22:43:01 +03:00
return 1 ;
* p + = sizeof ( __u32 ) ;
2021-08-16 20:16:38 +03:00
if ( cnf . sc_data ) {
if ( strncmp ( ( char * ) * p , cnf . sc_data , len ) )
2021-07-20 22:43:01 +03:00
return 1 ;
2021-08-16 20:16:38 +03:00
* p + = len ;
aligned - = len ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
while ( aligned - - ) {
2021-07-20 22:43:01 +03:00
if ( * * p ! = ' \0 ' )
return 1 ;
* p + = sizeof ( __u8 ) ;
}
}
}
return 0 ;
}
2021-08-16 20:16:38 +03:00
static int check_ioam_header_and_data ( int tid , struct ioam6_trace_hdr * ioam6h ,
__u32 trace_type , __u16 ioam_ns )
2021-07-20 22:43:01 +03:00
{
__u8 * p ;
2021-08-16 20:16:38 +03:00
if ( check_ioam_header ( tid , ioam6h , trace_type , ioam_ns ) )
2021-07-20 22:43:01 +03:00
return 1 ;
2021-08-16 20:16:38 +03:00
p = ioam6h - > data + ioam6h - > remlen * 4 ;
switch ( tid ) {
case TEST_OUT_BIT0 :
case TEST_OUT_BIT1 :
case TEST_OUT_BIT2 :
case TEST_OUT_BIT3 :
case TEST_OUT_BIT4 :
case TEST_OUT_BIT5 :
case TEST_OUT_BIT6 :
case TEST_OUT_BIT7 :
case TEST_OUT_BIT8 :
case TEST_OUT_BIT9 :
case TEST_OUT_BIT10 :
case TEST_OUT_BIT11 :
case TEST_OUT_BIT22 :
case TEST_OUT_FULL_SUPP_TRACE :
return check_ioam6_data ( & p , ioam6h , node1 ) ;
case TEST_IN_BIT0 :
case TEST_IN_BIT1 :
case TEST_IN_BIT2 :
case TEST_IN_BIT3 :
case TEST_IN_BIT4 :
case TEST_IN_BIT5 :
case TEST_IN_BIT6 :
case TEST_IN_BIT7 :
case TEST_IN_BIT8 :
case TEST_IN_BIT9 :
case TEST_IN_BIT10 :
case TEST_IN_BIT11 :
case TEST_IN_BIT22 :
case TEST_IN_FULL_SUPP_TRACE :
{
__u32 tmp32 = node2 . egr_wide ;
__u16 tmp16 = node2 . egr_id ;
int res ;
node2 . egr_id = 0xffff ;
node2 . egr_wide = 0xffffffff ;
res = check_ioam6_data ( & p , ioam6h , node2 ) ;
node2 . egr_id = tmp16 ;
node2 . egr_wide = tmp32 ;
return res ;
2021-07-20 22:43:01 +03:00
}
2021-08-16 20:16:38 +03:00
case TEST_FWD_FULL_SUPP_TRACE :
if ( check_ioam6_data ( & p , ioam6h , node3 ) )
2021-07-20 22:43:01 +03:00
return 1 ;
2021-08-16 20:16:38 +03:00
if ( check_ioam6_data ( & p , ioam6h , node2 ) )
2021-07-20 22:43:01 +03:00
return 1 ;
2021-08-16 20:16:38 +03:00
return check_ioam6_data ( & p , ioam6h , node1 ) ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
default :
break ;
2021-07-20 22:43:01 +03:00
}
2021-08-16 20:16:38 +03:00
return 1 ;
}
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
static int str2id ( const char * tname )
{
if ( ! strcmp ( " out_undef_ns " , tname ) )
return TEST_OUT_UNDEF_NS ;
if ( ! strcmp ( " out_no_room " , tname ) )
return TEST_OUT_NO_ROOM ;
if ( ! strcmp ( " out_bit0 " , tname ) )
return TEST_OUT_BIT0 ;
if ( ! strcmp ( " out_bit1 " , tname ) )
return TEST_OUT_BIT1 ;
if ( ! strcmp ( " out_bit2 " , tname ) )
return TEST_OUT_BIT2 ;
if ( ! strcmp ( " out_bit3 " , tname ) )
return TEST_OUT_BIT3 ;
if ( ! strcmp ( " out_bit4 " , tname ) )
return TEST_OUT_BIT4 ;
if ( ! strcmp ( " out_bit5 " , tname ) )
return TEST_OUT_BIT5 ;
if ( ! strcmp ( " out_bit6 " , tname ) )
return TEST_OUT_BIT6 ;
if ( ! strcmp ( " out_bit7 " , tname ) )
return TEST_OUT_BIT7 ;
if ( ! strcmp ( " out_bit8 " , tname ) )
return TEST_OUT_BIT8 ;
if ( ! strcmp ( " out_bit9 " , tname ) )
return TEST_OUT_BIT9 ;
if ( ! strcmp ( " out_bit10 " , tname ) )
return TEST_OUT_BIT10 ;
if ( ! strcmp ( " out_bit11 " , tname ) )
return TEST_OUT_BIT11 ;
if ( ! strcmp ( " out_bit22 " , tname ) )
return TEST_OUT_BIT22 ;
if ( ! strcmp ( " out_full_supp_trace " , tname ) )
return TEST_OUT_FULL_SUPP_TRACE ;
if ( ! strcmp ( " in_undef_ns " , tname ) )
return TEST_IN_UNDEF_NS ;
if ( ! strcmp ( " in_no_room " , tname ) )
return TEST_IN_NO_ROOM ;
if ( ! strcmp ( " in_oflag " , tname ) )
return TEST_IN_OFLAG ;
if ( ! strcmp ( " in_bit0 " , tname ) )
return TEST_IN_BIT0 ;
if ( ! strcmp ( " in_bit1 " , tname ) )
return TEST_IN_BIT1 ;
if ( ! strcmp ( " in_bit2 " , tname ) )
return TEST_IN_BIT2 ;
if ( ! strcmp ( " in_bit3 " , tname ) )
return TEST_IN_BIT3 ;
if ( ! strcmp ( " in_bit4 " , tname ) )
return TEST_IN_BIT4 ;
if ( ! strcmp ( " in_bit5 " , tname ) )
return TEST_IN_BIT5 ;
if ( ! strcmp ( " in_bit6 " , tname ) )
return TEST_IN_BIT6 ;
if ( ! strcmp ( " in_bit7 " , tname ) )
return TEST_IN_BIT7 ;
if ( ! strcmp ( " in_bit8 " , tname ) )
return TEST_IN_BIT8 ;
if ( ! strcmp ( " in_bit9 " , tname ) )
return TEST_IN_BIT9 ;
if ( ! strcmp ( " in_bit10 " , tname ) )
return TEST_IN_BIT10 ;
if ( ! strcmp ( " in_bit11 " , tname ) )
return TEST_IN_BIT11 ;
if ( ! strcmp ( " in_bit22 " , tname ) )
return TEST_IN_BIT22 ;
if ( ! strcmp ( " in_full_supp_trace " , tname ) )
return TEST_IN_FULL_SUPP_TRACE ;
if ( ! strcmp ( " fwd_full_supp_trace " , tname ) )
return TEST_FWD_FULL_SUPP_TRACE ;
return - 1 ;
}
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
static int ipv6_addr_equal ( const struct in6_addr * a1 , const struct in6_addr * a2 )
{
return ( ( a1 - > s6_addr32 [ 0 ] ^ a2 - > s6_addr32 [ 0 ] ) |
( a1 - > s6_addr32 [ 1 ] ^ a2 - > s6_addr32 [ 1 ] ) |
( a1 - > s6_addr32 [ 2 ] ^ a2 - > s6_addr32 [ 2 ] ) |
( a1 - > s6_addr32 [ 3 ] ^ a2 - > s6_addr32 [ 3 ] ) ) = = 0 ;
}
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
static int get_u32 ( __u32 * val , const char * arg , int base )
{
unsigned long res ;
char * ptr ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
if ( ! arg | | ! * arg )
return - 1 ;
res = strtoul ( arg , & ptr , base ) ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
if ( ! ptr | | ptr = = arg | | * ptr )
return - 1 ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
if ( res = = ULONG_MAX & & errno = = ERANGE )
return - 1 ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
if ( res > 0xFFFFFFFFUL )
return - 1 ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
* val = res ;
2021-07-20 22:43:01 +03:00
return 0 ;
}
2021-08-16 20:16:38 +03:00
static int get_u16 ( __u16 * val , const char * arg , int base )
2021-07-20 22:43:01 +03:00
{
2021-08-16 20:16:38 +03:00
unsigned long res ;
char * ptr ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
if ( ! arg | | ! * arg )
return - 1 ;
res = strtoul ( arg , & ptr , base ) ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
if ( ! ptr | | ptr = = arg | | * ptr )
return - 1 ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
if ( res = = ULONG_MAX & & errno = = ERANGE )
return - 1 ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
if ( res > 0xFFFFUL )
return - 1 ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
* val = res ;
return 0 ;
2021-07-20 22:43:01 +03:00
}
2021-08-16 20:16:38 +03:00
static int ( * func [ __TEST_MAX ] ) ( int , struct ioam6_trace_hdr * , __u32 , __u16 ) = {
[ TEST_OUT_UNDEF_NS ] = check_ioam_header ,
[ TEST_OUT_NO_ROOM ] = check_ioam_header ,
[ TEST_OUT_BIT0 ] = check_ioam_header_and_data ,
[ TEST_OUT_BIT1 ] = check_ioam_header_and_data ,
[ TEST_OUT_BIT2 ] = check_ioam_header_and_data ,
[ TEST_OUT_BIT3 ] = check_ioam_header_and_data ,
[ TEST_OUT_BIT4 ] = check_ioam_header_and_data ,
[ TEST_OUT_BIT5 ] = check_ioam_header_and_data ,
[ TEST_OUT_BIT6 ] = check_ioam_header_and_data ,
[ TEST_OUT_BIT7 ] = check_ioam_header_and_data ,
[ TEST_OUT_BIT8 ] = check_ioam_header_and_data ,
[ TEST_OUT_BIT9 ] = check_ioam_header_and_data ,
[ TEST_OUT_BIT10 ] = check_ioam_header_and_data ,
[ TEST_OUT_BIT11 ] = check_ioam_header_and_data ,
[ TEST_OUT_BIT22 ] = check_ioam_header_and_data ,
[ TEST_OUT_FULL_SUPP_TRACE ] = check_ioam_header_and_data ,
[ TEST_IN_UNDEF_NS ] = check_ioam_header ,
[ TEST_IN_NO_ROOM ] = check_ioam_header ,
[ TEST_IN_OFLAG ] = check_ioam_header ,
[ TEST_IN_BIT0 ] = check_ioam_header_and_data ,
[ TEST_IN_BIT1 ] = check_ioam_header_and_data ,
[ TEST_IN_BIT2 ] = check_ioam_header_and_data ,
[ TEST_IN_BIT3 ] = check_ioam_header_and_data ,
[ TEST_IN_BIT4 ] = check_ioam_header_and_data ,
[ TEST_IN_BIT5 ] = check_ioam_header_and_data ,
[ TEST_IN_BIT6 ] = check_ioam_header_and_data ,
[ TEST_IN_BIT7 ] = check_ioam_header_and_data ,
[ TEST_IN_BIT8 ] = check_ioam_header_and_data ,
[ TEST_IN_BIT9 ] = check_ioam_header_and_data ,
[ TEST_IN_BIT10 ] = check_ioam_header_and_data ,
[ TEST_IN_BIT11 ] = check_ioam_header_and_data ,
[ TEST_IN_BIT22 ] = check_ioam_header_and_data ,
[ TEST_IN_FULL_SUPP_TRACE ] = check_ioam_header_and_data ,
[ TEST_FWD_FULL_SUPP_TRACE ] = check_ioam_header_and_data ,
} ;
2021-07-20 22:43:01 +03:00
int main ( int argc , char * * argv )
{
2021-08-16 20:16:38 +03:00
int fd , size , hoplen , tid , ret = 1 ;
struct in6_addr src , dst ;
2021-07-20 22:43:01 +03:00
struct ioam6_hdr * opt ;
struct ipv6hdr * ip6h ;
__u8 buffer [ 400 ] , * p ;
2021-08-16 20:16:38 +03:00
__u16 ioam_ns ;
__u32 tr_type ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
if ( argc ! = 7 )
goto out ;
tid = str2id ( argv [ 2 ] ) ;
if ( tid < 0 | | ! func [ tid ] )
goto out ;
if ( inet_pton ( AF_INET6 , argv [ 3 ] , & src ) ! = 1 | |
inet_pton ( AF_INET6 , argv [ 4 ] , & dst ) ! = 1 )
goto out ;
if ( get_u32 ( & tr_type , argv [ 5 ] , 16 ) | |
get_u16 ( & ioam_ns , argv [ 6 ] , 0 ) )
2021-07-20 22:43:01 +03:00
goto out ;
fd = socket ( AF_PACKET , SOCK_DGRAM , __cpu_to_be16 ( ETH_P_IPV6 ) ) ;
2021-08-16 20:16:38 +03:00
if ( ! fd )
2021-07-20 22:43:01 +03:00
goto out ;
if ( setsockopt ( fd , SOL_SOCKET , SO_BINDTODEVICE ,
2021-08-16 20:16:38 +03:00
argv [ 1 ] , strlen ( argv [ 1 ] ) ) )
2021-07-20 22:43:01 +03:00
goto close ;
2021-08-16 20:16:38 +03:00
recv :
size = recv ( fd , buffer , sizeof ( buffer ) , 0 ) ;
if ( size < = 0 )
goto close ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
ip6h = ( struct ipv6hdr * ) buffer ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
if ( ! ipv6_addr_equal ( & ip6h - > saddr , & src ) | |
! ipv6_addr_equal ( & ip6h - > daddr , & dst ) )
goto recv ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
if ( ip6h - > nexthdr ! = IPPROTO_HOPOPTS )
goto close ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
p = buffer + sizeof ( * ip6h ) ;
hoplen = ( p [ 1 ] + 1 ) < < 3 ;
p + = sizeof ( struct ipv6_hopopt_hdr ) ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
while ( hoplen > 0 ) {
opt = ( struct ioam6_hdr * ) p ;
2021-07-20 22:43:01 +03:00
2021-08-16 20:16:38 +03:00
if ( opt - > opt_type = = IPV6_TLV_IOAM & &
opt - > type = = IOAM6_TYPE_PREALLOC ) {
p + = sizeof ( * opt ) ;
ret = func [ tid ] ( tid , ( struct ioam6_trace_hdr * ) p ,
tr_type , ioam_ns ) ;
break ;
2021-07-20 22:43:01 +03:00
}
2021-08-16 20:16:38 +03:00
p + = opt - > opt_len + 2 ;
hoplen - = opt - > opt_len + 2 ;
}
2021-07-20 22:43:01 +03:00
close :
close ( fd ) ;
out :
return ret ;
}