Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BTF Support #69

Merged
merged 15 commits into from
Jul 26, 2024
18 changes: 9 additions & 9 deletions ebpf_ffi/cbpf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
#include <linux/kernel.h>
#include <netpacket/packet.h>

bool load_cbpf_program(void *prog_buff, size_t size, std::string *error,
bool load_cbpf_program(void *prog_buff, size_t size, std::string &error,
int *socks) {
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, socks) < 0) {
*error = strerror(errno);
error = strerror(errno);
return false;
}
// cBPF programs have two relevant structures: sock_filter, and sock_fprog
Expand All @@ -40,12 +40,12 @@ bool load_cbpf_program(void *prog_buff, size_t size, std::string *error,
tv.tv_usec = 10000;
if (setsockopt(socks[1], SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv,
sizeof tv) < 0) {
*error = strerror(errno);
error = strerror(errno);
return false;
}
if (setsockopt(socks[1], SOL_SOCKET, SO_ATTACH_FILTER, &program,
sizeof(program)) < 0) {
*error = strerror(errno);
error = strerror(errno);
return false;
}
return true;
Expand All @@ -72,7 +72,7 @@ struct bpf_result ffi_load_cbpf_program(void *prog_buff, size_t size,
ValidationResult vres;

int socks[2] = {-1, -1};
if (!load_cbpf_program(prog_buff, size, &error_message, socks)) {
if (!load_cbpf_program(prog_buff, size, error_message, socks)) {
// Return why we failed to load the program.
return validation_error(error_message, &vres);
}
Expand Down Expand Up @@ -101,15 +101,15 @@ struct bpf_result ffi_load_cbpf_program(void *prog_buff, size_t size,

bool execute_cbpf_program(int socket_write, int socket_read, uint8_t *input,
uint8_t *output, int input_length,
std::string *error_message) {
std::string &error_message) {
if (write(socket_write, input, input_length) != input_length) {
*error_message = "Could not write all data to socket";
error_message = "Could not write all data to socket";
return false;
}

close(socket_write);
if (read(socket_read, output, input_length) != input_length) {
*error_message = "Could not read all data to socket";
error_message = "Could not read all data to socket";
}
close(socket_read);

Expand Down Expand Up @@ -153,7 +153,7 @@ struct bpf_result ffi_execute_cbpf_program(void *serialized_proto,
memset(read_data, 0x00, data_size + 1);
std::string error_message;
if (!execute_cbpf_program(socket_write, socket_read, data, read_data,
data_size, &error_message)) {
data_size, error_message)) {
return return_error(error_message, &execution_result);
}

Expand Down
4 changes: 2 additions & 2 deletions ebpf_ffi/cbpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ extern "C" {
// Actual implementation of load program. The split between ffi and
// implementation is done so the impl code can be shared with other parts of the
// codebase also written in C++.
bool load_cbpf_program(void *prog_buff, size_t size, std::string *error,
bool load_cbpf_program(void *prog_buff, size_t size, std::string &error,
int *socks);

// Loads a bpf program specified by |prog_buff| with |size| and returns struct
Expand All @@ -34,7 +34,7 @@ struct bpf_result ffi_load_cbpf_program(void *prog_buff, size_t size,
uint64_t coverage_size);

bool execute_cbpf_program(int prog_fd, uint8_t *input, uint8_t *output,
int input_length, std::string *error_message);
int input_length, std::string &error_message);

// Runs the specified cbpf program by sending some data to a socket.
// Serialized proto is of type ExecutionRequest.
Expand Down
75 changes: 39 additions & 36 deletions ebpf_ffi/ebpf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,57 +19,70 @@ namespace ebpf_ffi {
// This constant was determined arbitrarily, the number of 0's has incremented
// when the size was no longer enough for the verifier logs.
constexpr size_t kLogBuffSize = 100000000;
// This constnat was determined arbitrarily for the btf logs
constexpr size_t btfKLogBuffSize = 1024;
} // namespace ebpf_ffi

int btf_load(void *btf_buff, size_t btf_size, std::string *error) {
// btf_buff: Pointer to a buffer where the BTF data is stored
// btf_size: Size of the BTF data in bytes
int btf_load(void *btf_buff, size_t btf_size, std::string &error) {
union bpf_attr btf_attr;
memset(&btf_attr, 0, sizeof(btf_attr));
btf_attr.btf = (uint64_t)btf_buff;
btf_attr.btf_size = btf_size;

char *btf_log_buf = (char *)malloc(1024);
memset(btf_log_buf, 0, 1024);
char *btf_log_buf = (char *)malloc(ebpf_ffi::btfKLogBuffSize);
memset(btf_log_buf, 0, ebpf_ffi::btfKLogBuffSize);
btf_attr.btf_log_buf = (uint64_t)btf_log_buf;
btf_attr.btf_log_size = 1024;
btf_attr.btf_log_size = ebpf_ffi::btfKLogBuffSize;
btf_attr.btf_log_level = 2;

int btf_fd = syscall(SYS_bpf, BPF_BTF_LOAD, &btf_attr, sizeof(btf_attr));
if (btf_fd < 0) {
*error = strerror(errno);
error = strerror(errno);
}
return btf_fd;
}

int load_ebpf_program(uint8_t *prog_buff, int prog_size, uint8_t *btf_buff,
int btf_size, uint8_t *func_buff, int func_size,
std::string *verifier_log, std::string *error) {
int load_ebpf_program(void *serialized_proto, size_t size,
std::string *verifier_log, std::string &error) {
std::string serialized_proto_string(
reinterpret_cast<const char *>(serialized_proto), size);
EncodedProgram program;
if (!program.ParseFromString(serialized_proto_string)) {
error = "Could not parse EncodedProgram proto";
}

struct bpf_insn *insn;
union bpf_attr attr = {};

// For the verifier log.
unsigned char *log_buf = (unsigned char *)malloc(ebpf_ffi::kLogBuffSize);
memset(log_buf, 0, ebpf_ffi::kLogBuffSize);

int btf_fd = btf_load(btf_buff, btf_size, error);
struct bpf_func_info *func = (struct bpf_func_info *)func_buff;
attr.prog_btf_fd = btf_fd;
attr.func_info_rec_size = sizeof(struct bpf_func_info);
attr.func_info = (uint64_t)(func);
attr.func_info_cnt = (func_size / sizeof(struct bpf_func_info)) - 1;
;

insn = (struct bpf_insn *)prog_buff;
int btf_fd = btf_load(((uint8_t *)(program.btf().c_str())),
(program.btf().length()), error);
if (!(btf_fd < 0)) {
struct bpf_func_info *func =
(struct bpf_func_info *)((uint8_t *)(program.function().c_str()));
attr.prog_btf_fd = btf_fd;
attr.func_info_rec_size = sizeof(struct bpf_func_info);
attr.func_info = (uint64_t)(func);
attr.func_info_cnt =
((program.function().length()) / sizeof(struct bpf_func_info));
}
insn = (struct bpf_insn *)((uint8_t *)(program.program().c_str()));
attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
attr.insns = (uint64_t)insn;
attr.insn_cnt = (prog_size / (sizeof(struct bpf_insn)));
attr.insn_cnt = ((program.program().length()) / (sizeof(struct bpf_insn)));
attr.license = (uint64_t) "GPL";
attr.log_size = ebpf_ffi::kLogBuffSize;
attr.log_buf = (uint64_t)log_buf;
attr.log_level = 2;

int program_fd = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
if (program_fd < 0) {
*error = strerror(errno);
error = strerror(errno);
}

*verifier_log =
Expand All @@ -83,25 +96,15 @@ struct bpf_result ffi_load_ebpf_program(void *serialized_proto, size_t size,
int coverage_enabled,
uint64_t coverage_size) {
std::string verifier_log, error_message;
std::string serialized_proto_string(
reinterpret_cast<const char *>(serialized_proto), size);
EncodedProgram program;
if (!program.ParseFromString(serialized_proto_string)) {
error_message = "Could not parse EncodedProgram proto";
}

struct coverage_data cover;
memset(&cover, 0, sizeof(struct coverage_data));
cover.fd = -1;
cover.coverage_size = coverage_size;
if (coverage_enabled) enable_coverage(&cover);
uint8_t *prog_buff = (uint8_t *)(program.program().c_str());
uint8_t *btf_buff = (uint8_t *)(program.btf().c_str());
uint8_t *func_buff = (uint8_t *)(program.function().c_str());

int program_fd = load_ebpf_program(
prog_buff, program.program().length(), btf_buff, program.btf().length(),
func_buff, program.function().length(), &verifier_log, &error_message);
int program_fd =
load_ebpf_program(serialized_proto, size, &verifier_log, error_message);
ValidationResult vres;
if (coverage_enabled) get_coverage_and_free_resources(&cover, &vres);

Expand Down Expand Up @@ -129,7 +132,7 @@ struct bpf_result ffi_load_ebpf_program(void *serialized_proto, size_t size,
}

bool get_map_elements(int map_fd, size_t map_size, std::vector<uint64_t> *res,
std::string *error) {
std::string &error) {
for (uint64_t key = 0; key < map_size; key++) {
uint64_t element = 0;
union bpf_attr lookup_map = {.map_fd = static_cast<uint32_t>(map_fd),
Expand All @@ -138,7 +141,7 @@ bool get_map_elements(int map_fd, size_t map_size, std::vector<uint64_t> *res,
int err =
syscall(SYS_bpf, BPF_MAP_LOOKUP_ELEM, &lookup_map, sizeof(lookup_map));
if (err < 0) {
*error = strerror(errno);
error = strerror(errno);
return false;
}
res->push_back(element);
Expand Down Expand Up @@ -177,7 +180,7 @@ struct bpf_result ffi_get_map_elements(int map_fd, uint64_t map_size) {
MapElements res;
std::vector<uint64_t> elements;
std::string error_message;
if (!get_map_elements(map_fd, map_size, &elements, &error_message)) {
if (!get_map_elements(map_fd, map_size, &elements, error_message)) {
res.set_error_message(error_message);
return serialize_proto(res);
}
Expand All @@ -187,7 +190,7 @@ struct bpf_result ffi_get_map_elements(int map_fd, uint64_t map_size) {
}

bool execute_ebpf_program(int prog_fd, uint8_t *input, int input_length,
std::string *error_message) {
std::string &error_message) {
int socks[2] = {};
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, socks) != 0) {
return execute_error(error_message, strerror(errno), NULL);
Expand Down Expand Up @@ -231,7 +234,7 @@ struct bpf_result ffi_execute_ebpf_program(void *serialized_proto,
}

std::string error_message;
if (!execute_ebpf_program(prog_fd, data, data_size, &error_message)) {
if (!execute_ebpf_program(prog_fd, data, data_size, error_message)) {
return return_error(error_message, &execution_result);
}

Expand Down
9 changes: 4 additions & 5 deletions ebpf_ffi/ebpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ extern "C" {
// Actual implementation of load program. The split between ffi and
// implementation is done so the impl code can be shared with other parts of the
// codebase also written in C++.
int load_ebpf_program(uint8_t *prog_buff, int prog_size, uint8_t *btf_buff,
int btf_size, uint8_t *func_buff, int func_size,
std::string *verifier_log, std::string *error);
int load_ebpf_program(void *serialized_proto, size_t size,
std::string *verifier_log, std::string &error);

// Loads a bpf program specified by |prog_buff| with |size| and returns struct
// with a serialized ValidationResult proto.
Expand All @@ -41,7 +40,7 @@ struct bpf_result ffi_load_ebpf_program(void *serialized_proto, size_t size,
uint64_t coverage_size);

bool get_map_elements(int map_fd, size_t map_size, std::vector<uint64_t> *res,
std::string *error);
std::string &error);

// Sets the value at key |key| in the map described by |map_fd| to |value|.
int ffi_update_map_element(int map_fd, int key, uint64_t value);
Expand All @@ -57,7 +56,7 @@ int ffi_create_bpf_map(size_t size);
struct bpf_result ffi_get_map_elements(int map_fd, uint64_t map_size);

bool execute_ebpf_program(int prog_fd, uint8_t *input, int input_length,
std::string *error_message);
std::string &error_message);

/// Runs the specified ebpf program by sending some data to a socket.
// Serialized proto is of type ExecutionRequest.
Expand Down
4 changes: 2 additions & 2 deletions ebpf_ffi/ffi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,13 @@ void get_coverage_and_free_resources(struct coverage_data *cstruct,
munmap(cstruct->coverage_buffer, cstruct->coverage_size * sizeof(uint64_t));
}

bool execute_error(std::string *error_message, const char *strerr,
bool execute_error(std::string &error_message, const char *strerr,
int *sockets) {
if (sockets != nullptr) {
close(sockets[0]);
close(sockets[1]);
}
*error_message = strerr;
error_message = strerr;
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion ebpf_ffi/ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ void enable_coverage(struct coverage_data *coverage_info);
void get_coverage_and_free_resources(struct coverage_data *cstruct,
ValidationResult *vres);

bool execute_error(std::string *error_message, const char *strerr,
bool execute_error(std::string &error_message, const char *strerr,
int *sockets);

struct bpf_result return_error(std::string error_message,
Expand Down
Loading
Loading