[PATCH v4] ARM: net: JIT compiler for packet filters
Eric Dumazet
eric.dumazet at gmail.com
Thu Dec 22 08:43:26 EST 2011
Le jeudi 22 décembre 2011 à 13:59 +0100, Mircea Gherzan a écrit :
> Based of Matt Evans's PPC64 implementation.
>
> The compiler generates ARM instructions but interworking is
> supported for Thumb2 kernels.
>
> Supports both little and big endian. Unaligned loads are emitted
> for ARMv6+. Not all the BPF opcodes that deal with ancillary data
> are supported. The scratch memory of the filter lives on the stack.
> Hardware integer division is used if it is available.
>
> Enabled in the same way as for x86-64 and PPC64:
>
> echo 1 > /proc/sys/net/core/bpf_jit_enable
>
> A value greater than 1 enables opcode output.
>
> Signed-off-by: Mircea Gherzan <mgherzan at gmail.com>
> ---
...
> +/*
> + * ABI:
> + *
> + * r0 scratch register
> + * r4 BPF register A
> + * r5 BPF register X
> + * r6 pointer to the skb
> + * r7 skb->data
> + * r8 skb_headlen(skb)
> + */
> +
> +#define r_scratch ARM_R0
> +/* r1-r3 are (also) used for the unaligned loads on the non-ARMv7 slowpath */
> +#define r_off ARM_R1
> +#define r_A ARM_R4
> +#define r_X ARM_R5
> +#define r_skb ARM_R6
> +#define r_skb_data ARM_R7
> +#define r_skb_hl ARM_R8
> +
> +#define SCRATCH_SP_OFFSET 0
> +#define SCRATCH_OFF(k) (SCRATCH_SP_OFFSET + (k))
> +
> +#define SEEN_MEM ((1 << BPF_MEMWORDS) - 1)
> +#define SEEN_MEM_WORD(k) (1 << (k))
> +#define SEEN_X (1 << BPF_MEMWORDS)
> +#define SEEN_CALL (1 << (BPF_MEMWORDS + 1))
> +#define SEEN_DATA (1 << (BPF_MEMWORDS + 2))
> +#define SEEN_LEN (1 << (BPF_MEMWORDS + 3))
This seems wrong. skb->len has nothing special, its a particular case of
skb dereferencing.
You should rename this to SEEN_SKB_REF, and use it for everything
needing r_skb :
> + if (ctx->seen & (SEEN_DATA | SEEN_LEN))
> + emit(ARM_MOV_R(r_skb, ARM_R0), ctx);
> +
here you handled the thing correctly.
> + case BPF_S_LD_W_LEN:
> + ctx->seen |= SEEN_LEN;
> + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
> + emit(ARM_LDR_I(r_A, r_skb,
> + offsetof(struct sk_buff, len)), ctx);
> + break;
but here there is a problem :
> + case BPF_S_ANC_PROTOCOL:
> + /* A = ntohs(skb->protocol) */
> + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
> + protocol) != 2);
> + off = offsetof(struct sk_buff, protocol);
> + emit(ARM_LDRH_I(r_scratch, r_skb, off), ctx);
> + emit_swap16(r_A, r_scratch, ctx);
> + break;
here too :
> + case BPF_S_ANC_IFINDEX:
> + /* A = skb->dev->ifindex */
> + off = offsetof(struct sk_buff, dev);
> + emit(ARM_LDR_I(r_scratch, r_skb, off), ctx);
> +
> + emit(ARM_CMP_I(r_scratch, 0), ctx);
> + emit_err_ret(ARM_COND_EQ, ctx);
> +
> + BUILD_BUG_ON(FIELD_SIZEOF(struct net_device,
> + ifindex) != 4);
> + off = offsetof(struct net_device, ifindex);
> + emit(ARM_LDR_I(r_A, r_scratch, off), ctx);
> + break;
here too :
> + case BPF_S_ANC_MARK:
> + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
> + off = offsetof(struct sk_buff, mark);
> + emit(ARM_LDR_I(r_A, r_skb, off), ctx);
> + break;
here too :
> + case BPF_S_ANC_RXHASH:
> + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
> + off = offsetof(struct sk_buff, rxhash);
> + emit(ARM_LDR_I(r_A, r_skb, off), ctx);
> + break;
and also here :
> + case BPF_S_ANC_QUEUE:
> + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff,
> + queue_mapping) != 2);
> + BUILD_BUG_ON(offsetof(struct sk_buff,
> + queue_mapping) > 0xff);
> + off = offsetof(struct sk_buff, queue_mapping);
> + emit(ARM_LDRH_I(r_A, r_skb, off), ctx);
> + break;
More information about the linux-arm-kernel
mailing list