aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/bpf/arraymap.c
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@fb.com>2017-03-15 21:26:42 -0400
committerDavid S. Miller <davem@davemloft.net>2017-03-16 23:44:11 -0400
commit81ed18ab3098b6519274545e80a29caacb77d160 (patch)
tree62cf05acb5648f25efd010110c6f40b70d1371c6 /kernel/bpf/arraymap.c
parent8041902dae5299c1f194ba42d14383f734631009 (diff)
bpf: add helper inlining infra and optimize map_array lookup
Optimize bpf_call -> bpf_map_lookup_elem() -> array_map_lookup_elem() into a sequence of bpf instructions. When JIT is on the sequence of bpf instructions is the sequence of native cpu instructions with significantly faster performance than indirect call and two function's prologue/epilogue. Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Daniel Borkmann <daniel@iogearbox.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'kernel/bpf/arraymap.c')
-rw-r--r--kernel/bpf/arraymap.c29
1 files changed, 29 insertions, 0 deletions
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 6b6f41f0b211..bcf9955fac95 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -1,4 +1,5 @@
1/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com 1/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
2 * Copyright (c) 2016,2017 Facebook
2 * 3 *
3 * This program is free software; you can redistribute it and/or 4 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of version 2 of the GNU General Public 5 * modify it under the terms of version 2 of the GNU General Public
@@ -113,6 +114,33 @@ static void *array_map_lookup_elem(struct bpf_map *map, void *key)
113 return array->value + array->elem_size * index; 114 return array->value + array->elem_size * index;
114} 115}
115 116
117/* emit BPF instructions equivalent to C code of array_map_lookup_elem() */
118static u32 array_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf)
119{
120 struct bpf_array *array = container_of(map, struct bpf_array, map);
121 struct bpf_insn *insn = insn_buf;
122 u32 elem_size = array->elem_size;
123 const int ret = BPF_REG_0;
124 const int map_ptr = BPF_REG_1;
125 const int index = BPF_REG_2;
126
127 *insn++ = BPF_ALU64_IMM(BPF_ADD, map_ptr, offsetof(struct bpf_array, value));
128 *insn++ = BPF_LDX_MEM(BPF_W, ret, index, 0);
129 *insn++ = BPF_JMP_IMM(BPF_JGE, ret, array->map.max_entries,
130 elem_size == 1 ? 2 : 3);
131 if (elem_size == 1) {
132 /* nop */
133 } else if (is_power_of_2(elem_size)) {
134 *insn++ = BPF_ALU64_IMM(BPF_LSH, ret, ilog2(elem_size));
135 } else {
136 *insn++ = BPF_ALU64_IMM(BPF_MUL, ret, elem_size);
137 }
138 *insn++ = BPF_ALU64_REG(BPF_ADD, ret, map_ptr);
139 *insn++ = BPF_JMP_IMM(BPF_JA, 0, 0, 1);
140 *insn++ = BPF_MOV64_IMM(ret, 0);
141 return insn - insn_buf;
142}
143
116/* Called from eBPF program */ 144/* Called from eBPF program */
117static void *percpu_array_map_lookup_elem(struct bpf_map *map, void *key) 145static void *percpu_array_map_lookup_elem(struct bpf_map *map, void *key)
118{ 146{
@@ -267,6 +295,7 @@ static const struct bpf_map_ops array_ops = {
267 .map_lookup_elem = array_map_lookup_elem, 295 .map_lookup_elem = array_map_lookup_elem,
268 .map_update_elem = array_map_update_elem, 296 .map_update_elem = array_map_update_elem,
269 .map_delete_elem = array_map_delete_elem, 297 .map_delete_elem = array_map_delete_elem,
298 .map_gen_lookup = array_map_gen_lookup,
270}; 299};
271 300
272static struct bpf_map_type_list array_type __ro_after_init = { 301static struct bpf_map_type_list array_type __ro_after_init = {