diff options
author | Eugene Syromyatnikov <evgsyr@gmail.com> | 2022-05-25 17:34:20 +0200 |
---|---|---|
committer | Dmitry V. Levin <ldv@strace.io> | 2022-05-26 23:11:20 +0000 |
commit | dda44d34e5fc0878e6ba3e08c6f297522758bae6 (patch) | |
tree | 0843db580794ab05f44a529d350f59775301802d | |
parent | c3ae37c314bfb43d5646699136debf96a5ed3540 (diff) | |
download | strace-dda44d34e5fc0878e6ba3e08c6f297522758bae6.tar.gz |
bpf: improve bpf(BPF_LINK_CREATE) decoding
union bpf_attr.link_create got a couple of new fields; this patch
attempts to decode it based on the attach_type field value, which
is imprecise, but the next best thing without information about
the type of prog_fd.
* src/xlat/bpf_link_create_kprobe_multi_flags.in: New file.
* src/gen_bpf_attr_check.sh: Ignore anonymous union fields;
* src/bpf_attr.h (BPF_LINK_CREATE_struct): Add target_btf_id, iter_info,
iter_info_len, perf_event.bpf_cookie, kprobe_multi.flags,
kprobe_multi.cnt, kprobe_multi.syms, kprobe_multi.addrs,
kprobe_multi.cookies fields.
(expected_BPF_LINK_CREATE_struct_size): Change to 48.
* src/bpf.c: Include "xlat/bpf_link_create_kprobe_multi_flags.h".
(BEGIN_BPF_CMD_DECODER): Remove const qualifier from attr_size
definition.
(union strace_bpf_iter_link_info): New type definition.
(print_iter_info_array_member, print_str_array_member): New functions.
(BEGIN_BPF_CMD_DECODER(BPF_LINK_CREATE)): Decode new fields.
* tests/bpf.c: Add new checks.
-rw-r--r-- | src/bpf.c | 137 | ||||
-rw-r--r-- | src/bpf_attr.h | 22 | ||||
-rwxr-xr-x | src/gen_bpf_attr_check.sh | 2 | ||||
-rw-r--r-- | src/xlat/bpf_link_create_kprobe_multi_flags.in | 1 | ||||
-rw-r--r-- | tests/bpf.c | 309 |
5 files changed, 458 insertions, 13 deletions
@@ -29,6 +29,7 @@ #include "xlat/bpf_query_flags.h" #include "xlat/bpf_task_fd_type.h" #include "xlat/bpf_test_run_flags.h" +#include "xlat/bpf_link_create_kprobe_multi_flags.h" #include "xlat/ebpf_regs.h" #include "xlat/numa_node.h" @@ -48,7 +49,7 @@ bpf_cmd_decoder(struct tcb *const tcp, \ static DECL_BPF_CMD_DECODER(decode_ ## bpf_cmd) \ { \ struct bpf_cmd ## _struct attr = {}; \ - const size_t attr_size = bpf_cmd ## _struct_size; \ + size_t attr_size = bpf_cmd ## _struct_size; \ const unsigned int len = MIN(size, attr_size); \ memcpy(&attr, data, len); \ do { \ @@ -1367,6 +1368,41 @@ BEGIN_BPF_CMD_DECODER(BPF_MAP_DELETE_BATCH) } END_BPF_CMD_DECODER(0) +union strace_bpf_iter_link_info { + struct { + uint32_t map_fd; + } map; +}; + +static bool +print_iter_info_array_member(struct tcb *tcp, void *elem_buf, + size_t elem_size, void *data) +{ + union strace_bpf_iter_link_info *bili = + (union strace_bpf_iter_link_info *) elem_buf; + + tprint_struct_begin(); + tprints_field_name("map"); + tprint_struct_begin(); + PRINT_FIELD_FD(bili->map, map_fd, tcp); + tprint_struct_end(); + tprint_struct_end(); + + return true; +} + +static bool +print_str_array_member(struct tcb *tcp, void *elem_buf, + size_t elem_size, void *data) +{ + kernel_ulong_t ptr = opt_wordsize(*(uint64_t *) elem_buf, + *(uint32_t *) elem_buf); + + printstr(tcp, ptr); + + return true; +} + BEGIN_BPF_CMD_DECODER(BPF_LINK_CREATE) { tprint_struct_begin(); @@ -1379,6 +1415,105 @@ BEGIN_BPF_CMD_DECODER(BPF_LINK_CREATE) PRINT_FIELD_XVAL(attr, attach_type, bpf_attach_type, "BPF_???"); tprint_struct_next(); PRINT_FIELD_X(attr, flags); + + if (len <= offsetof(struct BPF_LINK_CREATE_struct, target_btf_id)) + goto print_bpf_link_create_end; + + /* Trying to guess the union decoding based on the attach type */ + switch (attr.attach_type) { + /* TODO: check that prog type == BPF_PROG_TYPE_EXT */ + /* + * Yes, it is BPF_CGROUP_INET_INGRESS, see the inconceivable genius + * of the expected_attach_type check in v5.6-rc1~151^2~46^2~1^2~2. + */ + case 0: + /* Introduced in Linux commit v5.10-rc1~107^2~96^2~12^2~5 */ + if (attr.target_btf_id) { + tprint_struct_next(); + PRINT_FIELD_U(attr, target_btf_id); + } + attr_size = offsetofend(typeof(attr), target_btf_id); + break; + + /* TODO: prog type == BPF_PROG_TYPE_TRACING */ + case BPF_TRACE_ITER: { + /* Introduced in Linux commit v5.9-rc1~36^2~30^2~8^2~1 */ + union strace_bpf_iter_link_info buf; + + tprint_struct_next(); + tprints_field_name("iter_info"); + print_big_u64_addr(attr.iter_info); + print_array(tcp, attr.iter_info, attr.iter_info_len, + &buf, sizeof(buf), tfetch_mem, + print_iter_info_array_member, 0); + tprint_struct_next(); + PRINT_FIELD_U(attr, iter_info_len); + attr_size = offsetofend(typeof(attr), iter_info_len); + break; + } + + /* TODO: prog type == BPF_PROG_TYPE_{KPROBE,PERF_EVENT,TRACEPOINT} */ + case BPF_PERF_EVENT: + /* Introduced in Linux commit v5.15-rc1~157^2~22^2~33^2~11 */ + tprint_struct_next(); + tprints_field_name("perf_event"); + tprint_struct_begin(); + PRINT_FIELD_X(attr.perf_event, bpf_cookie); + tprint_struct_end(); + attr_size = offsetofend(typeof(attr), perf_event.bpf_cookie); + break; + + /* TODO: prog type == BPF_PROG_TYPE_KPROBE */ + case BPF_TRACE_KPROBE_MULTI: { + /* Introduced in Linux commit v5.18-rc1~136^2~11^2~28^2~10 */ + union { + kernel_ulong_t ptr; + uint64_t addr; + uint64_t cookie; + } buf; + + tprint_struct_next(); + tprints_field_name("kprobe_multi"); + tprint_struct_begin(); + PRINT_FIELD_FLAGS(attr.kprobe_multi, flags, + bpf_link_create_kprobe_multi_flags, + "BPF_F_???"); + tprint_struct_next(); + PRINT_FIELD_U(attr.kprobe_multi, cnt); + tprint_struct_next(); + tprints_field_name("syms"); + print_big_u64_addr(attr.kprobe_multi.syms); + print_array(tcp, attr.kprobe_multi.syms, attr.kprobe_multi.cnt, + &buf.ptr, current_wordsize, + tfetch_mem, print_str_array_member, 0); + tprint_struct_next(); + tprints_field_name("addrs"); + print_big_u64_addr(attr.kprobe_multi.addrs); + print_array(tcp, attr.kprobe_multi.addrs, attr.kprobe_multi.cnt, + &buf.ptr, sizeof(buf.addr), + tfetch_mem, print_xint_array_member, 0); + tprint_struct_next(); + tprints_field_name("cookies"); + print_big_u64_addr(attr.kprobe_multi.cookies); + print_array(tcp, attr.kprobe_multi.cookies, + attr.kprobe_multi.cnt, + &buf.cookie, sizeof(buf.cookie), + tfetch_mem, print_xint_array_member, 0); + tprint_struct_end(); + attr_size = offsetofend(typeof(attr), kprobe_multi.cookies); + break; + } + + default: + /* + * NB: resetting attr_size, so decode_attr_extra_data + * can pick up non-zero values in the union at the end + * of the link_create struct. + */ + attr_size = offsetofend(typeof(attr), flags); + } + +print_bpf_link_create_end: tprint_struct_end(); } END_BPF_CMD_DECODER(RVAL_DECODED | RVAL_FD) diff --git a/src/bpf_attr.h b/src/bpf_attr.h index 7f853e264..62d7bd76f 100644 --- a/src/bpf_attr.h +++ b/src/bpf_attr.h @@ -401,11 +401,31 @@ struct BPF_LINK_CREATE_struct /* link_create */ { uint32_t target_fd; uint32_t attach_type; uint32_t flags; + union { + uint32_t target_btf_id; + + struct { + uint64_t ATTRIBUTE_ALIGNED(8) iter_info; + uint32_t iter_info_len; + }; + + struct { + uint64_t ATTRIBUTE_ALIGNED(8) bpf_cookie; + } perf_event; + + struct { + uint32_t flags; + uint32_t cnt; + uint64_t ATTRIBUTE_ALIGNED(8) syms; + uint64_t ATTRIBUTE_ALIGNED(8) addrs; + uint64_t ATTRIBUTE_ALIGNED(8) cookies; + } kprobe_multi; + }; }; # define BPF_LINK_CREATE_struct_size \ sizeof(struct BPF_LINK_CREATE_struct) -# define expected_BPF_LINK_CREATE_struct_size 16 +# define expected_BPF_LINK_CREATE_struct_size 48 struct BPF_LINK_UPDATE_struct /* link_update */ { uint32_t link_fd; diff --git a/src/gen_bpf_attr_check.sh b/src/gen_bpf_attr_check.sh index c8fe1e3e6..b8c2cdb40 100755 --- a/src/gen_bpf_attr_check.sh +++ b/src/gen_bpf_attr_check.sh @@ -32,7 +32,7 @@ for struct in $(sed -n 's/^struct \([^[:space:]]\+_struct\) .*/\1/p' < "$input") enum="$enum${enum:+.}" ENUM="$ENUM${ENUM:+_}" sed -n '/^struct '"$struct"' [^{]*{/,/^};$/p' < "$input" | - sed -n 's/^[[:space:]]\+[^][;:]*[[:space:]]\([^][[:space:];:]\+\)\(\[[^;:]*\]\)\?;$/\1/p' | + sed -n 's/^[[:space:]]\+[^][;:]*[[:space:]]\([^]}[[:space:];:]\+\)\(\[[^;:]*\]\)\?;$/\1/p' | while read field; do FIELD="$(printf %s "$field" |tr '[:lower:]' '[:upper:]')" cat <<EOF diff --git a/src/xlat/bpf_link_create_kprobe_multi_flags.in b/src/xlat/bpf_link_create_kprobe_multi_flags.in new file mode 100644 index 000000000..c65157d99 --- /dev/null +++ b/src/xlat/bpf_link_create_kprobe_multi_flags.in @@ -0,0 +1 @@ +BPF_F_KPROBE_MULTI_RETURN (1U << 0) diff --git a/tests/bpf.c b/tests/bpf.c index e4ffac3bb..8668575be 100644 --- a/tests/bpf.c +++ b/tests/bpf.c @@ -26,6 +26,7 @@ #include "print_fields.h" #include "xlat.h" +#include "xlat/bpf_attach_type.h" #include "xlat/bpf_commands.h" #include "xlat/bpf_map_types.h" #include "xlat/bpf_prog_types.h" @@ -1484,24 +1485,312 @@ static const struct bpf_attr_check BPF_MAP_DELETE_BATCH_checks[] = { } }; -static const struct bpf_attr_check BPF_LINK_CREATE_checks[] = { - { - .data = { .BPF_LINK_CREATE_data = { .prog_fd = -1, .target_fd = -2 } }, - .size = offsetofend(struct BPF_LINK_CREATE_struct, flags), - .str = "link_create={prog_fd=-1, target_fd=-2" +static void +init_BPF_LINK_CREATE_attr1(struct bpf_attr_check *check, size_t idx) +{ + struct BPF_LINK_CREATE_struct *attr = &check->data.BPF_LINK_CREATE_data; + + attr->attach_type = idx; +} + +static void +print_BPF_LINK_CREATE_attr1(const struct bpf_attr_check *check, + unsigned long addr, size_t idx) +{ + printf("link_create={prog_fd=-1, target_fd=-559038737" + ", attach_type=%s, flags=0x4}", + sprintxval(bpf_attach_type, idx, "BPF_???")); +} + +/* Keep sorted */ +static const uint8_t special_attach_types[] = + { 0, BPF_TRACE_ITER, BPF_PERF_EVENT, BPF_TRACE_KPROBE_MULTI }; + +static void +init_BPF_LINK_CREATE_attr2(struct bpf_attr_check *check, size_t idx) +{ + struct BPF_LINK_CREATE_struct *attr = &check->data.BPF_LINK_CREATE_data; + + /* skip special_attach_types */ + for (size_t i = 0; i < ARRAY_SIZE(special_attach_types) + && idx >= special_attach_types[i]; i++, idx++); + + attr->attach_type = idx; + + check->data.char_data[19] = ' '; + check->data.char_data[23] = 'O'; + check->data.char_data[27] = 'H'; + check->data.char_data[31] = ' '; + check->data.char_data[35] = 'H'; + check->data.char_data[39] = 'A'; + check->data.char_data[43] = 'I'; + check->data.char_data[47] = '!'; +} + +static void +print_BPF_LINK_CREATE_attr2(const struct bpf_attr_check *check, + unsigned long addr, size_t idx) +{ + /* skip special_attach_types */ + for (size_t i = 0; i < ARRAY_SIZE(special_attach_types) + && idx >= special_attach_types[i]; i++, idx++); + + printf("link_create={prog_fd=-1, target_fd=-559038737" + ", attach_type=%s, flags=0xbadc0ded}, " +#if VERBOSE + "extra_data=\"\\x00\\x00\\x00\\x20\\x00\\x00\\x00\\x4f" + "\\x00\\x00\\x00\\x48\\x00\\x00\\x00\\x20\\x00\\x00\\x00\\x48" + "\\x00\\x00\\x00\\x41\\x00\\x00\\x00\\x49\\x00\\x00\\x00\\x21\"" + " /* bytes 16..47 */" +#else + "..." +#endif + , + sprintxval(bpf_attach_type, idx, "BPF_???")); +} + +static const int iter_info_data[] = { 0, 42, 314159265, 0xbadc0ded, -1 }; +static int *iter_info_data_p; + +static void +init_BPF_LINK_CREATE_attr7(struct bpf_attr_check *check, size_t idx) +{ + struct BPF_LINK_CREATE_struct *attr = &check->data.BPF_LINK_CREATE_data; + + if (!iter_info_data_p) { + iter_info_data_p = tail_memdup(iter_info_data, + sizeof(iter_info_data)); + } + + attr->iter_info = (uintptr_t) iter_info_data_p; + attr->iter_info_len = ARRAY_SIZE(iter_info_data) + idx; +} + +static void +print_BPF_LINK_CREATE_attr7(const struct bpf_attr_check *check, + unsigned long addr, size_t idx) +{ + printf("link_create={prog_fd=0" FD0_PATH ", target_fd=0" FD0_PATH + ", attach_type=BPF_TRACE_ITER, flags=0" + ", iter_info=[{map={map_fd=0" FD0_PATH "}}, {map={map_fd=42}}" + ", {map={map_fd=314159265}}, {map={map_fd=-1159983635}}" + ", {map={map_fd=-1}}"); + if (idx) { + printf(", ... /* %p */", + iter_info_data_p + ARRAY_SIZE(iter_info_data)); + } + printf("], iter_info_len=%zu}", ARRAY_SIZE(iter_info_data) + idx); + +} + +static const char *syms_data[] = { "foo", NULL, "OH\0HAI", + "abcdefghijklmnopqrstuvwxyz0123456789" }; +static char **syms_data_p; +static const uint64_t addrs_data[] = { 0, 1, 0xbadc0ded, + 0xfacefeeddeadc0deULL }; +static uint64_t *addrs_data_p; + +static_assert(ARRAY_SIZE(syms_data) == ARRAY_SIZE(addrs_data), + "syms_data and addrs_data have to have the same element count"); + +static void +init_BPF_LINK_CREATE_attr12(struct bpf_attr_check *check, size_t idx) +{ + struct BPF_LINK_CREATE_struct *attr = &check->data.BPF_LINK_CREATE_data; + + if (!syms_data_p) + syms_data_p = tail_memdup(syms_data, sizeof(syms_data)); + if (!addrs_data_p) + addrs_data_p = tail_memdup(addrs_data, sizeof(addrs_data)); + + attr->kprobe_multi.cnt = ARRAY_SIZE(syms_data) + idx; + attr->kprobe_multi.syms = (uintptr_t) syms_data_p; + attr->kprobe_multi.addrs = (uintptr_t) addrs_data_p; + attr->kprobe_multi.cookies = (uintptr_t) addrs_data_p; +} + +static void +print_BPF_LINK_CREATE_attr12(const struct bpf_attr_check *check, + unsigned long addr, size_t idx) +{ + printf("link_create={prog_fd=0" FD0_PATH ", target_fd=0" FD0_PATH + ", attach_type=BPF_TRACE_KPROBE_MULTI, flags=0" + ", kprobe_multi={flags=BPF_F_KPROBE_MULTI_RETURN|0xfacebeee" + ", cnt=%zu", ARRAY_SIZE(syms_data) + idx); + printf(", syms=[\"foo\", NULL, \"OH\"" + ", \"abcdefghijklmnopqrstuvwxyz012345\"..."); + if (idx) + printf(", ... /* %p */", syms_data_p + ARRAY_SIZE(syms_data)); + for (size_t i = 0; i < 2; i++) { + printf("], %s=[0, 0x1, 0xbadc0ded, 0xfacefeeddeadc0de", + i ? "cookies" : "addrs"); + if (idx) { + printf(", ... /* %p */", + addrs_data_p + ARRAY_SIZE(addrs_data)); + } + } + printf("]}}"); +} + +static struct bpf_attr_check BPF_LINK_CREATE_checks[] = { + { /* 0 */ + .data = { .BPF_LINK_CREATE_data = { .prog_fd = 0, .target_fd = 0 } }, + .size = offsetofend(struct BPF_LINK_CREATE_struct, target_fd), + .str = "link_create={prog_fd=0" FD0_PATH ", target_fd=0" FD0_PATH ", attach_type=BPF_CGROUP_INET_INGRESS, flags=0}" }, - { + { /* 1 */ .data = { .BPF_LINK_CREATE_data = { .prog_fd = -1, .target_fd = 0xdeadbeef, - .attach_type = 5, .flags = 4 } }, .size = offsetofend(struct BPF_LINK_CREATE_struct, flags), - .str = "link_create={prog_fd=-1, target_fd=-559038737" - ", attach_type=BPF_SK_SKB_STREAM_VERDICT, flags=0x4}" - } + .iters = ARRAY_SIZE(bpf_attach_type_xdata), + .init_fn = init_BPF_LINK_CREATE_attr1, + .print_fn = print_BPF_LINK_CREATE_attr1, + }, + { /* 2 - all non-special attach_types */ + .data = { .BPF_LINK_CREATE_data = { + .prog_fd = -1, + .target_fd = 0xdeadbeef, + .attach_type = 5, + .flags = 0xbadc0ded + } }, + .size = 48, + .iters = ARRAY_SIZE(bpf_attach_type_xdata) + - ARRAY_SIZE(special_attach_types), + .init_fn = init_BPF_LINK_CREATE_attr2, + .print_fn = print_BPF_LINK_CREATE_attr2, + }, + + { /* 3 */ + .data = { .BPF_LINK_CREATE_data = { + .attach_type = 0, + } }, + .size = offsetofend(struct BPF_LINK_CREATE_struct, + target_btf_id), + .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH + ", attach_type=BPF_CGROUP_INET_INGRESS, flags=0}" + }, + { /* 4 */ + .data = { .BPF_LINK_CREATE_data = { + .attach_type = 0, + .target_btf_id = 0xfacefeed, + } }, + .size = offsetofend(struct BPF_LINK_CREATE_struct, + target_btf_id), + .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH + ", attach_type=BPF_CGROUP_INET_INGRESS, flags=0" + ", target_btf_id=4207869677}" + }, + + { /* 5 */ + .data = { .BPF_LINK_CREATE_data = { + .attach_type = 28, + } }, + .size = offsetofend(struct BPF_LINK_CREATE_struct, + iter_info_len), + .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH + ", attach_type=BPF_TRACE_ITER, flags=0" + ", iter_info=NULL, iter_info_len=0}" + }, + { /* 6 */ + .data = { .BPF_LINK_CREATE_data = { + .attach_type = 28, + .iter_info = 0xffffffff00000000, + .iter_info_len = 0xdeadface, + } }, + .size = offsetofend(struct BPF_LINK_CREATE_struct, + iter_info_len), + .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH + ", attach_type=BPF_TRACE_ITER, flags=0" + ", iter_info=" BIG_ADDR("0xffffffff00000000", "NULL") + ", iter_info_len=3735943886}" + }, + { /* 7 */ + .data = { .BPF_LINK_CREATE_data = { + .attach_type = 28, + } }, + .size = offsetofend(struct BPF_LINK_CREATE_struct, + iter_info_len), + .iters = 2, + .init_fn = init_BPF_LINK_CREATE_attr7, + .print_fn = print_BPF_LINK_CREATE_attr7, + }, + + { /* 8 */ + .data = { .BPF_LINK_CREATE_data = { + .attach_type = 41, + } }, + .size = offsetofend(struct BPF_LINK_CREATE_struct, + perf_event.bpf_cookie), + .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH + ", attach_type=BPF_PERF_EVENT, flags=0" + ", perf_event={bpf_cookie=0}}" + }, + { /* 9 */ + .data = { .BPF_LINK_CREATE_data = { + .attach_type = 41, + .perf_event = { .bpf_cookie = 0xdeadc0defacecafeULL }, + } }, + .size = offsetofend(struct BPF_LINK_CREATE_struct, + perf_event.bpf_cookie), + .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH + ", attach_type=BPF_PERF_EVENT, flags=0" + ", perf_event={bpf_cookie=0xdeadc0defacecafe}}" + }, + + { /* 10 */ + .data = { .BPF_LINK_CREATE_data = { + .attach_type = 42, + } }, + .size = offsetofend(struct BPF_LINK_CREATE_struct, + kprobe_multi.cookies), + .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH + ", attach_type=BPF_TRACE_KPROBE_MULTI, flags=0" + ", kprobe_multi={flags=0, cnt=0, syms=NULL, addrs=NULL" + ", cookies=NULL}}" + }, + { /* 11 */ + .data = { .BPF_LINK_CREATE_data = { + .attach_type = 42, + .kprobe_multi = { + .flags = 0xdeadc0de, + .cnt = 0xbadfaced, + .syms = 0xffffffff00000000, + .addrs = 0xffffffff00000000, + .cookies = 0xffffffff00000000, + }, + } }, + .size = offsetofend(struct BPF_LINK_CREATE_struct, + kprobe_multi.cookies), + .str = "link_create={prog_fd=0" FD0_PATH", target_fd=0" FD0_PATH + ", attach_type=BPF_TRACE_KPROBE_MULTI, flags=0" + ", kprobe_multi={flags=0xdeadc0de /* BPF_F_??? */" + ", cnt=3135220973" + ", syms=" BIG_ADDR("0xffffffff00000000", "NULL") + ", addrs=" BIG_ADDR("0xffffffff00000000", "NULL") + ", cookies=" BIG_ADDR("0xffffffff00000000", "NULL") "}}" + }, + /* + * Note that here we rely on the fact that this attach_type has the + * largest de-facto attr_size to get the additional checks performed + * with the last check passed. + */ + { /* 12 */ + .data = { .BPF_LINK_CREATE_data = { + .attach_type = 42, + .kprobe_multi = { + .flags = 0xfacebeef, + } + } }, + .size = offsetofend(struct BPF_LINK_CREATE_struct, + kprobe_multi.cookies), + .iters = 2, + .init_fn = init_BPF_LINK_CREATE_attr12, + .print_fn = print_BPF_LINK_CREATE_attr12, + }, }; static const struct bpf_attr_check BPF_LINK_UPDATE_checks[] = { |