On Thu, Aug 22, 2024 at 2:25 AM Tony Ambardar <[email protected]> wrote:
>
> From: Tony Ambardar <[email protected]>
>
> Track target endianness in 'struct bpf_gen' and process in-memory data in
> native byte-order, but on finalization convert the embedded loader BPF
> insns to target endianness.
>
> The light skeleton also includes a target-accessed data blob which is
> heterogeneous and thus difficult to convert to target byte-order on
> finalization. Add support functions to convert data to target endianness
> as it is added to the blob.
>
> Also add additional debug logging for data blob structure details and
> skeleton loading.
>
> Signed-off-by: Tony Ambardar <[email protected]>
> ---
> tools/lib/bpf/bpf_gen_internal.h | 1 +
> tools/lib/bpf/gen_loader.c | 187 +++++++++++++++++++++++--------
> tools/lib/bpf/libbpf.c | 1 +
> tools/lib/bpf/skel_internal.h | 3 +-
> 4 files changed, 147 insertions(+), 45 deletions(-)
>
[...]
> +/*
> + * Fields of bpf_attr are set to values in native byte-order before being
> + * written to the target-bound data blob, and may need endian conversion.
> + * This macro allows setting the correct value in situ and is simpler than
> + * writing a separate converter for *all fields* of *all records* included
> + * in union bpf_attr.
> + */
> +#define move_tgt_endian(lval, rval) { \
> + if (!gen->swapped_endian) \
> + lval = (rval); \
add {} here and for else branch, please
> + else \
> + switch (sizeof(lval)) { \
> + case 2: \
> + lval = bswap_16(rval); \
> + break; \
> + case 4: \
> + lval = bswap_32(rval); \
> + break; \
> + case 8: \
> + lval = bswap_64(rval); \
> + break; \
I'd also go for more compact:
case 2: lval = bswap_16(rval); break;
case 4: lval = bswap_32(rval); break;
> + default: \
> + lval = (rval); \
> + pr_warn("unsupported bswap size!\n"); \
case 1: is unsupported? It just doesn't need a byte swap, so please
add it explicitly and avoid unnecessary warnings
> + } \
> + }
> +
> void bpf_gen__load_btf(struct bpf_gen *gen, const void *btf_raw_data,
> __u32 btf_raw_size)
> {
[...]
> emit(gen, BPF_LDX_MEM(BPF_B, BPF_REG_9, BPF_REG_8, offsetofend(struct
> bpf_insn, code)));
> emit(gen, BPF_ALU32_IMM(BPF_AND, BPF_REG_9, reg_mask));
> emit(gen, BPF_STX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, offsetofend(struct
> bpf_insn, code)));
> @@ -931,11 +971,34 @@ static void cleanup_relos(struct bpf_gen *gen, int
> insns)
> cleanup_core_relo(gen);
> }
>
> +/* Covert func, line, and core relo info records to target endianness,
typo: convert
> + * checking the blob size is consistent with 32-bit fields.
> + */
> +static void info_blob_bswap(struct bpf_gen *gen, int info_off, __u32 size)
> +{
> + __u32 *field = gen->data_start + info_off;
> + int i, cnt = size / sizeof(__u32);
> +
> + if (size && size % sizeof(__u32)) {
nit: () around mod operation
> + pr_warn("info records not using 32-bit fields!\n");
> + return;
> + }
> + if (gen->swapped_endian)
> + for (i = 0; i < cnt; i++, field++)
> + *field = bswap_32(*field);
> +}
> +
> void bpf_gen__prog_load(struct bpf_gen *gen,
> enum bpf_prog_type prog_type, const char *prog_name,
> const char *license, struct bpf_insn *insns, size_t
> insn_cnt,
> struct bpf_prog_load_opts *load_attr, int prog_idx)
> {
> + int func_info_tot_sz = load_attr->func_info_cnt *
> + load_attr->func_info_rec_size;
> + int line_info_tot_sz = load_attr->line_info_cnt *
> + load_attr->line_info_rec_size;
> + int core_relo_tot_sz = gen->core_relo_cnt *
> + sizeof(struct bpf_core_relo);
> int prog_load_attr, license_off, insns_off, func_info, line_info,
> core_relos;
> int attr_size = offsetofend(union bpf_attr, core_relo_rec_size);
> union bpf_attr attr;
> @@ -947,32 +1010,60 @@ void bpf_gen__prog_load(struct bpf_gen *gen,
> license_off = add_data(gen, license, strlen(license) + 1);
> /* add insns to blob of bytes */
> insns_off = add_data(gen, insns, insn_cnt * sizeof(struct bpf_insn));
> + pr_debug("gen: prog_load: license off %d insn off %d\n",
> + license_off, insns_off);
>
> - attr.prog_type = prog_type;
> - attr.expected_attach_type = load_attr->expected_attach_type;
> - attr.attach_btf_id = load_attr->attach_btf_id;
> - attr.prog_ifindex = load_attr->prog_ifindex;
> - attr.kern_version = 0;
> - attr.insn_cnt = (__u32)insn_cnt;
> - attr.prog_flags = load_attr->prog_flags;
> -
> - attr.func_info_rec_size = load_attr->func_info_rec_size;
> - attr.func_info_cnt = load_attr->func_info_cnt;
> - func_info = add_data(gen, load_attr->func_info,
> - attr.func_info_cnt * attr.func_info_rec_size);
> + /* convert blob insns to target endianness */
> + if (gen->swapped_endian) {
> + struct bpf_insn *insn = gen->data_start + insns_off;
> + int i;
>
> - attr.line_info_rec_size = load_attr->line_info_rec_size;
> - attr.line_info_cnt = load_attr->line_info_cnt;
> - line_info = add_data(gen, load_attr->line_info,
> - attr.line_info_cnt * attr.line_info_rec_size);
> + for (i = 0; i < insn_cnt; i++, insn++)
> + bpf_insn_bswap(insn);
> + }
>
> - attr.core_relo_rec_size = sizeof(struct bpf_core_relo);
> - attr.core_relo_cnt = gen->core_relo_cnt;
> - core_relos = add_data(gen, gen->core_relos,
> - attr.core_relo_cnt * attr.core_relo_rec_size);
> + move_tgt_endian(attr.prog_type, prog_type);
> + move_tgt_endian(attr.expected_attach_type,
> load_attr->expected_attach_type);
> + move_tgt_endian(attr.attach_btf_id, load_attr->attach_btf_id);
> + move_tgt_endian(attr.prog_ifindex, load_attr->prog_ifindex);
> + attr.kern_version = 0;
> + move_tgt_endian(attr.insn_cnt, (__u32)insn_cnt);
> + move_tgt_endian(attr.prog_flags, load_attr->prog_flags);
> +
> + move_tgt_endian(attr.func_info_rec_size,
> load_attr->func_info_rec_size);
> + move_tgt_endian(attr.func_info_cnt, load_attr->func_info_cnt);
this is quite intrusive, maybe instead of imperative move_tgt_endian()
macro, develop the one that could be used as
attr.func_info_cnt = tgt_endian(load_attr->func_info_cnt);
? I.e., working as an expression, taking into account the need to swap
and byte size of the argument. Should be doable.
> + func_info = add_data(gen, load_attr->func_info, func_info_tot_sz);
> + pr_debug("gen: prog_load: func_info: off %d cnt %d rec size %d\n",
> + func_info, load_attr->func_info_cnt,
> + load_attr->func_info_rec_size);
[...]