mirror of https://gitee.com/openkylin/linux.git
Merge branch 'bpf-int128-btf'
Yonghong Song says: ==================== Previous maximum supported integer bit width is 64. But the __int128 type has been supported by most (if not all) 64bit architectures including bpf for both gcc and clang. The kernel itself uses __int128 for x64 and arm64. Some bcc tools are using __int128 in bpf programs to describe ipv6 addresses. Without 128bit int support, the vmlinux BTF won't work and those bpf programs using __int128 cannot utilize BTF. This patch set therefore implements BTF __int128 support. ==================== Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
commit
e13279e211
104
kernel/bpf/btf.c
104
kernel/bpf/btf.c
|
@ -157,7 +157,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define BITS_PER_U64 (sizeof(u64) * BITS_PER_BYTE)
|
#define BITS_PER_U128 (sizeof(u64) * BITS_PER_BYTE * 2)
|
||||||
#define BITS_PER_BYTE_MASK (BITS_PER_BYTE - 1)
|
#define BITS_PER_BYTE_MASK (BITS_PER_BYTE - 1)
|
||||||
#define BITS_PER_BYTE_MASKED(bits) ((bits) & BITS_PER_BYTE_MASK)
|
#define BITS_PER_BYTE_MASKED(bits) ((bits) & BITS_PER_BYTE_MASK)
|
||||||
#define BITS_ROUNDDOWN_BYTES(bits) ((bits) >> 3)
|
#define BITS_ROUNDDOWN_BYTES(bits) ((bits) >> 3)
|
||||||
|
@ -525,7 +525,7 @@ const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Regular int is not a bit field and it must be either
|
* Regular int is not a bit field and it must be either
|
||||||
* u8/u16/u32/u64.
|
* u8/u16/u32/u64 or __int128.
|
||||||
*/
|
*/
|
||||||
static bool btf_type_int_is_regular(const struct btf_type *t)
|
static bool btf_type_int_is_regular(const struct btf_type *t)
|
||||||
{
|
{
|
||||||
|
@ -538,7 +538,8 @@ static bool btf_type_int_is_regular(const struct btf_type *t)
|
||||||
if (BITS_PER_BYTE_MASKED(nr_bits) ||
|
if (BITS_PER_BYTE_MASKED(nr_bits) ||
|
||||||
BTF_INT_OFFSET(int_data) ||
|
BTF_INT_OFFSET(int_data) ||
|
||||||
(nr_bytes != sizeof(u8) && nr_bytes != sizeof(u16) &&
|
(nr_bytes != sizeof(u8) && nr_bytes != sizeof(u16) &&
|
||||||
nr_bytes != sizeof(u32) && nr_bytes != sizeof(u64))) {
|
nr_bytes != sizeof(u32) && nr_bytes != sizeof(u64) &&
|
||||||
|
nr_bytes != (2 * sizeof(u64)))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1063,9 +1064,9 @@ static int btf_int_check_member(struct btf_verifier_env *env,
|
||||||
nr_copy_bits = BTF_INT_BITS(int_data) +
|
nr_copy_bits = BTF_INT_BITS(int_data) +
|
||||||
BITS_PER_BYTE_MASKED(struct_bits_off);
|
BITS_PER_BYTE_MASKED(struct_bits_off);
|
||||||
|
|
||||||
if (nr_copy_bits > BITS_PER_U64) {
|
if (nr_copy_bits > BITS_PER_U128) {
|
||||||
btf_verifier_log_member(env, struct_type, member,
|
btf_verifier_log_member(env, struct_type, member,
|
||||||
"nr_copy_bits exceeds 64");
|
"nr_copy_bits exceeds 128");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1119,9 +1120,9 @@ static int btf_int_check_kflag_member(struct btf_verifier_env *env,
|
||||||
|
|
||||||
bytes_offset = BITS_ROUNDDOWN_BYTES(struct_bits_off);
|
bytes_offset = BITS_ROUNDDOWN_BYTES(struct_bits_off);
|
||||||
nr_copy_bits = nr_bits + BITS_PER_BYTE_MASKED(struct_bits_off);
|
nr_copy_bits = nr_bits + BITS_PER_BYTE_MASKED(struct_bits_off);
|
||||||
if (nr_copy_bits > BITS_PER_U64) {
|
if (nr_copy_bits > BITS_PER_U128) {
|
||||||
btf_verifier_log_member(env, struct_type, member,
|
btf_verifier_log_member(env, struct_type, member,
|
||||||
"nr_copy_bits exceeds 64");
|
"nr_copy_bits exceeds 128");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1168,9 +1169,9 @@ static s32 btf_int_check_meta(struct btf_verifier_env *env,
|
||||||
|
|
||||||
nr_bits = BTF_INT_BITS(int_data) + BTF_INT_OFFSET(int_data);
|
nr_bits = BTF_INT_BITS(int_data) + BTF_INT_OFFSET(int_data);
|
||||||
|
|
||||||
if (nr_bits > BITS_PER_U64) {
|
if (nr_bits > BITS_PER_U128) {
|
||||||
btf_verifier_log_type(env, t, "nr_bits exceeds %zu",
|
btf_verifier_log_type(env, t, "nr_bits exceeds %zu",
|
||||||
BITS_PER_U64);
|
BITS_PER_U128);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1211,31 +1212,93 @@ static void btf_int_log(struct btf_verifier_env *env,
|
||||||
btf_int_encoding_str(BTF_INT_ENCODING(int_data)));
|
btf_int_encoding_str(BTF_INT_ENCODING(int_data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void btf_int128_print(struct seq_file *m, void *data)
|
||||||
|
{
|
||||||
|
/* data points to a __int128 number.
|
||||||
|
* Suppose
|
||||||
|
* int128_num = *(__int128 *)data;
|
||||||
|
* The below formulas shows what upper_num and lower_num represents:
|
||||||
|
* upper_num = int128_num >> 64;
|
||||||
|
* lower_num = int128_num & 0xffffffffFFFFFFFFULL;
|
||||||
|
*/
|
||||||
|
u64 upper_num, lower_num;
|
||||||
|
|
||||||
|
#ifdef __BIG_ENDIAN_BITFIELD
|
||||||
|
upper_num = *(u64 *)data;
|
||||||
|
lower_num = *(u64 *)(data + 8);
|
||||||
|
#else
|
||||||
|
upper_num = *(u64 *)(data + 8);
|
||||||
|
lower_num = *(u64 *)data;
|
||||||
|
#endif
|
||||||
|
if (upper_num == 0)
|
||||||
|
seq_printf(m, "0x%llx", lower_num);
|
||||||
|
else
|
||||||
|
seq_printf(m, "0x%llx%016llx", upper_num, lower_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void btf_int128_shift(u64 *print_num, u16 left_shift_bits,
|
||||||
|
u16 right_shift_bits)
|
||||||
|
{
|
||||||
|
u64 upper_num, lower_num;
|
||||||
|
|
||||||
|
#ifdef __BIG_ENDIAN_BITFIELD
|
||||||
|
upper_num = print_num[0];
|
||||||
|
lower_num = print_num[1];
|
||||||
|
#else
|
||||||
|
upper_num = print_num[1];
|
||||||
|
lower_num = print_num[0];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* shake out un-needed bits by shift/or operations */
|
||||||
|
if (left_shift_bits >= 64) {
|
||||||
|
upper_num = lower_num << (left_shift_bits - 64);
|
||||||
|
lower_num = 0;
|
||||||
|
} else {
|
||||||
|
upper_num = (upper_num << left_shift_bits) |
|
||||||
|
(lower_num >> (64 - left_shift_bits));
|
||||||
|
lower_num = lower_num << left_shift_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (right_shift_bits >= 64) {
|
||||||
|
lower_num = upper_num >> (right_shift_bits - 64);
|
||||||
|
upper_num = 0;
|
||||||
|
} else {
|
||||||
|
lower_num = (lower_num >> right_shift_bits) |
|
||||||
|
(upper_num << (64 - right_shift_bits));
|
||||||
|
upper_num = upper_num >> right_shift_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __BIG_ENDIAN_BITFIELD
|
||||||
|
print_num[0] = upper_num;
|
||||||
|
print_num[1] = lower_num;
|
||||||
|
#else
|
||||||
|
print_num[0] = lower_num;
|
||||||
|
print_num[1] = upper_num;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void btf_bitfield_seq_show(void *data, u8 bits_offset,
|
static void btf_bitfield_seq_show(void *data, u8 bits_offset,
|
||||||
u8 nr_bits, struct seq_file *m)
|
u8 nr_bits, struct seq_file *m)
|
||||||
{
|
{
|
||||||
u16 left_shift_bits, right_shift_bits;
|
u16 left_shift_bits, right_shift_bits;
|
||||||
u8 nr_copy_bytes;
|
u8 nr_copy_bytes;
|
||||||
u8 nr_copy_bits;
|
u8 nr_copy_bits;
|
||||||
u64 print_num;
|
u64 print_num[2] = {};
|
||||||
|
|
||||||
nr_copy_bits = nr_bits + bits_offset;
|
nr_copy_bits = nr_bits + bits_offset;
|
||||||
nr_copy_bytes = BITS_ROUNDUP_BYTES(nr_copy_bits);
|
nr_copy_bytes = BITS_ROUNDUP_BYTES(nr_copy_bits);
|
||||||
|
|
||||||
print_num = 0;
|
memcpy(print_num, data, nr_copy_bytes);
|
||||||
memcpy(&print_num, data, nr_copy_bytes);
|
|
||||||
|
|
||||||
#ifdef __BIG_ENDIAN_BITFIELD
|
#ifdef __BIG_ENDIAN_BITFIELD
|
||||||
left_shift_bits = bits_offset;
|
left_shift_bits = bits_offset;
|
||||||
#else
|
#else
|
||||||
left_shift_bits = BITS_PER_U64 - nr_copy_bits;
|
left_shift_bits = BITS_PER_U128 - nr_copy_bits;
|
||||||
#endif
|
#endif
|
||||||
right_shift_bits = BITS_PER_U64 - nr_bits;
|
right_shift_bits = BITS_PER_U128 - nr_bits;
|
||||||
|
|
||||||
print_num <<= left_shift_bits;
|
btf_int128_shift(print_num, left_shift_bits, right_shift_bits);
|
||||||
print_num >>= right_shift_bits;
|
btf_int128_print(m, print_num);
|
||||||
|
|
||||||
seq_printf(m, "0x%llx", print_num);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1250,7 +1313,7 @@ static void btf_int_bits_seq_show(const struct btf *btf,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* bits_offset is at most 7.
|
* bits_offset is at most 7.
|
||||||
* BTF_INT_OFFSET() cannot exceed 64 bits.
|
* BTF_INT_OFFSET() cannot exceed 128 bits.
|
||||||
*/
|
*/
|
||||||
total_bits_offset = bits_offset + BTF_INT_OFFSET(int_data);
|
total_bits_offset = bits_offset + BTF_INT_OFFSET(int_data);
|
||||||
data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
|
data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
|
||||||
|
@ -1274,6 +1337,9 @@ static void btf_int_seq_show(const struct btf *btf, const struct btf_type *t,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (nr_bits) {
|
switch (nr_bits) {
|
||||||
|
case 128:
|
||||||
|
btf_int128_print(m, data);
|
||||||
|
break;
|
||||||
case 64:
|
case 64:
|
||||||
if (sign)
|
if (sign)
|
||||||
seq_printf(m, "%lld", *(s64 *)data);
|
seq_printf(m, "%lld", *(s64 *)data);
|
||||||
|
|
|
@ -73,35 +73,104 @@ static int btf_dumper_array(const struct btf_dumper *d, __u32 type_id,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void btf_int128_print(json_writer_t *jw, const void *data,
|
||||||
|
bool is_plain_text)
|
||||||
|
{
|
||||||
|
/* data points to a __int128 number.
|
||||||
|
* Suppose
|
||||||
|
* int128_num = *(__int128 *)data;
|
||||||
|
* The below formulas shows what upper_num and lower_num represents:
|
||||||
|
* upper_num = int128_num >> 64;
|
||||||
|
* lower_num = int128_num & 0xffffffffFFFFFFFFULL;
|
||||||
|
*/
|
||||||
|
__u64 upper_num, lower_num;
|
||||||
|
|
||||||
|
#ifdef __BIG_ENDIAN_BITFIELD
|
||||||
|
upper_num = *(__u64 *)data;
|
||||||
|
lower_num = *(__u64 *)(data + 8);
|
||||||
|
#else
|
||||||
|
upper_num = *(__u64 *)(data + 8);
|
||||||
|
lower_num = *(__u64 *)data;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (is_plain_text) {
|
||||||
|
if (upper_num == 0)
|
||||||
|
jsonw_printf(jw, "0x%llx", lower_num);
|
||||||
|
else
|
||||||
|
jsonw_printf(jw, "0x%llx%016llx", upper_num, lower_num);
|
||||||
|
} else {
|
||||||
|
if (upper_num == 0)
|
||||||
|
jsonw_printf(jw, "\"0x%llx\"", lower_num);
|
||||||
|
else
|
||||||
|
jsonw_printf(jw, "\"0x%llx%016llx\"", upper_num, lower_num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void btf_int128_shift(__u64 *print_num, u16 left_shift_bits,
|
||||||
|
u16 right_shift_bits)
|
||||||
|
{
|
||||||
|
__u64 upper_num, lower_num;
|
||||||
|
|
||||||
|
#ifdef __BIG_ENDIAN_BITFIELD
|
||||||
|
upper_num = print_num[0];
|
||||||
|
lower_num = print_num[1];
|
||||||
|
#else
|
||||||
|
upper_num = print_num[1];
|
||||||
|
lower_num = print_num[0];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* shake out un-needed bits by shift/or operations */
|
||||||
|
if (left_shift_bits >= 64) {
|
||||||
|
upper_num = lower_num << (left_shift_bits - 64);
|
||||||
|
lower_num = 0;
|
||||||
|
} else {
|
||||||
|
upper_num = (upper_num << left_shift_bits) |
|
||||||
|
(lower_num >> (64 - left_shift_bits));
|
||||||
|
lower_num = lower_num << left_shift_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (right_shift_bits >= 64) {
|
||||||
|
lower_num = upper_num >> (right_shift_bits - 64);
|
||||||
|
upper_num = 0;
|
||||||
|
} else {
|
||||||
|
lower_num = (lower_num >> right_shift_bits) |
|
||||||
|
(upper_num << (64 - right_shift_bits));
|
||||||
|
upper_num = upper_num >> right_shift_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __BIG_ENDIAN_BITFIELD
|
||||||
|
print_num[0] = upper_num;
|
||||||
|
print_num[1] = lower_num;
|
||||||
|
#else
|
||||||
|
print_num[0] = lower_num;
|
||||||
|
print_num[1] = upper_num;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void btf_dumper_bitfield(__u32 nr_bits, __u8 bit_offset,
|
static void btf_dumper_bitfield(__u32 nr_bits, __u8 bit_offset,
|
||||||
const void *data, json_writer_t *jw,
|
const void *data, json_writer_t *jw,
|
||||||
bool is_plain_text)
|
bool is_plain_text)
|
||||||
{
|
{
|
||||||
int left_shift_bits, right_shift_bits;
|
int left_shift_bits, right_shift_bits;
|
||||||
|
__u64 print_num[2] = {};
|
||||||
int bytes_to_copy;
|
int bytes_to_copy;
|
||||||
int bits_to_copy;
|
int bits_to_copy;
|
||||||
__u64 print_num;
|
|
||||||
|
|
||||||
bits_to_copy = bit_offset + nr_bits;
|
bits_to_copy = bit_offset + nr_bits;
|
||||||
bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy);
|
bytes_to_copy = BITS_ROUNDUP_BYTES(bits_to_copy);
|
||||||
|
|
||||||
print_num = 0;
|
memcpy(print_num, data, bytes_to_copy);
|
||||||
memcpy(&print_num, data, bytes_to_copy);
|
|
||||||
#if defined(__BIG_ENDIAN_BITFIELD)
|
#if defined(__BIG_ENDIAN_BITFIELD)
|
||||||
left_shift_bits = bit_offset;
|
left_shift_bits = bit_offset;
|
||||||
#elif defined(__LITTLE_ENDIAN_BITFIELD)
|
#elif defined(__LITTLE_ENDIAN_BITFIELD)
|
||||||
left_shift_bits = 64 - bits_to_copy;
|
left_shift_bits = 128 - bits_to_copy;
|
||||||
#else
|
#else
|
||||||
#error neither big nor little endian
|
#error neither big nor little endian
|
||||||
#endif
|
#endif
|
||||||
right_shift_bits = 64 - nr_bits;
|
right_shift_bits = 128 - nr_bits;
|
||||||
|
|
||||||
print_num <<= left_shift_bits;
|
btf_int128_shift(print_num, left_shift_bits, right_shift_bits);
|
||||||
print_num >>= right_shift_bits;
|
btf_int128_print(jw, print_num, is_plain_text);
|
||||||
if (is_plain_text)
|
|
||||||
jsonw_printf(jw, "0x%llx", print_num);
|
|
||||||
else
|
|
||||||
jsonw_printf(jw, "%llu", print_num);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,7 +182,7 @@ static void btf_dumper_int_bits(__u32 int_type, __u8 bit_offset,
|
||||||
int total_bits_offset;
|
int total_bits_offset;
|
||||||
|
|
||||||
/* bits_offset is at most 7.
|
/* bits_offset is at most 7.
|
||||||
* BTF_INT_OFFSET() cannot exceed 64 bits.
|
* BTF_INT_OFFSET() cannot exceed 128 bits.
|
||||||
*/
|
*/
|
||||||
total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type);
|
total_bits_offset = bit_offset + BTF_INT_OFFSET(int_type);
|
||||||
data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
|
data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
|
||||||
|
@ -139,6 +208,11 @@ static int btf_dumper_int(const struct btf_type *t, __u8 bit_offset,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nr_bits == 128) {
|
||||||
|
btf_int128_print(jw, data, is_plain_text);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
switch (BTF_INT_ENCODING(*int_type)) {
|
switch (BTF_INT_ENCODING(*int_type)) {
|
||||||
case 0:
|
case 0:
|
||||||
if (BTF_INT_BITS(*int_type) == 64)
|
if (BTF_INT_BITS(*int_type) == 64)
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <bpf/libbpf.h>
|
#include <bpf/libbpf.h>
|
||||||
#include <bpf/btf.h>
|
#include <bpf/btf.h>
|
||||||
|
|
||||||
|
@ -134,6 +135,12 @@ static struct btf_header hdr_tmpl = {
|
||||||
.hdr_len = sizeof(struct btf_header),
|
.hdr_len = sizeof(struct btf_header),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* several different mapv kinds(types) supported by pprint */
|
||||||
|
enum pprint_mapv_kind_t {
|
||||||
|
PPRINT_MAPV_KIND_BASIC = 0,
|
||||||
|
PPRINT_MAPV_KIND_INT128,
|
||||||
|
};
|
||||||
|
|
||||||
struct btf_raw_test {
|
struct btf_raw_test {
|
||||||
const char *descr;
|
const char *descr;
|
||||||
const char *str_sec;
|
const char *str_sec;
|
||||||
|
@ -156,6 +163,7 @@ struct btf_raw_test {
|
||||||
int type_off_delta;
|
int type_off_delta;
|
||||||
int str_off_delta;
|
int str_off_delta;
|
||||||
int str_len_delta;
|
int str_len_delta;
|
||||||
|
enum pprint_mapv_kind_t mapv_kind;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BTF_STR_SEC(str) \
|
#define BTF_STR_SEC(str) \
|
||||||
|
@ -2707,6 +2715,99 @@ static struct btf_raw_test raw_tests[] = {
|
||||||
.err_str = "Invalid member offset",
|
.err_str = "Invalid member offset",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.descr = "128-bit int",
|
||||||
|
.raw_types = {
|
||||||
|
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||||
|
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 128, 16), /* [2] */
|
||||||
|
BTF_END_RAW,
|
||||||
|
},
|
||||||
|
BTF_STR_SEC("\0A"),
|
||||||
|
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||||
|
.map_name = "int_type_check_btf",
|
||||||
|
.key_size = sizeof(int),
|
||||||
|
.value_size = sizeof(int),
|
||||||
|
.key_type_id = 1,
|
||||||
|
.value_type_id = 1,
|
||||||
|
.max_entries = 4,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.descr = "struct, 128-bit int member",
|
||||||
|
.raw_types = {
|
||||||
|
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||||
|
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 128, 16), /* [2] */
|
||||||
|
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), 16), /* [3] */
|
||||||
|
BTF_MEMBER_ENC(NAME_TBD, 2, 0),
|
||||||
|
BTF_END_RAW,
|
||||||
|
},
|
||||||
|
BTF_STR_SEC("\0A"),
|
||||||
|
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||||
|
.map_name = "struct_type_check_btf",
|
||||||
|
.key_size = sizeof(int),
|
||||||
|
.value_size = sizeof(int),
|
||||||
|
.key_type_id = 1,
|
||||||
|
.value_type_id = 1,
|
||||||
|
.max_entries = 4,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.descr = "struct, 120-bit int member bitfield",
|
||||||
|
.raw_types = {
|
||||||
|
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||||
|
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 120, 16), /* [2] */
|
||||||
|
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), 16), /* [3] */
|
||||||
|
BTF_MEMBER_ENC(NAME_TBD, 2, 0),
|
||||||
|
BTF_END_RAW,
|
||||||
|
},
|
||||||
|
BTF_STR_SEC("\0A"),
|
||||||
|
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||||
|
.map_name = "struct_type_check_btf",
|
||||||
|
.key_size = sizeof(int),
|
||||||
|
.value_size = sizeof(int),
|
||||||
|
.key_type_id = 1,
|
||||||
|
.value_type_id = 1,
|
||||||
|
.max_entries = 4,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.descr = "struct, kind_flag, 128-bit int member",
|
||||||
|
.raw_types = {
|
||||||
|
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||||
|
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 128, 16), /* [2] */
|
||||||
|
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 1), 16), /* [3] */
|
||||||
|
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(0, 0)),
|
||||||
|
BTF_END_RAW,
|
||||||
|
},
|
||||||
|
BTF_STR_SEC("\0A"),
|
||||||
|
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||||
|
.map_name = "struct_type_check_btf",
|
||||||
|
.key_size = sizeof(int),
|
||||||
|
.value_size = sizeof(int),
|
||||||
|
.key_type_id = 1,
|
||||||
|
.value_type_id = 1,
|
||||||
|
.max_entries = 4,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.descr = "struct, kind_flag, 120-bit int member bitfield",
|
||||||
|
.raw_types = {
|
||||||
|
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
|
||||||
|
BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 128, 16), /* [2] */
|
||||||
|
BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 1), 16), /* [3] */
|
||||||
|
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(120, 0)),
|
||||||
|
BTF_END_RAW,
|
||||||
|
},
|
||||||
|
BTF_STR_SEC("\0A"),
|
||||||
|
.map_type = BPF_MAP_TYPE_ARRAY,
|
||||||
|
.map_name = "struct_type_check_btf",
|
||||||
|
.key_size = sizeof(int),
|
||||||
|
.value_size = sizeof(int),
|
||||||
|
.key_type_id = 1,
|
||||||
|
.value_type_id = 1,
|
||||||
|
.max_entries = 4,
|
||||||
|
},
|
||||||
|
|
||||||
}; /* struct btf_raw_test raw_tests[] */
|
}; /* struct btf_raw_test raw_tests[] */
|
||||||
|
|
||||||
static const char *get_next_str(const char *start, const char *end)
|
static const char *get_next_str(const char *start, const char *end)
|
||||||
|
@ -3530,6 +3631,16 @@ struct pprint_mapv {
|
||||||
uint32_t bits2c:2;
|
uint32_t bits2c:2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef __SIZEOF_INT128__
|
||||||
|
struct pprint_mapv_int128 {
|
||||||
|
__int128 si128a;
|
||||||
|
__int128 si128b;
|
||||||
|
unsigned __int128 bits3:3;
|
||||||
|
unsigned __int128 bits80:80;
|
||||||
|
unsigned __int128 ui128;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct btf_raw_test pprint_test_template[] = {
|
static struct btf_raw_test pprint_test_template[] = {
|
||||||
{
|
{
|
||||||
.raw_types = {
|
.raw_types = {
|
||||||
|
@ -3721,6 +3832,35 @@ static struct btf_raw_test pprint_test_template[] = {
|
||||||
.max_entries = 128 * 1024,
|
.max_entries = 128 * 1024,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#ifdef __SIZEOF_INT128__
|
||||||
|
{
|
||||||
|
/* test int128 */
|
||||||
|
.raw_types = {
|
||||||
|
/* unsigned int */ /* [1] */
|
||||||
|
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4),
|
||||||
|
/* __int128 */ /* [2] */
|
||||||
|
BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 128, 16),
|
||||||
|
/* unsigned __int128 */ /* [3] */
|
||||||
|
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 128, 16),
|
||||||
|
/* struct pprint_mapv_int128 */ /* [4] */
|
||||||
|
BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 1, 5), 64),
|
||||||
|
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(0, 0)), /* si128a */
|
||||||
|
BTF_MEMBER_ENC(NAME_TBD, 2, BTF_MEMBER_OFFSET(0, 128)), /* si128b */
|
||||||
|
BTF_MEMBER_ENC(NAME_TBD, 3, BTF_MEMBER_OFFSET(3, 256)), /* bits3 */
|
||||||
|
BTF_MEMBER_ENC(NAME_TBD, 3, BTF_MEMBER_OFFSET(80, 259)), /* bits80 */
|
||||||
|
BTF_MEMBER_ENC(NAME_TBD, 3, BTF_MEMBER_OFFSET(0, 384)), /* ui128 */
|
||||||
|
BTF_END_RAW,
|
||||||
|
},
|
||||||
|
BTF_STR_SEC("\0unsigned int\0__int128\0unsigned __int128\0pprint_mapv_int128\0si128a\0si128b\0bits3\0bits80\0ui128"),
|
||||||
|
.key_size = sizeof(unsigned int),
|
||||||
|
.value_size = sizeof(struct pprint_mapv_int128),
|
||||||
|
.key_type_id = 1,
|
||||||
|
.value_type_id = 4,
|
||||||
|
.max_entries = 128 * 1024,
|
||||||
|
.mapv_kind = PPRINT_MAPV_KIND_INT128,
|
||||||
|
},
|
||||||
|
#endif
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct btf_pprint_test_meta {
|
static struct btf_pprint_test_meta {
|
||||||
|
@ -3787,12 +3927,28 @@ static struct btf_pprint_test_meta {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static size_t get_pprint_mapv_size(enum pprint_mapv_kind_t mapv_kind)
|
||||||
|
{
|
||||||
|
if (mapv_kind == PPRINT_MAPV_KIND_BASIC)
|
||||||
|
return sizeof(struct pprint_mapv);
|
||||||
|
|
||||||
static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i,
|
#ifdef __SIZEOF_INT128__
|
||||||
|
if (mapv_kind == PPRINT_MAPV_KIND_INT128)
|
||||||
|
return sizeof(struct pprint_mapv_int128);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_pprint_mapv(enum pprint_mapv_kind_t mapv_kind,
|
||||||
|
void *mapv, uint32_t i,
|
||||||
int num_cpus, int rounded_value_size)
|
int num_cpus, int rounded_value_size)
|
||||||
{
|
{
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
|
if (mapv_kind == PPRINT_MAPV_KIND_BASIC) {
|
||||||
|
struct pprint_mapv *v = mapv;
|
||||||
|
|
||||||
for (cpu = 0; cpu < num_cpus; cpu++) {
|
for (cpu = 0; cpu < num_cpus; cpu++) {
|
||||||
v->ui32 = i + cpu;
|
v->ui32 = i + cpu;
|
||||||
v->si32 = -i;
|
v->si32 = -i;
|
||||||
|
@ -3807,6 +3963,74 @@ static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __SIZEOF_INT128__
|
||||||
|
if (mapv_kind == PPRINT_MAPV_KIND_INT128) {
|
||||||
|
struct pprint_mapv_int128 *v = mapv;
|
||||||
|
|
||||||
|
for (cpu = 0; cpu < num_cpus; cpu++) {
|
||||||
|
v->si128a = i;
|
||||||
|
v->si128b = -i;
|
||||||
|
v->bits3 = i & 0x07;
|
||||||
|
v->bits80 = (((unsigned __int128)1) << 64) + i;
|
||||||
|
v->ui128 = (((unsigned __int128)2) << 64) + i;
|
||||||
|
v = (void *)v + rounded_value_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t get_pprint_expected_line(enum pprint_mapv_kind_t mapv_kind,
|
||||||
|
char *expected_line, ssize_t line_size,
|
||||||
|
bool percpu_map, unsigned int next_key,
|
||||||
|
int cpu, void *mapv)
|
||||||
|
{
|
||||||
|
ssize_t nexpected_line = -1;
|
||||||
|
|
||||||
|
if (mapv_kind == PPRINT_MAPV_KIND_BASIC) {
|
||||||
|
struct pprint_mapv *v = mapv;
|
||||||
|
|
||||||
|
nexpected_line = snprintf(expected_line, line_size,
|
||||||
|
"%s%u: {%u,0,%d,0x%x,0x%x,0x%x,"
|
||||||
|
"{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s,"
|
||||||
|
"%u,0x%x}\n",
|
||||||
|
percpu_map ? "\tcpu" : "",
|
||||||
|
percpu_map ? cpu : next_key,
|
||||||
|
v->ui32, v->si32,
|
||||||
|
v->unused_bits2a,
|
||||||
|
v->bits28,
|
||||||
|
v->unused_bits2b,
|
||||||
|
v->ui64,
|
||||||
|
v->ui8a[0], v->ui8a[1],
|
||||||
|
v->ui8a[2], v->ui8a[3],
|
||||||
|
v->ui8a[4], v->ui8a[5],
|
||||||
|
v->ui8a[6], v->ui8a[7],
|
||||||
|
pprint_enum_str[v->aenum],
|
||||||
|
v->ui32b,
|
||||||
|
v->bits2c);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __SIZEOF_INT128__
|
||||||
|
if (mapv_kind == PPRINT_MAPV_KIND_INT128) {
|
||||||
|
struct pprint_mapv_int128 *v = mapv;
|
||||||
|
|
||||||
|
nexpected_line = snprintf(expected_line, line_size,
|
||||||
|
"%s%u: {0x%lx,0x%lx,0x%lx,"
|
||||||
|
"0x%lx%016lx,0x%lx%016lx}\n",
|
||||||
|
percpu_map ? "\tcpu" : "",
|
||||||
|
percpu_map ? cpu : next_key,
|
||||||
|
(uint64_t)v->si128a,
|
||||||
|
(uint64_t)v->si128b,
|
||||||
|
(uint64_t)v->bits3,
|
||||||
|
(uint64_t)(v->bits80 >> 64),
|
||||||
|
(uint64_t)v->bits80,
|
||||||
|
(uint64_t)(v->ui128 >> 64),
|
||||||
|
(uint64_t)v->ui128);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return nexpected_line;
|
||||||
|
}
|
||||||
|
|
||||||
static int check_line(const char *expected_line, int nexpected_line,
|
static int check_line(const char *expected_line, int nexpected_line,
|
||||||
int expected_line_len, const char *line)
|
int expected_line_len, const char *line)
|
||||||
{
|
{
|
||||||
|
@ -3828,10 +4052,10 @@ static int check_line(const char *expected_line, int nexpected_line,
|
||||||
static int do_test_pprint(int test_num)
|
static int do_test_pprint(int test_num)
|
||||||
{
|
{
|
||||||
const struct btf_raw_test *test = &pprint_test_template[test_num];
|
const struct btf_raw_test *test = &pprint_test_template[test_num];
|
||||||
|
enum pprint_mapv_kind_t mapv_kind = test->mapv_kind;
|
||||||
struct bpf_create_map_attr create_attr = {};
|
struct bpf_create_map_attr create_attr = {};
|
||||||
bool ordered_map, lossless_map, percpu_map;
|
bool ordered_map, lossless_map, percpu_map;
|
||||||
int err, ret, num_cpus, rounded_value_size;
|
int err, ret, num_cpus, rounded_value_size;
|
||||||
struct pprint_mapv *mapv = NULL;
|
|
||||||
unsigned int key, nr_read_elems;
|
unsigned int key, nr_read_elems;
|
||||||
int map_fd = -1, btf_fd = -1;
|
int map_fd = -1, btf_fd = -1;
|
||||||
unsigned int raw_btf_size;
|
unsigned int raw_btf_size;
|
||||||
|
@ -3840,6 +4064,7 @@ static int do_test_pprint(int test_num)
|
||||||
char pin_path[255];
|
char pin_path[255];
|
||||||
size_t line_len = 0;
|
size_t line_len = 0;
|
||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
|
void *mapv = NULL;
|
||||||
uint8_t *raw_btf;
|
uint8_t *raw_btf;
|
||||||
ssize_t nread;
|
ssize_t nread;
|
||||||
|
|
||||||
|
@ -3892,7 +4117,7 @@ static int do_test_pprint(int test_num)
|
||||||
|
|
||||||
percpu_map = test->percpu_map;
|
percpu_map = test->percpu_map;
|
||||||
num_cpus = percpu_map ? bpf_num_possible_cpus() : 1;
|
num_cpus = percpu_map ? bpf_num_possible_cpus() : 1;
|
||||||
rounded_value_size = round_up(sizeof(struct pprint_mapv), 8);
|
rounded_value_size = round_up(get_pprint_mapv_size(mapv_kind), 8);
|
||||||
mapv = calloc(num_cpus, rounded_value_size);
|
mapv = calloc(num_cpus, rounded_value_size);
|
||||||
if (CHECK(!mapv, "mapv allocation failure")) {
|
if (CHECK(!mapv, "mapv allocation failure")) {
|
||||||
err = -1;
|
err = -1;
|
||||||
|
@ -3900,7 +4125,7 @@ static int do_test_pprint(int test_num)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (key = 0; key < test->max_entries; key++) {
|
for (key = 0; key < test->max_entries; key++) {
|
||||||
set_pprint_mapv(mapv, key, num_cpus, rounded_value_size);
|
set_pprint_mapv(mapv_kind, mapv, key, num_cpus, rounded_value_size);
|
||||||
bpf_map_update_elem(map_fd, &key, mapv, 0);
|
bpf_map_update_elem(map_fd, &key, mapv, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3924,13 +4149,13 @@ static int do_test_pprint(int test_num)
|
||||||
ordered_map = test->ordered_map;
|
ordered_map = test->ordered_map;
|
||||||
lossless_map = test->lossless_map;
|
lossless_map = test->lossless_map;
|
||||||
do {
|
do {
|
||||||
struct pprint_mapv *cmapv;
|
|
||||||
ssize_t nexpected_line;
|
ssize_t nexpected_line;
|
||||||
unsigned int next_key;
|
unsigned int next_key;
|
||||||
|
void *cmapv;
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
next_key = ordered_map ? nr_read_elems : atoi(line);
|
next_key = ordered_map ? nr_read_elems : atoi(line);
|
||||||
set_pprint_mapv(mapv, next_key, num_cpus, rounded_value_size);
|
set_pprint_mapv(mapv_kind, mapv, next_key, num_cpus, rounded_value_size);
|
||||||
cmapv = mapv;
|
cmapv = mapv;
|
||||||
|
|
||||||
for (cpu = 0; cpu < num_cpus; cpu++) {
|
for (cpu = 0; cpu < num_cpus; cpu++) {
|
||||||
|
@ -3963,31 +4188,16 @@ static int do_test_pprint(int test_num)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
nexpected_line = snprintf(expected_line, sizeof(expected_line),
|
nexpected_line = get_pprint_expected_line(mapv_kind, expected_line,
|
||||||
"%s%u: {%u,0,%d,0x%x,0x%x,0x%x,"
|
sizeof(expected_line),
|
||||||
"{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s,"
|
percpu_map, next_key,
|
||||||
"%u,0x%x}\n",
|
cpu, cmapv);
|
||||||
percpu_map ? "\tcpu" : "",
|
|
||||||
percpu_map ? cpu : next_key,
|
|
||||||
cmapv->ui32, cmapv->si32,
|
|
||||||
cmapv->unused_bits2a,
|
|
||||||
cmapv->bits28,
|
|
||||||
cmapv->unused_bits2b,
|
|
||||||
cmapv->ui64,
|
|
||||||
cmapv->ui8a[0], cmapv->ui8a[1],
|
|
||||||
cmapv->ui8a[2], cmapv->ui8a[3],
|
|
||||||
cmapv->ui8a[4], cmapv->ui8a[5],
|
|
||||||
cmapv->ui8a[6], cmapv->ui8a[7],
|
|
||||||
pprint_enum_str[cmapv->aenum],
|
|
||||||
cmapv->ui32b,
|
|
||||||
cmapv->bits2c);
|
|
||||||
|
|
||||||
err = check_line(expected_line, nexpected_line,
|
err = check_line(expected_line, nexpected_line,
|
||||||
sizeof(expected_line), line);
|
sizeof(expected_line), line);
|
||||||
if (err == -1)
|
if (err == -1)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
cmapv = (void *)cmapv + rounded_value_size;
|
cmapv = cmapv + rounded_value_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (percpu_map) {
|
if (percpu_map) {
|
||||||
|
|
Loading…
Reference in New Issue