1 /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com 2 * 3 * 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 * License as published by the Free Software Foundation. 6 * 7 * This program is distributed in the hope that it will be useful, but 8 * WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 * General Public License for more details. 11 */ 12 #include <linux/bpf.h> 13 #include <linux/err.h> 14 #include <linux/vmalloc.h> 15 #include <linux/slab.h> 16 #include <linux/mm.h> 17 18 struct bpf_array { 19 struct bpf_map map; 20 u32 elem_size; 21 char value[0] __aligned(8); 22 }; 23 24 /* Called from syscall */ 25 static struct bpf_map *array_map_alloc(union bpf_attr *attr) 26 { 27 struct bpf_array *array; 28 u32 elem_size, array_size; 29 30 /* check sanity of attributes */ 31 if (attr->max_entries == 0 || attr->key_size != 4 || 32 attr->value_size == 0) 33 return ERR_PTR(-EINVAL); 34 35 elem_size = round_up(attr->value_size, 8); 36 37 /* check round_up into zero and u32 overflow */ 38 if (elem_size == 0 || 39 attr->max_entries > (U32_MAX - sizeof(*array)) / elem_size) 40 return ERR_PTR(-ENOMEM); 41 42 array_size = sizeof(*array) + attr->max_entries * elem_size; 43 44 /* allocate all map elements and zero-initialize them */ 45 array = kzalloc(array_size, GFP_USER | __GFP_NOWARN); 46 if (!array) { 47 array = vzalloc(array_size); 48 if (!array) 49 return ERR_PTR(-ENOMEM); 50 } 51 52 /* copy mandatory map attributes */ 53 array->map.key_size = attr->key_size; 54 array->map.value_size = attr->value_size; 55 array->map.max_entries = attr->max_entries; 56 57 array->elem_size = elem_size; 58 59 return &array->map; 60 } 61 62 /* Called from syscall or from eBPF program */ 63 static void *array_map_lookup_elem(struct bpf_map *map, void *key) 64 { 65 struct bpf_array *array = container_of(map, struct bpf_array, map); 66 u32 index = *(u32 *)key; 67 68 if (index >= array->map.max_entries) 69 return NULL; 70 71 return array->value + array->elem_size * index; 72 } 73 74 /* Called from syscall */ 75 static int array_map_get_next_key(struct bpf_map *map, void *key, void *next_key) 76 { 77 struct bpf_array *array = container_of(map, struct bpf_array, map); 78 u32 index = *(u32 *)key; 79 u32 *next = (u32 *)next_key; 80 81 if (index >= array->map.max_entries) { 82 *next = 0; 83 return 0; 84 } 85 86 if (index == array->map.max_entries - 1) 87 return -ENOENT; 88 89 *next = index + 1; 90 return 0; 91 } 92 93 /* Called from syscall or from eBPF program */ 94 static int array_map_update_elem(struct bpf_map *map, void *key, void *value, 95 u64 map_flags) 96 { 97 struct bpf_array *array = container_of(map, struct bpf_array, map); 98 u32 index = *(u32 *)key; 99 100 if (map_flags > BPF_EXIST) 101 /* unknown flags */ 102 return -EINVAL; 103 104 if (index >= array->map.max_entries) 105 /* all elements were pre-allocated, cannot insert a new one */ 106 return -E2BIG; 107 108 if (map_flags == BPF_NOEXIST) 109 /* all elements already exist */ 110 return -EEXIST; 111 112 memcpy(array->value + array->elem_size * index, value, array->elem_size); 113 return 0; 114 } 115 116 /* Called from syscall or from eBPF program */ 117 static int array_map_delete_elem(struct bpf_map *map, void *key) 118 { 119 return -EINVAL; 120 } 121 122 /* Called when map->refcnt goes to zero, either from workqueue or from syscall */ 123 static void array_map_free(struct bpf_map *map) 124 { 125 struct bpf_array *array = container_of(map, struct bpf_array, map); 126 127 /* at this point bpf_prog->aux->refcnt == 0 and this map->refcnt == 0, 128 * so the programs (can be more than one that used this map) were 129 * disconnected from events. Wait for outstanding programs to complete 130 * and free the array 131 */ 132 synchronize_rcu(); 133 134 kvfree(array); 135 } 136 137 static struct bpf_map_ops array_ops = { 138 .map_alloc = array_map_alloc, 139 .map_free = array_map_free, 140 .map_get_next_key = array_map_get_next_key, 141 .map_lookup_elem = array_map_lookup_elem, 142 .map_update_elem = array_map_update_elem, 143 .map_delete_elem = array_map_delete_elem, 144 }; 145 146 static struct bpf_map_type_list tl = { 147 .ops = &array_ops, 148 .type = BPF_MAP_TYPE_ARRAY, 149 }; 150 151 static int __init register_array_map(void) 152 { 153 bpf_register_map_type(&tl); 154 return 0; 155 } 156 late_initcall(register_array_map); 157