1 #include <sys/resource.h>
3 #include <sys/socket.h>
12 #include <bpf/libbpf.h>
14 #include "ucode/module.h"
16 #define err_return_int(err, ...) do { set_error(err, __VA_ARGS__); return -1; } while(0)
17 #define err_return(err, ...) do { set_error(err, __VA_ARGS__); return NULL; } while(0)
18 #define TRUE ucv_boolean_new(true)
20 static uc_resource_type_t
*module_type
, *map_type
, *map_iter_type
, *program_type
;
21 static uc_value_t
*registry
;
22 static uc_vm_t
*debug_vm
;
35 struct uc_bpf_fd fd
; /* must be first */
36 unsigned int key_size
, val_size
;
39 struct uc_bpf_map_iter
{
41 unsigned int key_size
;
46 __attribute__((format(printf
, 2, 3))) static void
47 set_error(int errcode
, const char *fmt
, ...)
53 last_error
.code
= errcode
;
54 last_error
.msg
= NULL
;
58 xvasprintf(&last_error
.msg
, fmt
, ap
);
63 static void init_env(void)
65 static bool init_done
= false;
66 struct rlimit limit
= {
67 .rlim_cur
= RLIM_INFINITY
,
68 .rlim_max
= RLIM_INFINITY
,
74 setrlimit(RLIMIT_MEMLOCK
, &limit
);
79 uc_bpf_error(uc_vm_t
*vm
, size_t nargs
)
81 uc_value_t
*numeric
= uc_fn_arg(0);
82 const char *msg
= last_error
.msg
;
83 int code
= last_error
.code
;
87 if (last_error
.code
== 0)
92 if (ucv_is_truish(numeric
))
93 return ucv_int64_new(code
);
95 buf
= ucv_stringbuf_new();
96 if (code
< 0 && msg
) {
97 ucv_stringbuf_addstr(buf
, msg
, strlen(msg
));
100 ucv_stringbuf_addstr(buf
, s
, strlen(s
));
102 ucv_stringbuf_printf(buf
, ": %s", msg
);
105 return ucv_stringbuf_finish(buf
);
109 uc_bpf_module_set_opts(struct bpf_object
*obj
, uc_value_t
*opts
)
116 if (ucv_type(opts
) != UC_OBJECT
)
117 err_return_int(EINVAL
, "options argument");
119 if ((val
= ucv_object_get(opts
, "rodata", NULL
)) != NULL
) {
120 struct bpf_map
*map
= NULL
;
122 if (ucv_type(val
) != UC_STRING
)
123 err_return_int(EINVAL
, "rodata type");
125 while ((map
= bpf_object__next_map(obj
, map
)) != NULL
) {
126 if (!strstr(bpf_map__name(map
), ".rodata"))
133 err_return_int(errno
, "rodata map");
135 if (bpf_map__set_initial_value(map
, ucv_string_get(val
),
136 ucv_string_length(val
)))
137 err_return_int(errno
, "rodata");
140 if ((val
= ucv_object_get(opts
, "program-type", NULL
)) != NULL
) {
141 if (ucv_type(val
) != UC_OBJECT
)
142 err_return_int(EINVAL
, "prog_types argument");
144 ucv_object_foreach(val
, name
, type
) {
145 struct bpf_program
*prog
;
147 if (ucv_type(type
) != UC_INTEGER
)
148 err_return_int(EINVAL
, "program %s type", name
);
150 prog
= bpf_object__find_program_by_name(obj
, name
);
152 err_return_int(-1, "program %s not found", name
);
154 bpf_program__set_type(prog
, ucv_int64_get(type
));
162 uc_bpf_open_module(uc_vm_t
*vm
, size_t nargs
)
164 DECLARE_LIBBPF_OPTS(bpf_object_open_opts
, bpf_opts
);
165 uc_value_t
*path
= uc_fn_arg(0);
166 uc_value_t
*opts
= uc_fn_arg(1);
167 struct bpf_object
*obj
;
169 if (ucv_type(path
) != UC_STRING
)
170 err_return(EINVAL
, "module path");
173 obj
= bpf_object__open_file(ucv_string_get(path
), &bpf_opts
);
174 if (libbpf_get_error(obj
))
175 err_return(errno
, NULL
);
177 if (uc_bpf_module_set_opts(obj
, opts
)) {
178 bpf_object__close(obj
);
182 if (bpf_object__load(obj
)) {
183 bpf_object__close(obj
);
184 err_return(errno
, NULL
);
187 return uc_resource_new(module_type
, obj
);
191 uc_bpf_map_create(int fd
, unsigned int key_size
, unsigned int val_size
, bool close
)
193 struct uc_bpf_map
*uc_map
;
195 uc_map
= xalloc(sizeof(*uc_map
));
197 uc_map
->key_size
= key_size
;
198 uc_map
->val_size
= val_size
;
199 uc_map
->fd
.close
= close
;
201 return uc_resource_new(map_type
, uc_map
);
205 uc_bpf_open_map(uc_vm_t
*vm
, size_t nargs
)
207 struct bpf_map_info info
;
208 uc_value_t
*path
= uc_fn_arg(0);
209 __u32 len
= sizeof(info
);
213 if (ucv_type(path
) != UC_STRING
)
214 err_return(EINVAL
, "module path");
216 fd
= bpf_obj_get(ucv_string_get(path
));
218 err_return(errno
, NULL
);
220 err
= bpf_obj_get_info_by_fd(fd
, &info
, &len
);
223 err_return(errno
, NULL
);
226 return uc_bpf_map_create(fd
, info
.key_size
, info
.value_size
, true);
230 uc_bpf_open_program(uc_vm_t
*vm
, size_t nargs
)
232 uc_value_t
*path
= uc_fn_arg(0);
236 if (ucv_type(path
) != UC_STRING
)
237 err_return(EINVAL
, "module path");
239 fd
= bpf_obj_get(ucv_string_get(path
));
241 err_return(errno
, NULL
);
243 f
= xalloc(sizeof(*f
));
247 return uc_resource_new(program_type
, f
);
251 uc_bpf_module_get_maps(uc_vm_t
*vm
, size_t nargs
)
253 struct bpf_object
*obj
= uc_fn_thisval("bpf.module");
254 struct bpf_map
*map
= NULL
;
259 err_return(EINVAL
, NULL
);
261 rv
= ucv_array_new(vm
);
262 bpf_object__for_each_map(map
, obj
)
263 ucv_array_set(rv
, i
++, ucv_string_new(bpf_map__name(map
)));
269 uc_bpf_module_get_map(uc_vm_t
*vm
, size_t nargs
)
271 struct bpf_object
*obj
= uc_fn_thisval("bpf.module");
273 uc_value_t
*name
= uc_fn_arg(0);
276 if (!obj
|| ucv_type(name
) != UC_STRING
)
277 err_return(EINVAL
, NULL
);
279 map
= bpf_object__find_map_by_name(obj
, ucv_string_get(name
));
281 err_return(errno
, NULL
);
283 fd
= bpf_map__fd(map
);
285 err_return(EINVAL
, NULL
);
287 return uc_bpf_map_create(fd
, bpf_map__key_size(map
), bpf_map__value_size(map
), false);
291 uc_bpf_module_get_programs(uc_vm_t
*vm
, size_t nargs
)
293 struct bpf_object
*obj
= uc_fn_thisval("bpf.module");
294 struct bpf_program
*prog
= NULL
;
299 err_return(EINVAL
, NULL
);
301 rv
= ucv_array_new(vm
);
302 bpf_object__for_each_program(prog
, obj
)
303 ucv_array_set(rv
, i
++, ucv_string_new(bpf_program__name(prog
)));
309 uc_bpf_module_get_program(uc_vm_t
*vm
, size_t nargs
)
311 struct bpf_object
*obj
= uc_fn_thisval("bpf.module");
312 struct bpf_program
*prog
;
313 uc_value_t
*name
= uc_fn_arg(0);
317 if (!obj
|| !name
|| ucv_type(name
) != UC_STRING
)
318 err_return(EINVAL
, NULL
);
320 prog
= bpf_object__find_program_by_name(obj
, ucv_string_get(name
));
322 err_return(errno
, NULL
);
324 fd
= bpf_program__fd(prog
);
326 err_return(EINVAL
, NULL
);
328 f
= xalloc(sizeof(*f
));
331 return uc_resource_new(program_type
, f
);
335 uc_bpf_map_arg(uc_value_t
*val
, const char *kind
, unsigned int size
)
342 switch (ucv_type(val
)) {
345 val_int
.u32
= ucv_int64_get(val
);
347 val_int
.u64
= ucv_int64_get(val
);
353 if (size
!= ucv_string_length(val
))
356 return ucv_string_get(val
);
358 err_return(EINVAL
, "%s type", kind
);
361 err_return(EINVAL
, "%s size mismatch (expected: %d)", kind
, size
);
365 uc_bpf_map_get(uc_vm_t
*vm
, size_t nargs
)
367 struct uc_bpf_map
*map
= uc_fn_thisval("bpf.map");
368 uc_value_t
*a_key
= uc_fn_arg(0);
372 err_return(EINVAL
, NULL
);
374 key
= uc_bpf_map_arg(a_key
, "key", map
->key_size
);
378 val
= alloca(map
->val_size
);
379 if (bpf_map_lookup_elem(map
->fd
.fd
, key
, val
))
382 return ucv_string_new_length(val
, map
->val_size
);
386 uc_bpf_map_set(uc_vm_t
*vm
, size_t nargs
)
388 struct uc_bpf_map
*map
= uc_fn_thisval("bpf.map");
389 uc_value_t
*a_key
= uc_fn_arg(0);
390 uc_value_t
*a_val
= uc_fn_arg(1);
391 uc_value_t
*a_flags
= uc_fn_arg(2);
396 err_return(EINVAL
, NULL
);
398 key
= uc_bpf_map_arg(a_key
, "key", map
->key_size
);
402 val
= uc_bpf_map_arg(a_val
, "value", map
->val_size
);
408 else if (ucv_type(a_flags
) != UC_INTEGER
)
409 err_return(EINVAL
, "flags");
411 flags
= ucv_int64_get(a_flags
);
413 if (bpf_map_update_elem(map
->fd
.fd
, key
, val
, flags
))
416 return ucv_string_new_length(val
, map
->val_size
);
420 uc_bpf_map_delete(uc_vm_t
*vm
, size_t nargs
)
422 struct uc_bpf_map
*map
= uc_fn_thisval("bpf.map");
423 uc_value_t
*a_key
= uc_fn_arg(0);
424 uc_value_t
*a_return
= uc_fn_arg(1);
425 void *key
, *val
= NULL
;
429 err_return(EINVAL
, NULL
);
431 key
= uc_bpf_map_arg(a_key
, "key", map
->key_size
);
435 if (!ucv_is_truish(a_return
)) {
436 ret
= bpf_map_delete_elem(map
->fd
.fd
, key
);
438 return ucv_boolean_new(ret
== 0);
441 val
= alloca(map
->val_size
);
442 if (bpf_map_lookup_and_delete_elem(map
->fd
.fd
, key
, val
))
445 return ucv_string_new_length(val
, map
->val_size
);
449 uc_bpf_map_delete_all(uc_vm_t
*vm
, size_t nargs
)
451 struct uc_bpf_map
*map
= uc_fn_thisval("bpf.map");
452 uc_value_t
*filter
= uc_fn_arg(0);
457 err_return(EINVAL
, NULL
);
459 key
= alloca(map
->key_size
);
460 next
= alloca(map
->key_size
);
461 has_next
= !bpf_map_get_next_key(map
->fd
.fd
, NULL
, next
);
465 memcpy(key
, next
, map
->key_size
);
466 has_next
= !bpf_map_get_next_key(map
->fd
.fd
, next
, next
);
468 if (ucv_is_callable(filter
)) {
471 uc_value_push(ucv_get(filter
));
472 uc_value_push(ucv_string_new_length((const char *)key
, map
->key_size
));
473 if (uc_call(1) != EXCEPTION_NONE
)
476 rv
= uc_vm_stack_pop(vm
);
480 skip
= !ucv_is_truish(rv
);
485 bpf_map_delete_elem(map
->fd
.fd
, key
);
492 uc_bpf_map_iterator(uc_vm_t
*vm
, size_t nargs
)
494 struct uc_bpf_map
*map
= uc_fn_thisval("bpf.map");
495 struct uc_bpf_map_iter
*iter
;
498 err_return(EINVAL
, NULL
);
500 iter
= xalloc(sizeof(*iter
) + map
->key_size
);
501 iter
->fd
= map
->fd
.fd
;
502 iter
->key_size
= map
->key_size
;
503 iter
->has_next
= !bpf_map_get_next_key(iter
->fd
, NULL
, &iter
->key
);
505 return uc_resource_new(map_iter_type
, iter
);
509 uc_bpf_map_iter_next(uc_vm_t
*vm
, size_t nargs
)
511 struct uc_bpf_map_iter
*iter
= uc_fn_thisval("bpf.map_iter");
517 rv
= ucv_string_new_length((const char *)iter
->key
, iter
->key_size
);
518 iter
->has_next
= !bpf_map_get_next_key(iter
->fd
, &iter
->key
, &iter
->key
);
524 uc_bpf_map_iter_next_int(uc_vm_t
*vm
, size_t nargs
)
526 struct uc_bpf_map_iter
*iter
= uc_fn_thisval("bpf.map_iter");
533 if (iter
->key_size
== 4)
534 intval
= *(uint32_t *)iter
->key
;
535 else if (iter
->key_size
== 8)
536 intval
= *(uint64_t *)iter
->key
;
540 rv
= ucv_int64_new(intval
);
541 iter
->has_next
= !bpf_map_get_next_key(iter
->fd
, &iter
->key
, &iter
->key
);
547 uc_bpf_map_foreach(uc_vm_t
*vm
, size_t nargs
)
549 struct uc_bpf_map
*map
= uc_fn_thisval("bpf.map");
550 uc_value_t
*func
= uc_fn_arg(0);
555 key
= alloca(map
->key_size
);
556 next
= alloca(map
->key_size
);
557 has_next
= !bpf_map_get_next_key(map
->fd
.fd
, NULL
, next
);
563 memcpy(key
, next
, map
->key_size
);
564 has_next
= !bpf_map_get_next_key(map
->fd
.fd
, next
, next
);
566 uc_value_push(ucv_get(func
));
567 uc_value_push(ucv_string_new_length((const char *)key
, map
->key_size
));
569 if (uc_call(1) != EXCEPTION_NONE
)
572 rv
= uc_vm_stack_pop(vm
);
573 stop
= (ucv_type(rv
) == UC_BOOLEAN
&& !ucv_boolean_get(rv
));
582 return ucv_boolean_new(ret
);
586 uc_bpf_obj_pin(uc_vm_t
*vm
, size_t nargs
, const char *type
)
588 struct uc_bpf_fd
*f
= uc_fn_thisval(type
);
589 uc_value_t
*path
= uc_fn_arg(0);
591 if (ucv_type(path
) != UC_STRING
)
592 err_return(EINVAL
, NULL
);
594 if (bpf_obj_pin(f
->fd
, ucv_string_get(path
)))
595 err_return(errno
, NULL
);
601 uc_bpf_program_pin(uc_vm_t
*vm
, size_t nargs
)
603 return uc_bpf_obj_pin(vm
, nargs
, "bpf.program");
607 uc_bpf_map_pin(uc_vm_t
*vm
, size_t nargs
)
609 return uc_bpf_obj_pin(vm
, nargs
, "bpf.map");
613 uc_bpf_set_tc_hook(uc_value_t
*ifname
, uc_value_t
*type
, uc_value_t
*prio
,
616 DECLARE_LIBBPF_OPTS(bpf_tc_hook
, hook
);
617 DECLARE_LIBBPF_OPTS(bpf_tc_opts
, attach_tc
,
619 const char *type_str
;
622 if (ucv_type(ifname
) != UC_STRING
|| ucv_type(type
) != UC_STRING
||
623 ucv_type(prio
) != UC_INTEGER
)
624 err_return(EINVAL
, NULL
);
626 prio_val
= ucv_int64_get(prio
);
627 if (prio_val
> 0xffff)
628 err_return(EINVAL
, NULL
);
630 type_str
= ucv_string_get(type
);
631 if (!strcmp(type_str
, "ingress"))
632 hook
.attach_point
= BPF_TC_INGRESS
;
633 else if (!strcmp(type_str
, "egress"))
634 hook
.attach_point
= BPF_TC_EGRESS
;
636 err_return(EINVAL
, NULL
);
638 hook
.ifindex
= if_nametoindex(ucv_string_get(ifname
));
642 bpf_tc_hook_create(&hook
);
643 attach_tc
.priority
= prio_val
;
644 if (bpf_tc_detach(&hook
, &attach_tc
) < 0 && fd
< 0)
650 attach_tc
.prog_fd
= fd
;
651 if (bpf_tc_attach(&hook
, &attach_tc
) < 0)
659 err_return(ENOENT
, NULL
);
664 uc_bpf_program_tc_attach(uc_vm_t
*vm
, size_t nargs
)
666 struct uc_bpf_fd
*f
= uc_fn_thisval("bpf.program");
667 uc_value_t
*ifname
= uc_fn_arg(0);
668 uc_value_t
*type
= uc_fn_arg(1);
669 uc_value_t
*prio
= uc_fn_arg(2);
672 err_return(EINVAL
, NULL
);
674 return uc_bpf_set_tc_hook(ifname
, type
, prio
, f
->fd
);
678 uc_bpf_tc_detach(uc_vm_t
*vm
, size_t nargs
)
680 uc_value_t
*ifname
= uc_fn_arg(0);
681 uc_value_t
*type
= uc_fn_arg(1);
682 uc_value_t
*prio
= uc_fn_arg(2);
684 return uc_bpf_set_tc_hook(ifname
, type
, prio
, -1);
688 uc_bpf_debug_print(enum libbpf_print_level level
, const char *format
,
691 char buf
[256], *str
= NULL
;
697 size
= vsnprintf(buf
, sizeof(buf
), format
, ap
);
700 if (size
> 0 && (unsigned long)size
< ARRAY_SIZE(buf
) - 1) {
701 val
= ucv_string_new(buf
);
705 if (vasprintf(&str
, format
, args
) < 0)
708 val
= ucv_string_new(str
);
712 uc_vm_stack_push(debug_vm
, ucv_get(ucv_array_get(registry
, 0)));
713 uc_vm_stack_push(debug_vm
, ucv_int64_new(level
));
714 uc_vm_stack_push(debug_vm
, val
);
715 if (uc_vm_call(debug_vm
, false, 2) == EXCEPTION_NONE
)
716 ucv_put(uc_vm_stack_pop(debug_vm
));
722 uc_bpf_set_debug_handler(uc_vm_t
*vm
, size_t nargs
)
724 uc_value_t
*handler
= uc_fn_arg(0);
726 if (handler
&& !ucv_is_callable(handler
))
727 err_return(EINVAL
, NULL
);
730 libbpf_set_print(handler
? uc_bpf_debug_print
: NULL
);
732 ucv_array_set(registry
, 0, ucv_get(handler
));
738 register_constants(uc_vm_t
*vm
, uc_value_t
*scope
)
740 #define ADD_CONST(x) ucv_object_add(scope, #x, ucv_int64_new(x))
741 ADD_CONST(BPF_PROG_TYPE_SCHED_CLS
);
742 ADD_CONST(BPF_PROG_TYPE_SCHED_ACT
);
745 ADD_CONST(BPF_NOEXIST
);
746 ADD_CONST(BPF_EXIST
);
747 ADD_CONST(BPF_F_LOCK
);
750 static const uc_function_list_t module_fns
[] = {
751 { "get_map", uc_bpf_module_get_map
},
752 { "get_maps", uc_bpf_module_get_maps
},
753 { "get_programs", uc_bpf_module_get_programs
},
754 { "get_program", uc_bpf_module_get_program
},
757 static void module_free(void *ptr
)
759 struct bpf_object
*obj
= ptr
;
761 bpf_object__close(obj
);
764 static const uc_function_list_t map_fns
[] = {
765 { "pin", uc_bpf_map_pin
},
766 { "get", uc_bpf_map_get
},
767 { "set", uc_bpf_map_set
},
768 { "delete", uc_bpf_map_delete
},
769 { "delete_all", uc_bpf_map_delete_all
},
770 { "foreach", uc_bpf_map_foreach
},
771 { "iterator", uc_bpf_map_iterator
},
774 static void uc_bpf_fd_free(void *ptr
)
776 struct uc_bpf_fd
*f
= ptr
;
783 static const uc_function_list_t map_iter_fns
[] = {
784 { "next", uc_bpf_map_iter_next
},
785 { "next_int", uc_bpf_map_iter_next_int
},
788 static const uc_function_list_t prog_fns
[] = {
789 { "pin", uc_bpf_program_pin
},
790 { "tc_attach", uc_bpf_program_tc_attach
},
793 static const uc_function_list_t global_fns
[] = {
794 { "error", uc_bpf_error
},
795 { "set_debug_handler", uc_bpf_set_debug_handler
},
796 { "open_module", uc_bpf_open_module
},
797 { "open_map", uc_bpf_open_map
},
798 { "open_program", uc_bpf_open_program
},
799 { "tc_detach", uc_bpf_tc_detach
},
802 void uc_module_init(uc_vm_t
*vm
, uc_value_t
*scope
)
804 uc_function_list_register(scope
, global_fns
);
805 register_constants(vm
, scope
);
807 registry
= ucv_array_new(vm
);
808 uc_vm_registry_set(vm
, "bpf.registry", registry
);
810 module_type
= uc_type_declare(vm
, "bpf.module", module_fns
, module_free
);
811 map_type
= uc_type_declare(vm
, "bpf.map", map_fns
, uc_bpf_fd_free
);
812 map_iter_type
= uc_type_declare(vm
, "bpf.map_iter", map_iter_fns
, free
);
813 program_type
= uc_type_declare(vm
, "bpf.program", prog_fns
, uc_bpf_fd_free
);