diff options
Diffstat (limited to 'kernel/bpf/arraymap.c')
| -rw-r--r-- | kernel/bpf/arraymap.c | 33 | 
1 files changed, 31 insertions, 2 deletions
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index d771a3872500..98c0f00c3f5e 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -49,13 +49,15 @@ static int bpf_array_alloc_percpu(struct bpf_array *array)  static struct bpf_map *array_map_alloc(union bpf_attr *attr)  {  	bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY; +	int numa_node = bpf_map_attr_numa_node(attr);  	struct bpf_array *array;  	u64 array_size;  	u32 elem_size;  	/* check sanity of attributes */  	if (attr->max_entries == 0 || attr->key_size != 4 || -	    attr->value_size == 0 || attr->map_flags) +	    attr->value_size == 0 || attr->map_flags & ~BPF_F_NUMA_NODE || +	    (percpu && numa_node != NUMA_NO_NODE))  		return ERR_PTR(-EINVAL);  	if (attr->value_size > KMALLOC_MAX_SIZE) @@ -77,7 +79,7 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)  		return ERR_PTR(-ENOMEM);  	/* allocate all map elements and zero-initialize them */ -	array = bpf_map_area_alloc(array_size); +	array = bpf_map_area_alloc(array_size, numa_node);  	if (!array)  		return ERR_PTR(-ENOMEM); @@ -87,6 +89,7 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)  	array->map.value_size = attr->value_size;  	array->map.max_entries = attr->max_entries;  	array->map.map_flags = attr->map_flags; +	array->map.numa_node = numa_node;  	array->elem_size = elem_size;  	if (!percpu) @@ -603,6 +606,31 @@ static void *array_of_map_lookup_elem(struct bpf_map *map, void *key)  	return READ_ONCE(*inner_map);  } +static u32 array_of_map_gen_lookup(struct bpf_map *map, +				   struct bpf_insn *insn_buf) +{ +	u32 elem_size = round_up(map->value_size, 8); +	struct bpf_insn *insn = insn_buf; +	const int ret = BPF_REG_0; +	const int map_ptr = BPF_REG_1; +	const int index = BPF_REG_2; + +	*insn++ = BPF_ALU64_IMM(BPF_ADD, map_ptr, offsetof(struct bpf_array, value)); +	*insn++ = BPF_LDX_MEM(BPF_W, ret, index, 0); +	*insn++ = BPF_JMP_IMM(BPF_JGE, ret, map->max_entries, 5); +	if (is_power_of_2(elem_size)) +		*insn++ = BPF_ALU64_IMM(BPF_LSH, ret, ilog2(elem_size)); +	else +		*insn++ = BPF_ALU64_IMM(BPF_MUL, ret, elem_size); +	*insn++ = BPF_ALU64_REG(BPF_ADD, ret, map_ptr); +	*insn++ = BPF_LDX_MEM(BPF_DW, ret, ret, 0); +	*insn++ = BPF_JMP_IMM(BPF_JEQ, ret, 0, 1); +	*insn++ = BPF_JMP_IMM(BPF_JA, 0, 0, 1); +	*insn++ = BPF_MOV64_IMM(ret, 0); + +	return insn - insn_buf; +} +  const struct bpf_map_ops array_of_maps_map_ops = {  	.map_alloc = array_of_map_alloc,  	.map_free = array_of_map_free, @@ -612,4 +640,5 @@ const struct bpf_map_ops array_of_maps_map_ops = {  	.map_fd_get_ptr = bpf_map_fd_get_ptr,  	.map_fd_put_ptr = bpf_map_fd_put_ptr,  	.map_fd_sys_lookup_elem = bpf_map_fd_sys_lookup_elem, +	.map_gen_lookup = array_of_map_gen_lookup,  };  | 
