| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814 |
- #include <sys/resource.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <net/if.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <errno.h>
- #include <unistd.h>
- #include <bpf/bpf.h>
- #include <bpf/libbpf.h>
- #include "ucode/module.h"
- #define err_return_int(err, ...) do { set_error(err, __VA_ARGS__); return -1; } while(0)
- #define err_return(err, ...) do { set_error(err, __VA_ARGS__); return NULL; } while(0)
- #define TRUE ucv_boolean_new(true)
- static uc_resource_type_t *module_type, *map_type, *map_iter_type, *program_type;
- static uc_value_t *registry;
- static uc_vm_t *debug_vm;
- static struct {
- int code;
- char *msg;
- } last_error;
- struct uc_bpf_fd {
- int fd;
- bool close;
- };
- struct uc_bpf_map {
- struct uc_bpf_fd fd; /* must be first */
- unsigned int key_size, val_size;
- };
- struct uc_bpf_map_iter {
- int fd;
- unsigned int key_size;
- bool has_next;
- uint8_t key[];
- };
- __attribute__((format(printf, 2, 3))) static void
- set_error(int errcode, const char *fmt, ...)
- {
- va_list ap;
- free(last_error.msg);
- last_error.code = errcode;
- last_error.msg = NULL;
- if (fmt) {
- va_start(ap, fmt);
- xvasprintf(&last_error.msg, fmt, ap);
- va_end(ap);
- }
- }
- static void init_env(void)
- {
- static bool init_done = false;
- struct rlimit limit = {
- .rlim_cur = RLIM_INFINITY,
- .rlim_max = RLIM_INFINITY,
- };
- if (init_done)
- return;
- setrlimit(RLIMIT_MEMLOCK, &limit);
- init_done = true;
- }
- static uc_value_t *
- uc_bpf_error(uc_vm_t *vm, size_t nargs)
- {
- uc_value_t *numeric = uc_fn_arg(0);
- const char *msg = last_error.msg;
- int code = last_error.code;
- uc_stringbuf_t *buf;
- const char *s;
- if (last_error.code == 0)
- return NULL;
- set_error(0, NULL);
- if (ucv_is_truish(numeric))
- return ucv_int64_new(code);
- buf = ucv_stringbuf_new();
- if (code < 0 && msg) {
- ucv_stringbuf_addstr(buf, msg, strlen(msg));
- } else {
- s = strerror(code);
- ucv_stringbuf_addstr(buf, s, strlen(s));
- if (msg)
- ucv_stringbuf_printf(buf, ": %s", msg);
- }
- return ucv_stringbuf_finish(buf);
- }
- static int
- uc_bpf_module_set_opts(struct bpf_object *obj, uc_value_t *opts)
- {
- uc_value_t *val;
- if (!opts)
- return 0;
- if (ucv_type(opts) != UC_OBJECT)
- err_return_int(EINVAL, "options argument");
- if ((val = ucv_object_get(opts, "rodata", NULL)) != NULL) {
- struct bpf_map *map = NULL;
- if (ucv_type(val) != UC_STRING)
- err_return_int(EINVAL, "rodata type");
- while ((map = bpf_object__next_map(obj, map)) != NULL) {
- if (!strstr(bpf_map__name(map), ".rodata"))
- continue;
- break;
- }
- if (!map)
- err_return_int(errno, "rodata map");
- if (bpf_map__set_initial_value(map, ucv_string_get(val),
- ucv_string_length(val)))
- err_return_int(errno, "rodata");
- }
- if ((val = ucv_object_get(opts, "program-type", NULL)) != NULL) {
- if (ucv_type(val) != UC_OBJECT)
- err_return_int(EINVAL, "prog_types argument");
- ucv_object_foreach(val, name, type) {
- struct bpf_program *prog;
- if (ucv_type(type) != UC_INTEGER)
- err_return_int(EINVAL, "program %s type", name);
- prog = bpf_object__find_program_by_name(obj, name);
- if (!prog)
- err_return_int(-1, "program %s not found", name);
- bpf_program__set_type(prog, ucv_int64_get(type));
- }
- }
- return 0;
- }
- static uc_value_t *
- uc_bpf_open_module(uc_vm_t *vm, size_t nargs)
- {
- DECLARE_LIBBPF_OPTS(bpf_object_open_opts, bpf_opts);
- uc_value_t *path = uc_fn_arg(0);
- uc_value_t *opts = uc_fn_arg(1);
- struct bpf_object *obj;
- if (ucv_type(path) != UC_STRING)
- err_return(EINVAL, "module path");
- init_env();
- obj = bpf_object__open_file(ucv_string_get(path), &bpf_opts);
- if (libbpf_get_error(obj))
- err_return(errno, NULL);
- if (uc_bpf_module_set_opts(obj, opts)) {
- bpf_object__close(obj);
- return NULL;
- }
- if (bpf_object__load(obj)) {
- bpf_object__close(obj);
- err_return(errno, NULL);
- }
- return uc_resource_new(module_type, obj);
- }
- static uc_value_t *
- uc_bpf_map_create(int fd, unsigned int key_size, unsigned int val_size, bool close)
- {
- struct uc_bpf_map *uc_map;
- uc_map = xalloc(sizeof(*uc_map));
- uc_map->fd.fd = fd;
- uc_map->key_size = key_size;
- uc_map->val_size = val_size;
- uc_map->fd.close = close;
- return uc_resource_new(map_type, uc_map);
- }
- static uc_value_t *
- uc_bpf_open_map(uc_vm_t *vm, size_t nargs)
- {
- struct bpf_map_info info;
- uc_value_t *path = uc_fn_arg(0);
- __u32 len = sizeof(info);
- int err;
- int fd;
- if (ucv_type(path) != UC_STRING)
- err_return(EINVAL, "module path");
- fd = bpf_obj_get(ucv_string_get(path));
- if (fd < 0)
- err_return(errno, NULL);
- err = bpf_obj_get_info_by_fd(fd, &info, &len);
- if (err) {
- close(fd);
- err_return(errno, NULL);
- }
- return uc_bpf_map_create(fd, info.key_size, info.value_size, true);
- }
- static uc_value_t *
- uc_bpf_open_program(uc_vm_t *vm, size_t nargs)
- {
- uc_value_t *path = uc_fn_arg(0);
- struct uc_bpf_fd *f;
- int fd;
- if (ucv_type(path) != UC_STRING)
- err_return(EINVAL, "module path");
- fd = bpf_obj_get(ucv_string_get(path));
- if (fd < 0)
- err_return(errno, NULL);
- f = xalloc(sizeof(*f));
- f->fd = fd;
- f->close = true;
- return uc_resource_new(program_type, f);
- }
- static uc_value_t *
- uc_bpf_module_get_maps(uc_vm_t *vm, size_t nargs)
- {
- struct bpf_object *obj = uc_fn_thisval("bpf.module");
- struct bpf_map *map = NULL;
- uc_value_t *rv;
- int i = 0;
- if (!obj)
- err_return(EINVAL, NULL);
- rv = ucv_array_new(vm);
- bpf_object__for_each_map(map, obj)
- ucv_array_set(rv, i++, ucv_string_new(bpf_map__name(map)));
- return rv;
- }
- static uc_value_t *
- uc_bpf_module_get_map(uc_vm_t *vm, size_t nargs)
- {
- struct bpf_object *obj = uc_fn_thisval("bpf.module");
- struct bpf_map *map;
- uc_value_t *name = uc_fn_arg(0);
- int fd;
- if (!obj || ucv_type(name) != UC_STRING)
- err_return(EINVAL, NULL);
- map = bpf_object__find_map_by_name(obj, ucv_string_get(name));
- if (!map)
- err_return(errno, NULL);
- fd = bpf_map__fd(map);
- if (fd < 0)
- err_return(EINVAL, NULL);
- return uc_bpf_map_create(fd, bpf_map__key_size(map), bpf_map__value_size(map), false);
- }
- static uc_value_t *
- uc_bpf_module_get_programs(uc_vm_t *vm, size_t nargs)
- {
- struct bpf_object *obj = uc_fn_thisval("bpf.module");
- struct bpf_program *prog = NULL;
- uc_value_t *rv;
- int i = 0;
- if (!obj)
- err_return(EINVAL, NULL);
- rv = ucv_array_new(vm);
- bpf_object__for_each_program(prog, obj)
- ucv_array_set(rv, i++, ucv_string_new(bpf_program__name(prog)));
- return rv;
- }
- static uc_value_t *
- uc_bpf_module_get_program(uc_vm_t *vm, size_t nargs)
- {
- struct bpf_object *obj = uc_fn_thisval("bpf.module");
- struct bpf_program *prog;
- uc_value_t *name = uc_fn_arg(0);
- struct uc_bpf_fd *f;
- int fd;
- if (!obj || !name || ucv_type(name) != UC_STRING)
- err_return(EINVAL, NULL);
- prog = bpf_object__find_program_by_name(obj, ucv_string_get(name));
- if (!prog)
- err_return(errno, NULL);
- fd = bpf_program__fd(prog);
- if (fd < 0)
- err_return(EINVAL, NULL);
- f = xalloc(sizeof(*f));
- f->fd = fd;
- return uc_resource_new(program_type, f);
- }
- static void *
- uc_bpf_map_arg(uc_value_t *val, const char *kind, unsigned int size)
- {
- static union {
- uint32_t u32;
- uint64_t u64;
- } val_int;
- switch (ucv_type(val)) {
- case UC_INTEGER:
- if (size == 4)
- val_int.u32 = ucv_int64_get(val);
- else if (size == 8)
- val_int.u64 = ucv_int64_get(val);
- else
- break;
- return &val_int;
- case UC_STRING:
- if (size != ucv_string_length(val))
- break;
- return ucv_string_get(val);
- default:
- err_return(EINVAL, "%s type", kind);
- }
- err_return(EINVAL, "%s size mismatch (expected: %d)", kind, size);
- }
- static uc_value_t *
- uc_bpf_map_get(uc_vm_t *vm, size_t nargs)
- {
- struct uc_bpf_map *map = uc_fn_thisval("bpf.map");
- uc_value_t *a_key = uc_fn_arg(0);
- void *key, *val;
- if (!map)
- err_return(EINVAL, NULL);
- key = uc_bpf_map_arg(a_key, "key", map->key_size);
- if (!key)
- return NULL;
- val = alloca(map->val_size);
- if (bpf_map_lookup_elem(map->fd.fd, key, val))
- return NULL;
- return ucv_string_new_length(val, map->val_size);
- }
- static uc_value_t *
- uc_bpf_map_set(uc_vm_t *vm, size_t nargs)
- {
- struct uc_bpf_map *map = uc_fn_thisval("bpf.map");
- uc_value_t *a_key = uc_fn_arg(0);
- uc_value_t *a_val = uc_fn_arg(1);
- uc_value_t *a_flags = uc_fn_arg(2);
- uint64_t flags;
- void *key, *val;
- if (!map)
- err_return(EINVAL, NULL);
- key = uc_bpf_map_arg(a_key, "key", map->key_size);
- if (!key)
- return NULL;
- val = uc_bpf_map_arg(a_val, "value", map->val_size);
- if (!val)
- return NULL;
- if (!a_flags)
- flags = BPF_ANY;
- else if (ucv_type(a_flags) != UC_INTEGER)
- err_return(EINVAL, "flags");
- else
- flags = ucv_int64_get(a_flags);
- if (bpf_map_update_elem(map->fd.fd, key, val, flags))
- return NULL;
- return ucv_string_new_length(val, map->val_size);
- }
- static uc_value_t *
- uc_bpf_map_delete(uc_vm_t *vm, size_t nargs)
- {
- struct uc_bpf_map *map = uc_fn_thisval("bpf.map");
- uc_value_t *a_key = uc_fn_arg(0);
- uc_value_t *a_return = uc_fn_arg(1);
- void *key, *val = NULL;
- int ret;
- if (!map)
- err_return(EINVAL, NULL);
- key = uc_bpf_map_arg(a_key, "key", map->key_size);
- if (!key)
- return NULL;
- if (!ucv_is_truish(a_return)) {
- ret = bpf_map_delete_elem(map->fd.fd, key);
- return ucv_boolean_new(ret == 0);
- }
- val = alloca(map->val_size);
- if (bpf_map_lookup_and_delete_elem(map->fd.fd, key, val))
- return NULL;
- return ucv_string_new_length(val, map->val_size);
- }
- static uc_value_t *
- uc_bpf_map_delete_all(uc_vm_t *vm, size_t nargs)
- {
- struct uc_bpf_map *map = uc_fn_thisval("bpf.map");
- uc_value_t *filter = uc_fn_arg(0);
- bool has_next;
- void *key, *next;
- if (!map)
- err_return(EINVAL, NULL);
- key = alloca(map->key_size);
- next = alloca(map->key_size);
- has_next = !bpf_map_get_next_key(map->fd.fd, NULL, next);
- while (has_next) {
- bool skip = false;
- memcpy(key, next, map->key_size);
- has_next = !bpf_map_get_next_key(map->fd.fd, next, next);
- if (ucv_is_callable(filter)) {
- uc_value_t *rv;
- uc_value_push(ucv_get(filter));
- uc_value_push(ucv_string_new_length((const char *)key, map->key_size));
- if (uc_call(1) != EXCEPTION_NONE)
- break;
- rv = uc_vm_stack_pop(vm);
- if (!rv)
- break;
- skip = !ucv_is_truish(rv);
- ucv_put(rv);
- }
- if (!skip)
- bpf_map_delete_elem(map->fd.fd, key);
- }
- return TRUE;
- }
- static uc_value_t *
- uc_bpf_map_iterator(uc_vm_t *vm, size_t nargs)
- {
- struct uc_bpf_map *map = uc_fn_thisval("bpf.map");
- struct uc_bpf_map_iter *iter;
- if (!map)
- err_return(EINVAL, NULL);
- iter = xalloc(sizeof(*iter) + map->key_size);
- iter->fd = map->fd.fd;
- iter->key_size = map->key_size;
- iter->has_next = !bpf_map_get_next_key(iter->fd, NULL, &iter->key);
- return uc_resource_new(map_iter_type, iter);
- }
- static uc_value_t *
- uc_bpf_map_iter_next(uc_vm_t *vm, size_t nargs)
- {
- struct uc_bpf_map_iter *iter = uc_fn_thisval("bpf.map_iter");
- uc_value_t *rv;
- if (!iter->has_next)
- return NULL;
- rv = ucv_string_new_length((const char *)iter->key, iter->key_size);
- iter->has_next = !bpf_map_get_next_key(iter->fd, &iter->key, &iter->key);
- return rv;
- }
- static uc_value_t *
- uc_bpf_map_iter_next_int(uc_vm_t *vm, size_t nargs)
- {
- struct uc_bpf_map_iter *iter = uc_fn_thisval("bpf.map_iter");
- uint64_t intval;
- uc_value_t *rv;
- if (!iter->has_next)
- return NULL;
- if (iter->key_size == 4)
- intval = *(uint32_t *)iter->key;
- else if (iter->key_size == 8)
- intval = *(uint64_t *)iter->key;
- else
- return NULL;
- rv = ucv_int64_new(intval);
- iter->has_next = !bpf_map_get_next_key(iter->fd, &iter->key, &iter->key);
- return rv;
- }
- static uc_value_t *
- uc_bpf_map_foreach(uc_vm_t *vm, size_t nargs)
- {
- struct uc_bpf_map *map = uc_fn_thisval("bpf.map");
- uc_value_t *func = uc_fn_arg(0);
- bool has_next;
- void *key, *next;
- bool ret = false;
- key = alloca(map->key_size);
- next = alloca(map->key_size);
- has_next = !bpf_map_get_next_key(map->fd.fd, NULL, next);
- while (has_next) {
- uc_value_t *rv;
- bool stop;
- memcpy(key, next, map->key_size);
- has_next = !bpf_map_get_next_key(map->fd.fd, next, next);
- uc_value_push(ucv_get(func));
- uc_value_push(ucv_string_new_length((const char *)key, map->key_size));
- if (uc_call(1) != EXCEPTION_NONE)
- break;
- rv = uc_vm_stack_pop(vm);
- stop = (ucv_type(rv) == UC_BOOLEAN && !ucv_boolean_get(rv));
- ucv_put(rv);
- if (stop)
- break;
- ret = true;
- }
- return ucv_boolean_new(ret);
- }
- static uc_value_t *
- uc_bpf_obj_pin(uc_vm_t *vm, size_t nargs, const char *type)
- {
- struct uc_bpf_fd *f = uc_fn_thisval(type);
- uc_value_t *path = uc_fn_arg(0);
- if (ucv_type(path) != UC_STRING)
- err_return(EINVAL, NULL);
- if (bpf_obj_pin(f->fd, ucv_string_get(path)))
- err_return(errno, NULL);
- return TRUE;
- }
- static uc_value_t *
- uc_bpf_program_pin(uc_vm_t *vm, size_t nargs)
- {
- return uc_bpf_obj_pin(vm, nargs, "bpf.program");
- }
- static uc_value_t *
- uc_bpf_map_pin(uc_vm_t *vm, size_t nargs)
- {
- return uc_bpf_obj_pin(vm, nargs, "bpf.map");
- }
- static uc_value_t *
- uc_bpf_set_tc_hook(uc_value_t *ifname, uc_value_t *type, uc_value_t *prio,
- int fd)
- {
- DECLARE_LIBBPF_OPTS(bpf_tc_hook, hook);
- DECLARE_LIBBPF_OPTS(bpf_tc_opts, attach_tc,
- .handle = 1);
- const char *type_str;
- uint64_t prio_val;
- if (ucv_type(ifname) != UC_STRING || ucv_type(type) != UC_STRING ||
- ucv_type(prio) != UC_INTEGER)
- err_return(EINVAL, NULL);
- prio_val = ucv_int64_get(prio);
- if (prio_val > 0xffff)
- err_return(EINVAL, NULL);
- type_str = ucv_string_get(type);
- if (!strcmp(type_str, "ingress"))
- hook.attach_point = BPF_TC_INGRESS;
- else if (!strcmp(type_str, "egress"))
- hook.attach_point = BPF_TC_EGRESS;
- else
- err_return(EINVAL, NULL);
- hook.ifindex = if_nametoindex(ucv_string_get(ifname));
- if (!hook.ifindex)
- goto error;
- bpf_tc_hook_create(&hook);
- attach_tc.priority = prio_val;
- if (bpf_tc_detach(&hook, &attach_tc) < 0 && fd < 0)
- goto error;
- if (fd < 0)
- goto out;
- attach_tc.prog_fd = fd;
- if (bpf_tc_attach(&hook, &attach_tc) < 0)
- goto error;
- out:
- return TRUE;
- error:
- if (fd >= 0)
- err_return(ENOENT, NULL);
- return NULL;
- }
- static uc_value_t *
- uc_bpf_program_tc_attach(uc_vm_t *vm, size_t nargs)
- {
- struct uc_bpf_fd *f = uc_fn_thisval("bpf.program");
- uc_value_t *ifname = uc_fn_arg(0);
- uc_value_t *type = uc_fn_arg(1);
- uc_value_t *prio = uc_fn_arg(2);
- if (!f)
- err_return(EINVAL, NULL);
- return uc_bpf_set_tc_hook(ifname, type, prio, f->fd);
- }
- static uc_value_t *
- uc_bpf_tc_detach(uc_vm_t *vm, size_t nargs)
- {
- uc_value_t *ifname = uc_fn_arg(0);
- uc_value_t *type = uc_fn_arg(1);
- uc_value_t *prio = uc_fn_arg(2);
- return uc_bpf_set_tc_hook(ifname, type, prio, -1);
- }
- static int
- uc_bpf_debug_print(enum libbpf_print_level level, const char *format,
- va_list args)
- {
- char buf[256], *str = NULL;
- uc_value_t *val;
- va_list ap;
- int size;
- va_copy(ap, args);
- size = vsnprintf(buf, sizeof(buf), format, ap);
- va_end(ap);
- if (size > 0 && (unsigned long)size < ARRAY_SIZE(buf) - 1) {
- val = ucv_string_new(buf);
- goto out;
- }
- if (vasprintf(&str, format, args) < 0)
- return 0;
- val = ucv_string_new(str);
- free(str);
- out:
- uc_vm_stack_push(debug_vm, ucv_get(ucv_array_get(registry, 0)));
- uc_vm_stack_push(debug_vm, ucv_int64_new(level));
- uc_vm_stack_push(debug_vm, val);
- if (uc_vm_call(debug_vm, false, 2) == EXCEPTION_NONE)
- ucv_put(uc_vm_stack_pop(debug_vm));
- return 0;
- }
- static uc_value_t *
- uc_bpf_set_debug_handler(uc_vm_t *vm, size_t nargs)
- {
- uc_value_t *handler = uc_fn_arg(0);
- if (handler && !ucv_is_callable(handler))
- err_return(EINVAL, NULL);
- debug_vm = vm;
- libbpf_set_print(handler ? uc_bpf_debug_print : NULL);
- ucv_array_set(registry, 0, ucv_get(handler));
- return NULL;
- }
- static void
- register_constants(uc_vm_t *vm, uc_value_t *scope)
- {
- #define ADD_CONST(x) ucv_object_add(scope, #x, ucv_int64_new(x))
- ADD_CONST(BPF_PROG_TYPE_SCHED_CLS);
- ADD_CONST(BPF_PROG_TYPE_SCHED_ACT);
- ADD_CONST(BPF_ANY);
- ADD_CONST(BPF_NOEXIST);
- ADD_CONST(BPF_EXIST);
- ADD_CONST(BPF_F_LOCK);
- }
- static const uc_function_list_t module_fns[] = {
- { "get_map", uc_bpf_module_get_map },
- { "get_maps", uc_bpf_module_get_maps },
- { "get_programs", uc_bpf_module_get_programs },
- { "get_program", uc_bpf_module_get_program },
- };
- static void module_free(void *ptr)
- {
- struct bpf_object *obj = ptr;
- bpf_object__close(obj);
- }
- static const uc_function_list_t map_fns[] = {
- { "pin", uc_bpf_map_pin },
- { "get", uc_bpf_map_get },
- { "set", uc_bpf_map_set },
- { "delete", uc_bpf_map_delete },
- { "delete_all", uc_bpf_map_delete_all },
- { "foreach", uc_bpf_map_foreach },
- { "iterator", uc_bpf_map_iterator },
- };
- static void uc_bpf_fd_free(void *ptr)
- {
- struct uc_bpf_fd *f = ptr;
- if (f->close)
- close(f->fd);
- free(f);
- }
- static const uc_function_list_t map_iter_fns[] = {
- { "next", uc_bpf_map_iter_next },
- { "next_int", uc_bpf_map_iter_next_int },
- };
- static const uc_function_list_t prog_fns[] = {
- { "pin", uc_bpf_program_pin },
- { "tc_attach", uc_bpf_program_tc_attach },
- };
- static const uc_function_list_t global_fns[] = {
- { "error", uc_bpf_error },
- { "set_debug_handler", uc_bpf_set_debug_handler },
- { "open_module", uc_bpf_open_module },
- { "open_map", uc_bpf_open_map },
- { "open_program", uc_bpf_open_program },
- { "tc_detach", uc_bpf_tc_detach },
- };
- void uc_module_init(uc_vm_t *vm, uc_value_t *scope)
- {
- uc_function_list_register(scope, global_fns);
- register_constants(vm, scope);
- registry = ucv_array_new(vm);
- uc_vm_registry_set(vm, "bpf.registry", registry);
- module_type = uc_type_declare(vm, "bpf.module", module_fns, module_free);
- map_type = uc_type_declare(vm, "bpf.map", map_fns, uc_bpf_fd_free);
- map_iter_type = uc_type_declare(vm, "bpf.map_iter", map_iter_fns, free);
- program_type = uc_type_declare(vm, "bpf.program", prog_fns, uc_bpf_fd_free);
- }
|