github.com/cilium/cilium@v1.16.2/bpf/tests/common.h (about)

     1  /* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
     2  /* Copyright Authors of Cilium */
     3  
     4  #pragma once
     5  
     6  #include <linux/types.h>
     7  #include <linux/bpf.h>
     8  #include <bpf/compiler.h>
     9  #include <bpf/loader.h>
    10  #include <bpf/section.h>
    11  
    12  /* We can use this macro inside the actual datapath code
    13   * to compile-in the code for testing. The primary usecase
    14   * is initializing map-in-map or prog-map.
    15   */
    16  #define BPF_TEST
    17  
    18  #ifndef ___bpf_concat
    19  #define ___bpf_concat(a, b) a ## b
    20  #endif
    21  #ifndef ___bpf_apply
    22  #define ___bpf_apply(fn, n) ___bpf_concat(fn, n)
    23  #endif
    24  #ifndef ___bpf_nth
    25  #define ___bpf_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _a, _b, _c, N, ...) N
    26  #endif
    27  #ifndef ___bpf_narg
    28  #define ___bpf_narg(...) \
    29  	___bpf_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
    30  #endif
    31  
    32  #define __bpf_log_arg0(ptr, arg) do {} while (0)
    33  #define __bpf_log_arg1(ptr, arg) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; ptr += sizeof(__u64)
    34  #define __bpf_log_arg2(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \
    35  					  ptr += sizeof(__u64); __bpf_log_arg1(ptr, args)
    36  #define __bpf_log_arg3(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \
    37  					  ptr += sizeof(__u64); __bpf_log_arg2(ptr, args)
    38  #define __bpf_log_arg4(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \
    39  					  ptr += sizeof(__u64); __bpf_log_arg3(ptr, args)
    40  #define __bpf_log_arg5(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \
    41  					  ptr += sizeof(__u64); __bpf_log_arg4(ptr, args)
    42  #define __bpf_log_arg6(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \
    43  					  ptr += sizeof(__u64); __bpf_log_arg5(ptr, args)
    44  #define __bpf_log_arg7(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \
    45  					  ptr += sizeof(__u64); __bpf_log_arg6(ptr, args)
    46  #define __bpf_log_arg8(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \
    47  					  ptr += sizeof(__u64); __bpf_log_arg7(ptr, args)
    48  #define __bpf_log_arg9(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \
    49  					  ptr += sizeof(__u64); __bpf_log_arg8(ptr, args)
    50  #define __bpf_log_arg10(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \
    51  					  ptr += sizeof(__u64); __bpf_log_arg9(ptr, args)
    52  #define __bpf_log_arg11(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \
    53  					  ptr += sizeof(__u64); __bpf_log_arg10(ptr, args)
    54  #define __bpf_log_arg12(ptr, arg, args...) *(ptr++) = MKR_LOG_ARG; *(__u64 *)(ptr) = arg; \
    55  					  ptr += sizeof(__u64); __bpf_log_arg11(ptr, args)
    56  #define __bpf_log_arg(ptr, args...) \
    57  	___bpf_apply(__bpf_log_arg, ___bpf_narg(args))(ptr, args)
    58  
    59  /* These values have to stay in sync with the enum */
    60  /* values in bpf/tests/bpftest/trf.proto */
    61  #define TEST_ERROR 0
    62  #define TEST_PASS 1
    63  #define TEST_FAIL 2
    64  #define TEST_SKIP 3
    65  
    66  /* Max number of cpus to check when doing percpu hash assertions */
    67  #define NR_CPUS 128
    68  
    69  /* Use an array map with 1 key and a large value size as buffer to write results */
    70  /* into. */
    71  struct {
    72  	__uint(type, BPF_MAP_TYPE_ARRAY);
    73  	__uint(key_size, sizeof(__u32));
    74  	__uint(value_size, 8192);
    75  	__uint(pinning, LIBBPF_PIN_BY_NAME);
    76  	__uint(max_entries, 1);
    77  } suite_result_map __section_maps_btf;
    78  
    79  /* Values for the markers below are derived from this guide: */
    80  /* https://developers.google.com/protocol-buffers/docs/encoding#structure */
    81  
    82  #define PROTOBUF_WIRE_TYPE(field, type) ((field) << 3 | (type))
    83  
    84  #define PROTOBUF_VARINT 0
    85  #define PROTOBUF_FIXED64 1
    86  #define PROTOBUF_LENGTH_DELIMITED 2
    87  
    88  /* message SuiteResult */
    89  #define MKR_TEST_RESULT PROTOBUF_WIRE_TYPE(1, PROTOBUF_LENGTH_DELIMITED)
    90  #define MKR_SUITE_LOG	PROTOBUF_WIRE_TYPE(2, PROTOBUF_LENGTH_DELIMITED)
    91  
    92  /* message TestResult */
    93  #define MKR_TEST_NAME	PROTOBUF_WIRE_TYPE(1, PROTOBUF_LENGTH_DELIMITED)
    94  #define MKR_TEST_STATUS PROTOBUF_WIRE_TYPE(2, PROTOBUF_VARINT)
    95  #define MKR_TEST_LOG	PROTOBUF_WIRE_TYPE(3, PROTOBUF_LENGTH_DELIMITED)
    96  
    97  /* message Log */
    98  #define MKR_LOG_FMT	PROTOBUF_WIRE_TYPE(1, PROTOBUF_LENGTH_DELIMITED)
    99  #define MKR_LOG_ARG	PROTOBUF_WIRE_TYPE(2, PROTOBUF_FIXED64)
   100  
   101  /* Write a message to the unit log
   102   *	The conversion specifiers supported by *fmt* are the same as for
   103   *      bpf_trace_printk(). They are **%d**, **%i**, **%u**, **%x**, **%ld**,
   104   *      **%li**, **%lu**, **%lx**, **%lld**, **%lli**, **%llu**, **%llx**,
   105   *      **%p**. No modifier (size of field, padding with zeroes, etc.)
   106   *      is available
   107   */
   108  #define test_log(fmt, args...)						\
   109  ({									\
   110  	static const char ____fmt[] = fmt;				\
   111  	if (test_result_cursor) {					\
   112  		*(suite_result_cursor++) = MKR_TEST_LOG;		\
   113  	} else {							\
   114  		*(suite_result_cursor++) = MKR_SUITE_LOG;		\
   115  	}								\
   116  	*(suite_result_cursor++) = 2 + sizeof(____fmt) +		\
   117  		___bpf_narg(args) +					\
   118  		(___bpf_narg(args) * sizeof(unsigned long long));	\
   119  	*(suite_result_cursor++) = MKR_LOG_FMT;			\
   120  	*(suite_result_cursor++) = sizeof(____fmt);			\
   121  	memcpy(suite_result_cursor, ____fmt, sizeof(____fmt));		\
   122  	suite_result_cursor += sizeof(____fmt);			\
   123  									\
   124  									\
   125  	if (___bpf_narg(args) > 0) {					\
   126  		__bpf_log_arg(suite_result_cursor, args);		\
   127  	}								\
   128  })
   129  
   130  /* This is a hack to allow us to convert the integer produced by __LINE__ */
   131  /* to a string so we can concat it at compile time. */
   132  #define STRINGIZE(x) STRINGIZE2(x)
   133  #define STRINGIZE2(x) #x
   134  #define LINE_STRING STRINGIZE(__LINE__)
   135  
   136  /* Mark the current test as failed */
   137  #define test_fail()				\
   138  	if (test_result_cursor) {		\
   139  		*test_result_status = TEST_FAIL;\
   140  	} else {				\
   141  		suite_result = TEST_FAIL;	\
   142  	}					\
   143  
   144  /* Mark the current test as failed and exit the current TEST/CHECK */
   145  #define test_fail_now()				\
   146  	if (test_result_cursor) {		\
   147  		*test_result_status = TEST_FAIL;\
   148  		break;				\
   149  	} else {				\
   150  		return TEST_FAIL;		\
   151  	}
   152  
   153  /* Mark the current test as skipped */
   154  #define test_skip()				\
   155  	if (test_result_cursor) {		\
   156  		*test_result_status = TEST_SKIP;\
   157  	} else {				\
   158  		suite_result = TEST_SKIP;	\
   159  	}
   160  
   161  /* Mark the current test as skipped and exit the current TEST/CHECK */
   162  #define test_skip_now()					\
   163  	if (test_result_cursor) {			\
   164  		*test_result_status = TEST_SKIP;	\
   165  		break;					\
   166  	} else {					\
   167  		return TEST_SKIP;			\
   168  	}
   169  
   170  /* Write message to the log and mark current test as failed. */
   171  #define test_error(fmt, ...)			\
   172  	{					\
   173  		test_log(fmt, ##__VA_ARGS__);	\
   174  		test_fail();			\
   175  	}
   176  
   177  /* Log a message bpf_then fail_now */
   178  #define test_fatal(fmt, ...)			\
   179  	{					\
   180  		test_log(fmt, ##__VA_ARGS__);	\
   181  		test_fail_now()			\
   182  	}
   183  
   184  /* Assert that `cond` is true, fail the rest otherwise */
   185  #define assert(cond)							\
   186  	if (!(cond)) {							\
   187  		test_log("assert failed at " __FILE__ ":" LINE_STRING);	\
   188  		test_fail_now();					\
   189  	}
   190  
   191  /* Declare bpf_map_lookup_elem with the test_ prefix to avoid conflicts in the */
   192  /* future. */
   193  static void *(*test_bpf_map_lookup_elem)(void *map, const void *key) = (void *)1;
   194  
   195  /* Init sets up a number of variables which will be used by other macros. */
   196  /* - suite_result will be returned from the eBPF program */
   197  /* - test_result_status is a pointer into the suite_result_map when in a test */
   198  /* - suite_result_cursor keeps track of where in the suite result we are. */
   199  /* - test_result_cursor is a pointer to the varint of a test result, used to */
   200  /*   write the amount of bytes used after a test is done. */
   201  #define test_init()							  \
   202  	char suite_result = TEST_PASS;					  \
   203  	__maybe_unused char *test_result_status = 0;			  \
   204  	char *suite_result_cursor;					  \
   205  	{								  \
   206  		__u32 __key = 0;						  \
   207  		suite_result_cursor =					  \
   208  			test_bpf_map_lookup_elem(&suite_result_map, &__key);\
   209  		if (!suite_result_cursor) {				  \
   210  			return TEST_ERROR;				  \
   211  		}							  \
   212  	}								  \
   213  	__maybe_unused char *test_result_cursor = 0;			  \
   214  	__maybe_unused __u16 test_result_size;				  \
   215  	do {
   216  /* */
   217  /* Each test is single iteration do-while loop so we can break, to exit the */
   218  /* test without unique label names and goto's */
   219  #define TEST(name, body)						   \
   220  do {									   \
   221  	*(suite_result_cursor++) = MKR_TEST_RESULT;			   \
   222  	/* test_result_cursor will stay at test result length varint */    \
   223  	test_result_cursor = suite_result_cursor;			   \
   224  	/* Reserve 2 bytes for the varint indicating test result length */ \
   225  	suite_result_cursor += 2;					   \
   226  									   \
   227  	static const char ____name[] = name;				   \
   228  	*(suite_result_cursor++) = MKR_TEST_NAME;			   \
   229  	*(suite_result_cursor++) = sizeof(____name);			   \
   230  	memcpy(suite_result_cursor, ____name, sizeof(____name));	   \
   231  	suite_result_cursor += sizeof(____name);			   \
   232  									   \
   233  	*(suite_result_cursor++) = MKR_TEST_STATUS;			   \
   234  	test_result_status = suite_result_cursor;			   \
   235  									   \
   236  	*test_result_status = TEST_PASS;				   \
   237  	suite_result_cursor++;						   \
   238  									   \
   239  	body								   \
   240  } while (0);								   \
   241  /* Write the total size of the test result in bytes as varint */	   \
   242  test_result_size = (__u16)((long)suite_result_cursor -			   \
   243  	(long)test_result_cursor) - 2;					   \
   244  if (test_result_size > 127) {						   \
   245  	*(test_result_cursor) = (__u8)(test_result_size & 0b01111111) |	   \
   246  		0b10000000;						   \
   247  	test_result_size >>= 7;						   \
   248  	*(test_result_cursor + 1) = (__u8)test_result_size;		   \
   249  } else {								   \
   250  	*test_result_cursor = (__u8)(test_result_size) | 0b10000000;	   \
   251  }									   \
   252  test_result_cursor = 0;
   253  
   254  #define test_finish()		\
   255  	} while (0);		\
   256  	return suite_result
   257  
   258  #define PKTGEN(progtype, name) __section(progtype "/test/" name "/pktgen")
   259  #define SETUP(progtype, name) __section(progtype "/test/" name "/setup")
   260  #define CHECK(progtype, name) __section(progtype "/test/" name "/check")
   261  
   262  /* Asserts that the sum of per-cpu metrics map slots for a key equals count */
   263  #define assert_metrics_count(key, count) \
   264  ({ \
   265  	struct metrics_value *__entry = NULL; \
   266  	__u64 sum = 0; \
   267  	/* Iterate until lookup encounters null when hitting cpu number */ \
   268  	/* Assumes at most 128 CPUS */ \
   269  	for (int i = 0; i < NR_CPUS; i++) { \
   270  		__entry = map_lookup_percpu_elem(&METRICS_MAP, &key, i); \
   271  		if (!__entry) { \
   272  			break; \
   273  		} \
   274  		sum += __entry->count; \
   275  	} \
   276  	assert(sum == count); \
   277  })