diff options
author | Michael Holzheu <holzheu@linux.vnet.ibm.com> | 2015-07-29 15:15:18 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-07-29 17:59:58 -0400 |
commit | 9db7f2b818809ef2c40fbd64cfcf5ccb0107d7e8 (patch) | |
tree | e4d0b2ed3dc2e6900106edff81e834f063007e1c /arch/s390/net | |
parent | cde66c2d88da1d73d755109c80ce4c34b917596b (diff) |
s390/bpf: recache skb->data/hlen for skb_vlan_push/pop
Allow eBPF programs attached to TC qdiscs call skb_vlan_push/pop
via helper functions. These functions may change skb->data/hlen.
This data is cached by s390 JIT to improve performance of ld_abs/ld_ind
instructions. Therefore after a change we have to reload the data.
In case of usage of skb_vlan_push/pop, in the prologue we store
the SKB pointer on the stack and restore it after BPF_JMP_CALL
to skb_vlan_push/pop.
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/s390/net')
-rw-r--r-- | arch/s390/net/bpf_jit.h | 5 | ||||
-rw-r--r-- | arch/s390/net/bpf_jit_comp.c | 55 |
2 files changed, 37 insertions, 23 deletions
diff --git a/arch/s390/net/bpf_jit.h b/arch/s390/net/bpf_jit.h index f6498eec9ee1..f010c93a88b1 100644 --- a/arch/s390/net/bpf_jit.h +++ b/arch/s390/net/bpf_jit.h | |||
@@ -36,6 +36,8 @@ extern u8 sk_load_word[], sk_load_half[], sk_load_byte[]; | |||
36 | * | BPF stack | | | 36 | * | BPF stack | | |
37 | * | | | | 37 | * | | | |
38 | * +---------------+ | | 38 | * +---------------+ | |
39 | * | 8 byte skbp | | | ||
40 | * R15+170 -> +---------------+ | | ||
39 | * | 8 byte hlen | | | 41 | * | 8 byte hlen | | |
40 | * R15+168 -> +---------------+ | | 42 | * R15+168 -> +---------------+ | |
41 | * | 4 byte align | | | 43 | * | 4 byte align | | |
@@ -51,11 +53,12 @@ extern u8 sk_load_word[], sk_load_half[], sk_load_byte[]; | |||
51 | * We get 160 bytes stack space from calling function, but only use | 53 | * We get 160 bytes stack space from calling function, but only use |
52 | * 12 * 8 byte for old backchain, r15..r6, and tail_call_cnt. | 54 | * 12 * 8 byte for old backchain, r15..r6, and tail_call_cnt. |
53 | */ | 55 | */ |
54 | #define STK_SPACE (MAX_BPF_STACK + 8 + 4 + 4 + 160) | 56 | #define STK_SPACE (MAX_BPF_STACK + 8 + 8 + 4 + 4 + 160) |
55 | #define STK_160_UNUSED (160 - 12 * 8) | 57 | #define STK_160_UNUSED (160 - 12 * 8) |
56 | #define STK_OFF (STK_SPACE - STK_160_UNUSED) | 58 | #define STK_OFF (STK_SPACE - STK_160_UNUSED) |
57 | #define STK_OFF_TMP 160 /* Offset of tmp buffer on stack */ | 59 | #define STK_OFF_TMP 160 /* Offset of tmp buffer on stack */ |
58 | #define STK_OFF_HLEN 168 /* Offset of SKB header length on stack */ | 60 | #define STK_OFF_HLEN 168 /* Offset of SKB header length on stack */ |
61 | #define STK_OFF_SKBP 170 /* Offset of SKB pointer on stack */ | ||
59 | 62 | ||
60 | #define STK_OFF_R6 (160 - 11 * 8) /* Offset of r6 on stack */ | 63 | #define STK_OFF_R6 (160 - 11 * 8) /* Offset of r6 on stack */ |
61 | #define STK_OFF_TCCNT (160 - 12 * 8) /* Offset of tail_call_cnt on stack */ | 64 | #define STK_OFF_TCCNT (160 - 12 * 8) /* Offset of tail_call_cnt on stack */ |
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index 3dd01637f83a..bbbac6da37af 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c | |||
@@ -53,6 +53,7 @@ struct bpf_jit { | |||
53 | #define SEEN_LITERAL 8 /* code uses literals */ | 53 | #define SEEN_LITERAL 8 /* code uses literals */ |
54 | #define SEEN_FUNC 16 /* calls C functions */ | 54 | #define SEEN_FUNC 16 /* calls C functions */ |
55 | #define SEEN_TAIL_CALL 32 /* code uses tail calls */ | 55 | #define SEEN_TAIL_CALL 32 /* code uses tail calls */ |
56 | #define SEEN_SKB_CHANGE 64 /* code changes skb data */ | ||
56 | #define SEEN_STACK (SEEN_FUNC | SEEN_MEM | SEEN_SKB) | 57 | #define SEEN_STACK (SEEN_FUNC | SEEN_MEM | SEEN_SKB) |
57 | 58 | ||
58 | /* | 59 | /* |
@@ -382,6 +383,26 @@ static void save_restore_regs(struct bpf_jit *jit, int op) | |||
382 | } | 383 | } |
383 | 384 | ||
384 | /* | 385 | /* |
386 | * For SKB access %b1 contains the SKB pointer. For "bpf_jit.S" | ||
387 | * we store the SKB header length on the stack and the SKB data | ||
388 | * pointer in REG_SKB_DATA. | ||
389 | */ | ||
390 | static void emit_load_skb_data_hlen(struct bpf_jit *jit) | ||
391 | { | ||
392 | /* Header length: llgf %w1,<len>(%b1) */ | ||
393 | EMIT6_DISP_LH(0xe3000000, 0x0016, REG_W1, REG_0, BPF_REG_1, | ||
394 | offsetof(struct sk_buff, len)); | ||
395 | /* s %w1,<data_len>(%b1) */ | ||
396 | EMIT4_DISP(0x5b000000, REG_W1, BPF_REG_1, | ||
397 | offsetof(struct sk_buff, data_len)); | ||
398 | /* stg %w1,ST_OFF_HLEN(%r0,%r15) */ | ||
399 | EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W1, REG_0, REG_15, STK_OFF_HLEN); | ||
400 | /* lg %skb_data,data_off(%b1) */ | ||
401 | EMIT6_DISP_LH(0xe3000000, 0x0004, REG_SKB_DATA, REG_0, | ||
402 | BPF_REG_1, offsetof(struct sk_buff, data)); | ||
403 | } | ||
404 | |||
405 | /* | ||
385 | * Emit function prologue | 406 | * Emit function prologue |
386 | * | 407 | * |
387 | * Save registers and create stack frame if necessary. | 408 | * Save registers and create stack frame if necessary. |
@@ -421,25 +442,12 @@ static void bpf_jit_prologue(struct bpf_jit *jit, bool is_classic) | |||
421 | EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W1, REG_0, | 442 | EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W1, REG_0, |
422 | REG_15, 152); | 443 | REG_15, 152); |
423 | } | 444 | } |
424 | /* | 445 | if (jit->seen & SEEN_SKB) |
425 | * For SKB access %b1 contains the SKB pointer. For "bpf_jit.S" | 446 | emit_load_skb_data_hlen(jit); |
426 | * we store the SKB header length on the stack and the SKB data | 447 | if (jit->seen & SEEN_SKB_CHANGE) |
427 | * pointer in REG_SKB_DATA. | 448 | /* stg %b1,ST_OFF_SKBP(%r0,%r15) */ |
428 | */ | ||
429 | if (jit->seen & SEEN_SKB) { | ||
430 | /* Header length: llgf %w1,<len>(%b1) */ | ||
431 | EMIT6_DISP_LH(0xe3000000, 0x0016, REG_W1, REG_0, BPF_REG_1, | ||
432 | offsetof(struct sk_buff, len)); | ||
433 | /* s %w1,<data_len>(%b1) */ | ||
434 | EMIT4_DISP(0x5b000000, REG_W1, BPF_REG_1, | ||
435 | offsetof(struct sk_buff, data_len)); | ||
436 | /* stg %w1,ST_OFF_HLEN(%r0,%r15) */ | ||
437 | EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W1, REG_0, REG_15, | 449 | EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W1, REG_0, REG_15, |
438 | STK_OFF_HLEN); | 450 | STK_OFF_SKBP); |
439 | /* lg %skb_data,data_off(%b1) */ | ||
440 | EMIT6_DISP_LH(0xe3000000, 0x0004, REG_SKB_DATA, REG_0, | ||
441 | BPF_REG_1, offsetof(struct sk_buff, data)); | ||
442 | } | ||
443 | /* Clear A (%b0) and X (%b7) registers for converted BPF programs */ | 451 | /* Clear A (%b0) and X (%b7) registers for converted BPF programs */ |
444 | if (is_classic) { | 452 | if (is_classic) { |
445 | if (REG_SEEN(BPF_REG_A)) | 453 | if (REG_SEEN(BPF_REG_A)) |
@@ -967,10 +975,6 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i | |||
967 | */ | 975 | */ |
968 | const u64 func = (u64)__bpf_call_base + imm; | 976 | const u64 func = (u64)__bpf_call_base + imm; |
969 | 977 | ||
970 | if (bpf_helper_changes_skb_data((void *)func)) | ||
971 | /* TODO reload skb->data, hlen */ | ||
972 | return -1; | ||
973 | |||
974 | REG_SET_SEEN(BPF_REG_5); | 978 | REG_SET_SEEN(BPF_REG_5); |
975 | jit->seen |= SEEN_FUNC; | 979 | jit->seen |= SEEN_FUNC; |
976 | /* lg %w1,<d(imm)>(%l) */ | 980 | /* lg %w1,<d(imm)>(%l) */ |
@@ -980,6 +984,13 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i | |||
980 | EMIT2(0x0d00, REG_14, REG_W1); | 984 | EMIT2(0x0d00, REG_14, REG_W1); |
981 | /* lgr %b0,%r2: load return value into %b0 */ | 985 | /* lgr %b0,%r2: load return value into %b0 */ |
982 | EMIT4(0xb9040000, BPF_REG_0, REG_2); | 986 | EMIT4(0xb9040000, BPF_REG_0, REG_2); |
987 | if (bpf_helper_changes_skb_data((void *)func)) { | ||
988 | jit->seen |= SEEN_SKB_CHANGE; | ||
989 | /* lg %b1,ST_OFF_SKBP(%r15) */ | ||
990 | EMIT6_DISP_LH(0xe3000000, 0x0004, BPF_REG_1, REG_0, | ||
991 | REG_15, STK_OFF_SKBP); | ||
992 | emit_load_skb_data_hlen(jit); | ||
993 | } | ||
983 | break; | 994 | break; |
984 | } | 995 | } |
985 | case BPF_JMP | BPF_CALL | BPF_X: | 996 | case BPF_JMP | BPF_CALL | BPF_X: |