356 строки
8.4 KiB
C++
356 строки
8.4 KiB
C++
// Copyright (c) Microsoft Corporation
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#include "api_internal.h"
|
|
#include "bpf.h"
|
|
#include "ebpf_tracelog.h"
|
|
#include "libbpf.h"
|
|
#include "libbpf_internal.h"
|
|
|
|
// This file implements APIs in LibBPF's libbpf.h and is based on code in external/libbpf/src/libbpf.c
|
|
// used under the BSD-2-Clause license , so the coding style tries to match the libbpf.c style to
|
|
// minimize diffs until libbpf becomes cross-platform capable. This is a temporary workaround for
|
|
// issue #351 until we can compile and use libbpf.c directly.
|
|
|
|
int
|
|
bpf_map_create(
|
|
enum bpf_map_type map_type,
|
|
const char* map_name,
|
|
__u32 key_size,
|
|
__u32 value_size,
|
|
__u32 max_entries,
|
|
const struct bpf_map_create_opts* opts)
|
|
{
|
|
fd_t map_fd;
|
|
ebpf_result_t result = ebpf_map_create(map_type, map_name, key_size, value_size, max_entries, opts, &map_fd);
|
|
if (result != EBPF_SUCCESS) {
|
|
return libbpf_result_err(result);
|
|
}
|
|
return map_fd;
|
|
}
|
|
|
|
int
|
|
bpf_create_map_xattr(const struct bpf_create_map_attr* create_attr)
|
|
{
|
|
LIBBPF_OPTS(bpf_map_create_opts, p);
|
|
|
|
p.map_flags = create_attr->map_flags;
|
|
p.numa_node = create_attr->numa_node;
|
|
p.btf_fd = create_attr->btf_fd;
|
|
p.btf_key_type_id = create_attr->btf_key_type_id;
|
|
p.btf_value_type_id = create_attr->btf_value_type_id;
|
|
p.map_ifindex = create_attr->map_ifindex;
|
|
p.inner_map_fd = create_attr->inner_map_fd;
|
|
|
|
return bpf_map_create(
|
|
create_attr->map_type,
|
|
create_attr->name,
|
|
create_attr->key_size,
|
|
create_attr->value_size,
|
|
create_attr->max_entries,
|
|
&p);
|
|
}
|
|
|
|
int
|
|
bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, int max_entries, uint32_t map_flags)
|
|
{
|
|
LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = map_flags);
|
|
|
|
return bpf_map_create(map_type, NULL, key_size, value_size, max_entries, &opts);
|
|
}
|
|
|
|
int
|
|
bpf_create_map_in_map(
|
|
enum bpf_map_type map_type, const char* name, int key_size, int inner_map_fd, int max_entries, __u32 map_flags)
|
|
{
|
|
LIBBPF_OPTS(bpf_map_create_opts, opts, .inner_map_fd = (uint32_t)inner_map_fd, .map_flags = map_flags, );
|
|
|
|
return bpf_map_create(map_type, name, key_size, 4, max_entries, &opts);
|
|
}
|
|
|
|
struct bpf_map*
|
|
bpf_map__next(const struct bpf_map* prev, const struct bpf_object* obj)
|
|
{
|
|
return bpf_object__next_map(obj, prev);
|
|
}
|
|
|
|
struct bpf_map*
|
|
bpf_object__next_map(const struct bpf_object* object, const struct bpf_map* previous)
|
|
{
|
|
return ebpf_map_next(previous, object);
|
|
}
|
|
|
|
struct bpf_map*
|
|
bpf_map__prev(const struct bpf_map* next, const struct bpf_object* obj)
|
|
{
|
|
return bpf_object__prev_map(obj, next);
|
|
}
|
|
|
|
struct bpf_map*
|
|
bpf_object__prev_map(const struct bpf_object* object, const struct bpf_map* next)
|
|
{
|
|
return ebpf_map_previous(next, object);
|
|
}
|
|
|
|
int
|
|
bpf_map__unpin(struct bpf_map* map, const char* path)
|
|
{
|
|
return libbpf_result_err(ebpf_map_unpin(map, path));
|
|
}
|
|
|
|
int
|
|
bpf_map__pin(struct bpf_map* map, const char* path)
|
|
{
|
|
return libbpf_result_err(ebpf_map_pin(map, path));
|
|
}
|
|
|
|
int
|
|
bpf_object__pin_maps(struct bpf_object* obj, const char* path)
|
|
{
|
|
struct bpf_map* map;
|
|
int err;
|
|
|
|
if (!obj) {
|
|
return libbpf_err(-ENOENT);
|
|
}
|
|
|
|
bpf_object__for_each_map(map, obj)
|
|
{
|
|
char* pin_path = NULL;
|
|
char buf[PATH_MAX];
|
|
|
|
if (path) {
|
|
int len;
|
|
|
|
len = snprintf(buf, PATH_MAX, "%s/%s", path, bpf_map__name(map));
|
|
if (len < 0) {
|
|
err = -EINVAL;
|
|
goto err_unpin_maps;
|
|
} else if (len >= PATH_MAX) {
|
|
err = -ENAMETOOLONG;
|
|
goto err_unpin_maps;
|
|
}
|
|
pin_path = buf;
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
err = bpf_map__pin(map, pin_path);
|
|
if (err) {
|
|
goto err_unpin_maps;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
err_unpin_maps:
|
|
while ((map = bpf_object__prev_map(obj, map)) != NULL) {
|
|
bpf_map__unpin(map, NULL);
|
|
}
|
|
return libbpf_err(err);
|
|
}
|
|
|
|
int
|
|
bpf_object__unpin_maps(struct bpf_object* obj, const char* path)
|
|
{
|
|
struct bpf_map* map;
|
|
int err;
|
|
|
|
if (!obj) {
|
|
return libbpf_err(-ENOENT);
|
|
}
|
|
|
|
bpf_object__for_each_map(map, obj)
|
|
{
|
|
char* pin_path = NULL;
|
|
char buf[PATH_MAX];
|
|
|
|
if (path) {
|
|
int len;
|
|
|
|
len = snprintf(buf, PATH_MAX, "%s/%s", path, bpf_map__name(map));
|
|
if (len < 0) {
|
|
return libbpf_err(-EINVAL);
|
|
} else if (len >= PATH_MAX) {
|
|
return libbpf_err(-ENAMETOOLONG);
|
|
}
|
|
pin_path = buf;
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
err = bpf_map__unpin(map, pin_path);
|
|
if (err) {
|
|
return libbpf_err(err);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
const char*
|
|
bpf_map__name(const struct bpf_map* map)
|
|
{
|
|
return map ? map->name : NULL;
|
|
}
|
|
|
|
enum bpf_map_type
|
|
bpf_map__type(const struct bpf_map* map)
|
|
{
|
|
return map->map_definition.type;
|
|
}
|
|
|
|
__u32
|
|
bpf_map__key_size(const struct bpf_map* map)
|
|
{
|
|
return map->map_definition.key_size;
|
|
}
|
|
|
|
__u32
|
|
bpf_map__value_size(const struct bpf_map* map)
|
|
{
|
|
return map->map_definition.value_size;
|
|
}
|
|
|
|
__u32
|
|
bpf_map__max_entries(const struct bpf_map* map)
|
|
{
|
|
return map->map_definition.max_entries;
|
|
}
|
|
|
|
bool
|
|
bpf_map__is_pinned(const struct bpf_map* map)
|
|
{
|
|
return map->pinned;
|
|
}
|
|
|
|
int
|
|
bpf_map__fd(const struct bpf_map* map)
|
|
{
|
|
return map ? map->map_fd : libbpf_err(-EINVAL);
|
|
}
|
|
|
|
struct bpf_map*
|
|
bpf_object__find_map_by_name(const struct bpf_object* obj, const char* name)
|
|
{
|
|
struct bpf_map* pos;
|
|
|
|
bpf_object__for_each_map(pos, obj)
|
|
{
|
|
if (pos->name && !strcmp(pos->name, name)) {
|
|
return pos;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int
|
|
bpf_object__find_map_fd_by_name(const struct bpf_object* obj, const char* name)
|
|
{
|
|
return bpf_map__fd(bpf_object__find_map_by_name(obj, name));
|
|
}
|
|
|
|
int
|
|
bpf_map__set_pin_path(struct bpf_map* map, const char* path)
|
|
{
|
|
return libbpf_result_err(ebpf_map_set_pin_path(map, path));
|
|
}
|
|
|
|
int
|
|
bpf_map_update_elem(int fd, const void* key, const void* value, uint64_t flags)
|
|
{
|
|
return libbpf_result_err(ebpf_map_update_element(fd, key, value, flags));
|
|
}
|
|
|
|
int
|
|
bpf_map_delete_elem(int fd, const void* key)
|
|
{
|
|
return libbpf_result_err(ebpf_map_delete_element(fd, key));
|
|
}
|
|
|
|
int
|
|
bpf_map_lookup_elem(int fd, const void* key, void* value)
|
|
{
|
|
return libbpf_result_err(ebpf_map_lookup_element(fd, key, value));
|
|
}
|
|
|
|
int
|
|
bpf_map_lookup_and_delete_elem(int fd, const void* key, void* value)
|
|
{
|
|
return libbpf_result_err(ebpf_map_lookup_and_delete_element(fd, key, value));
|
|
}
|
|
|
|
int
|
|
bpf_map_get_next_key(int fd, const void* key, void* next_key)
|
|
{
|
|
return libbpf_result_err(ebpf_map_get_next_key(fd, key, next_key));
|
|
}
|
|
|
|
int
|
|
bpf_map_get_fd_by_id(uint32_t id)
|
|
{
|
|
fd_t fd;
|
|
ebpf_result_t result = ebpf_get_map_fd_by_id(id, &fd);
|
|
if (result != EBPF_SUCCESS) {
|
|
return libbpf_result_err(result);
|
|
}
|
|
return fd;
|
|
}
|
|
|
|
int
|
|
bpf_map_get_next_id(uint32_t start_id, uint32_t* next_id)
|
|
{
|
|
return libbpf_result_err(ebpf_get_next_map_id(start_id, next_id));
|
|
}
|
|
|
|
typedef struct ring_buffer
|
|
{
|
|
std::vector<ring_buffer_subscription_t*> subscriptions;
|
|
} ring_buffer_t;
|
|
|
|
struct ring_buffer*
|
|
ring_buffer__new(int map_fd, ring_buffer_sample_fn sample_cb, void* ctx, const struct ring_buffer_opts* /* opts */)
|
|
{
|
|
ebpf_result result = EBPF_SUCCESS;
|
|
ring_buffer_t* local_ring_buffer = nullptr;
|
|
|
|
try {
|
|
std::unique_ptr<ring_buffer_t> ring_buffer = std::make_unique<ring_buffer_t>();
|
|
ring_buffer_subscription_t* subscription = nullptr;
|
|
result = ebpf_ring_buffer_map_subscribe(map_fd, ctx, sample_cb, &subscription);
|
|
if (result != EBPF_SUCCESS) {
|
|
goto Exit;
|
|
}
|
|
ring_buffer->subscriptions.push_back(subscription);
|
|
local_ring_buffer = ring_buffer.release();
|
|
} catch (const std::bad_alloc&) {
|
|
result = EBPF_NO_MEMORY;
|
|
goto Exit;
|
|
}
|
|
Exit:
|
|
if (result != EBPF_SUCCESS) {
|
|
EBPF_LOG_FUNCTION_ERROR(result);
|
|
}
|
|
EBPF_RETURN_POINTER(ring_buffer_t*, local_ring_buffer);
|
|
}
|
|
|
|
void
|
|
ring_buffer__free(struct ring_buffer* ring_buffer)
|
|
{
|
|
for (auto it = ring_buffer->subscriptions.begin(); it != ring_buffer->subscriptions.end(); it++) {
|
|
(void)ebpf_ring_buffer_map_unsubscribe(*it);
|
|
}
|
|
ring_buffer->subscriptions.clear();
|
|
delete ring_buffer;
|
|
}
|
|
|
|
const char*
|
|
libbpf_bpf_map_type_str(enum bpf_map_type t)
|
|
{
|
|
if (t < 0 || t >= _countof(_ebpf_map_display_names)) {
|
|
return nullptr;
|
|
}
|
|
|
|
return _ebpf_map_display_names[t];
|
|
}
|