diff --git a/.gitmodules b/.gitmodules
index b90d85fbb..744d216c3 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -6,3 +6,6 @@
path = external/ubpf
url = https://github.com/iovisor/ubpf.git
branch = master
+[submodule "external/libbpf"]
+ path = external/libbpf
+ url = https://github.com/libbpf/libbpf.git
diff --git a/ebpfapi/Source.def b/ebpfapi/Source.def
index d48d860aa..0138f99f8 100644
--- a/ebpfapi/Source.def
+++ b/ebpfapi/Source.def
@@ -5,34 +5,65 @@
LIBRARY
EXPORTS
- ebpf_api_initiate
- ebpf_api_terminate
- ebpf_api_load_program
- ebpf_api_create_map
- ebpf_api_map_find_element
- ebpf_api_map_update_element
- ebpf_api_map_delete_element
- ebpf_api_get_next_map_key
- ebpf_api_elf_enumerate_sections
- ebpf_api_elf_disassemble_section
- ebpf_api_elf_verify_section
- ebpf_api_elf_free
- ebpf_api_pin_object
- ebpf_api_unpin_object
- ebpf_api_get_next_map
- ebpf_api_get_pinned_map
- ebpf_api_get_next_program
- ebpf_api_program_query_info
- ebpf_api_link_program
- ebpf_api_close_handle
- ebpf_api_get_pinned_map_info
- ebpf_api_map_info_free
- ebpf_free_string
- ebpf_map_get_fd
- ebpf_map_next
- ebpf_map_previous
- ebpf_object_close
- ebpf_program_get_fd
- ebpf_program_load
- ebpf_program_next
- ebpf_program_previous
+ bpf_link__destroy
+ bpf_map__fd
+ bpf_map__is_pinned
+ bpf_map__key_size
+ bpf_map__max_entries
+ bpf_map__next
+ bpf_map__pin
+ bpf_map__prev
+ bpf_map__type
+ bpf_map__unpin
+ bpf_map__value_size
+ bpf_object__close
+ bpf_object__find_program_by_name
+ bpf_object__name
+ bpf_object__pin
+ bpf_object__pin_maps
+ bpf_object__pin_programs
+ bpf_object__unpin_maps
+ bpf_object__unpin_programs
+ bpf_prog_load
+ bpf_program__attach
+ bpf_program__attach_xdp
+ bpf_program__fd
+ bpf_program__get_expected_attach_type
+ bpf_program__name
+ bpf_program__next
+ bpf_program__pin
+ bpf_program__prev
+ bpf_program__section_name
+ bpf_program__set_expected_attach_type
+ bpf_program__unpin
+ ebpf_api_initiate
+ ebpf_api_terminate
+ ebpf_api_load_program
+ ebpf_api_create_map
+ ebpf_api_map_find_element
+ ebpf_api_map_update_element
+ ebpf_api_map_delete_element
+ ebpf_api_get_next_map_key
+ ebpf_api_elf_enumerate_sections
+ ebpf_api_elf_disassemble_section
+ ebpf_api_elf_verify_section
+ ebpf_api_elf_free
+ ebpf_api_pin_object
+ ebpf_api_unpin_object
+ ebpf_api_get_next_map
+ ebpf_api_get_pinned_map
+ ebpf_api_get_next_program
+ ebpf_api_program_query_info
+ ebpf_api_link_program
+ ebpf_api_close_handle
+ ebpf_api_get_pinned_map_info
+ ebpf_api_map_info_free
+ ebpf_free_string
+ ebpf_map_get_fd
+ ebpf_map_next
+ ebpf_map_previous
+ ebpf_object_close
+ ebpf_program_get_fd
+ ebpf_program_load
+ ebpf_program_next
+ ebpf_program_previous
diff --git a/external/libbpf b/external/libbpf
new file mode 160000
index 000000000..90405ffa9
--- /dev/null
+++ b/external/libbpf
@@ -0,0 +1 @@
+Subproject commit 90405ffa91abbdbfd9f56b70adbfa0be6cc0fe3f
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
new file mode 100644
index 000000000..f94b9498d
--- /dev/null
+++ b/include/linux/bpf.h
@@ -0,0 +1,47 @@
+// Copyright (c) Microsoft Corporation
+// // SPDX-License-Identifier: MIT
+#pragma once
+
+// This file is needed since bpf.h includes it.
+// It should be thought of as platform/bpf.h not Linux per se.
+
+#include "ebpf_program_types.h"
+#include "ebpf_api.h"
+#define LIBBPF_API
+#include "libbpf_common.h"
+#undef LIBBPF_DEPRECATED
+#define LIBBPF_DEPRECATED(x)
+
+typedef uint8_t __u8;
+typedef uint32_t __u32;
+typedef uint64_t __u64;
+typedef uint32_t pid_t;
+
+#define bpf_map _ebpf_map
+#define bpf_map_type _ebpf_map_type
+#define bpf_object _ebpf_object
+#define bpf_program _ebpf_program
+#define bpf_prog_info _ebpf_program_info
+#define BPF_MAP_TYPE_ARRAY EBPF_MAP_TYPE_ARRAY
+
+enum bpf_prog_type
+{
+ BPF_PROG_TYPE_UNKNOWN,
+ BPF_PROG_TYPE_XDP,
+};
+
+enum bpf_attach_type
+{
+ BPF_ATTACH_TYPE_UNKNOWN,
+ BPF_ATTACH_TYPE_XDP,
+};
+
+enum bpf_func_id
+{
+ BPF_FUNC_ID_UNKNOWN
+};
+
+enum bpf_stats_type
+{
+ BPF_STATS_TYPE_UNKNOWN
+};
diff --git a/libs/api/api.vcxproj b/libs/api/api.vcxproj
index e25cdd4cc..ee6cb70bb 100644
--- a/libs/api/api.vcxproj
+++ b/libs/api/api.vcxproj
@@ -97,6 +97,7 @@
pch.h
stdcpplatest
MultiThreadedDebug
+ $(SolutionDir)external\libbpf\src;$(SolutionDir)libs\api;$(SolutionDir)rpc_interface;$(SolutionDir)libs\service;$(SolutionDir)libs\api_common;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)external\ubpf\vm;$(SolutionDir)external\ubpf\vm\inc;$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)external\ebpf-verifier\external;$(SolutionDir)external\ebpf-verifier\external\elfio;$(OutDir);%(AdditionalIncludeDirectories)
Windows
@@ -115,6 +116,7 @@
Use
pch.h
stdcpplatest
+ $(SolutionDir)external\libbpf\src;
Windows
@@ -132,7 +134,7 @@
true
NotUsing
pch.h
- $(SolutionDir)libs\api;$(SolutionDir)rpc_interface;$(SolutionDir)libs\service;$(SolutionDir)libs\api_common;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)external\ubpf\vm;$(SolutionDir)external\ubpf\vm\inc;$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)external\ebpf-verifier\external;$(SolutionDir)external\ebpf-verifier\external\elfio;$(OutDir);%(AdditionalIncludeDirectories)
+ $(SolutionDir)external\libbpf\src;$(SolutionDir)libs\api;$(SolutionDir)rpc_interface;$(SolutionDir)libs\service;$(SolutionDir)libs\api_common;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)external\ubpf\vm;$(SolutionDir)external\ubpf\vm\inc;$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)external\ebpf-verifier\external;$(SolutionDir)external\ebpf-verifier\external\elfio;$(OutDir);%(AdditionalIncludeDirectories)
stdcpplatest
MultiThreadedDebug
true
@@ -154,7 +156,7 @@
true
NotUsing
pch.h
- $(SolutionDir)rpc_interface;$(SolutionDir)libs\service;$(SolutionDir)libs\api_common;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)external\ubpf\vm;$(SolutionDir)external\ubpf\vm\inc;$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)external\ebpf-verifier\external;$(SolutionDir)external\ebpf-verifier\external\elfio;$(OutDir);%(AdditionalIncludeDirectories)
+ $(SolutionDir)external\libbpf\src;$(SolutionDir)rpc_interface;$(SolutionDir)libs\service;$(SolutionDir)libs\api_common;$(SolutionDir)include;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)external\ubpf\vm;$(SolutionDir)external\ubpf\vm\inc;$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)external\ebpf-verifier\external;$(SolutionDir)external\ebpf-verifier\external\elfio;$(OutDir);%(AdditionalIncludeDirectories)
stdcpplatest
true
@@ -171,6 +173,9 @@
+
+
+
@@ -201,4 +206,4 @@
-
+
\ No newline at end of file
diff --git a/libs/api/api.vcxproj.filters b/libs/api/api.vcxproj.filters
index 544a54720..ba57c7f12 100644
--- a/libs/api/api.vcxproj.filters
+++ b/libs/api/api.vcxproj.filters
@@ -25,6 +25,15 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
diff --git a/libs/api/api_internal.h b/libs/api/api_internal.h
index bfe52eec4..55a17ca51 100644
--- a/libs/api/api_internal.h
+++ b/libs/api/api_internal.h
@@ -29,7 +29,7 @@ typedef struct _ebpf_map
char* name;
ebpf_handle_t map_handle;
fd_t map_fd;
- ebpf_map_definition_t map_defintion;
+ ebpf_map_definition_t map_definition;
char* pin_path;
bool pinned;
} ebpf_map_t;
diff --git a/libs/api/ebpf_api.cpp b/libs/api/ebpf_api.cpp
index 84cd15a54..3198a2eba 100644
--- a/libs/api/ebpf_api.cpp
+++ b/libs/api/ebpf_api.cpp
@@ -3,6 +3,7 @@
#include "pch.h"
+#include
#include
#include "api_common.hpp"
#include "api_internal.h"
@@ -677,7 +678,7 @@ clean_up_ebpf_program(_In_ _Post_invalid_ ebpf_program_t* program)
_ebpf_programs.erase(program->fd);
}
if (program->handle != ebpf_handle_invalid) {
- CloseHandle(program->handle);
+ Platform::CloseHandle(program->handle);
}
free(program->byte_code);
free(program->program_name);
@@ -702,7 +703,7 @@ clean_up_ebpf_map(_In_ _Post_invalid_ ebpf_map_t* map)
_ebpf_maps.erase(map->map_fd);
}
if (map->map_handle != ebpf_handle_invalid) {
- CloseHandle(map->map_handle);
+ Platform::CloseHandle(map->map_handle);
}
free(map);
@@ -758,10 +759,10 @@ _initialize_map(_Out_ ebpf_map_t* map, _In_ const ebpf_object_t* object, _In_ co
map->object = object;
map->map_handle = (ebpf_handle_t)map_cache.handle;
map->map_fd = map_cache.ebpf_map_descriptor.original_fd;
- map->map_defintion.type = (ebpf_map_type_t)map_cache.ebpf_map_descriptor.type;
- map->map_defintion.key_size = map_cache.ebpf_map_descriptor.key_size;
- map->map_defintion.value_size = map_cache.ebpf_map_descriptor.value_size;
- map->map_defintion.max_entries = map_cache.ebpf_map_descriptor.max_entries;
+ map->map_definition.type = (ebpf_map_type_t)map_cache.ebpf_map_descriptor.type;
+ map->map_definition.key_size = map_cache.ebpf_map_descriptor.key_size;
+ map->map_definition.value_size = map_cache.ebpf_map_descriptor.value_size;
+ map->map_definition.max_entries = map_cache.ebpf_map_descriptor.max_entries;
map->pinned = false;
map->pin_path = nullptr;
}
diff --git a/libs/api/libbpf_internal.h b/libs/api/libbpf_internal.h
new file mode 100644
index 000000000..9c36e5935
--- /dev/null
+++ b/libs/api/libbpf_internal.h
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft Corporation
+// SPDX-License-Identifier: MIT
+#pragma once
+
+#define PATH_MAX MAX_PATH
+#define strdup _strdup
+
+static inline int
+libbpf_err(int ret)
+{
+ if (ret < 0)
+ errno = -ret;
+ return ret;
+}
diff --git a/libs/api/libbpf_map.cpp b/libs/api/libbpf_map.cpp
new file mode 100644
index 000000000..a0169eb79
--- /dev/null
+++ b/libs/api/libbpf_map.cpp
@@ -0,0 +1,184 @@
+// Copyright (c) Microsoft Corporation
+// SPDX-License-Identifier: MIT
+
+#include "api_internal.h"
+#pragma warning(push)
+#pragma warning(disable : 4200)
+#include "libbpf.h"
+#pragma warning(pop)
+#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.
+
+struct bpf_map*
+bpf_map__next(const struct bpf_map* previous, const struct bpf_object* object)
+{
+ return ebpf_map_next(previous, object);
+}
+
+struct bpf_map*
+bpf_map__prev(const struct bpf_map* next, const struct bpf_object* object)
+{
+ return ebpf_map_previous(next, object);
+}
+
+int
+bpf_map__unpin(struct bpf_map* map, const char* path)
+{
+ int err;
+
+ if (map == NULL) {
+ return libbpf_err(-EINVAL);
+ }
+
+ err = ebpf_api_unpin_object((const uint8_t*)path, (uint32_t)strlen(path));
+ if (err) {
+ return libbpf_err(err);
+ }
+
+ map->pinned = false;
+
+ return 0;
+}
+
+int
+bpf_map__pin(struct bpf_map* map, const char* path)
+{
+ int err;
+
+ if (map == NULL) {
+ return libbpf_err(-EINVAL);
+ }
+
+ err = ebpf_api_pin_object(map->map_handle, (const uint8_t*)path, (uint32_t)strlen(path));
+ if (err)
+ return libbpf_err(-err);
+
+ map->pinned = true;
+
+ return 0;
+}
+
+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_map__prev(map, obj)) != 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);
+}
diff --git a/libs/api/libbpf_object.cpp b/libs/api/libbpf_object.cpp
new file mode 100644
index 000000000..d1dbb5ea8
--- /dev/null
+++ b/libs/api/libbpf_object.cpp
@@ -0,0 +1,58 @@
+// Copyright (c) Microsoft Corporation
+// SPDX-License-Identifier: MIT
+
+#include "api_internal.h"
+#pragma warning(push)
+#pragma warning(disable : 4200)
+#include "libbpf.h"
+#pragma warning(pop)
+#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.
+
+const char*
+bpf_object__name(const struct bpf_object* object)
+{
+ return object->file_name;
+}
+
+int
+bpf_object__pin(struct bpf_object* obj, const char* path)
+{
+ int err;
+
+ err = bpf_object__pin_maps(obj, path);
+ if (err)
+ return libbpf_err(err);
+
+ err = bpf_object__pin_programs(obj, path);
+ if (err) {
+ bpf_object__unpin_maps(obj, path);
+ return libbpf_err(err);
+ }
+
+ return 0;
+}
+
+void
+bpf_object__close(struct bpf_object* object)
+{
+ ebpf_object_close(object);
+}
+
+struct bpf_program*
+bpf_object__find_program_by_name(const struct bpf_object* obj, const char* name)
+{
+ struct bpf_program* prog;
+
+ bpf_object__for_each_program(prog, obj)
+ {
+ if (!strcmp(prog->program_name, name))
+ return prog;
+ }
+ errno = ENOENT;
+ return nullptr;
+}
diff --git a/libs/api/libbpf_program.cpp b/libs/api/libbpf_program.cpp
new file mode 100644
index 000000000..08c851e23
--- /dev/null
+++ b/libs/api/libbpf_program.cpp
@@ -0,0 +1,278 @@
+// Copyright (c) Microsoft Corporation
+// SPDX-License-Identifier: MIT
+
+#include "api_internal.h"
+#pragma warning(push)
+#pragma warning(disable : 4200)
+#include "libbpf.h"
+#pragma warning(pop)
+#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.
+
+static const ebpf_program_type_t*
+_get_ebpf_program_type(enum bpf_prog_type type)
+{
+ // TODO(issue #223): read this mapping from the registry
+ switch (type) {
+ case BPF_PROG_TYPE_XDP:
+ return &EBPF_PROGRAM_TYPE_XDP;
+ }
+ return nullptr;
+}
+
+static const ebpf_attach_type_t*
+_get_ebpf_attach_type(enum bpf_attach_type type)
+{
+ // TODO(issue #223): read this mapping from the registry
+ switch (type) {
+ case BPF_ATTACH_TYPE_XDP:
+ return &EBPF_ATTACH_TYPE_XDP;
+ }
+ return nullptr;
+}
+
+static enum bpf_attach_type
+_get_bpf_attach_type(const ebpf_attach_type_t* type)
+{
+ // TODO(issue #223): read this mapping from the registry
+ if (memcmp(type, &EBPF_ATTACH_TYPE_XDP, sizeof(*type)) == 0) {
+ return BPF_ATTACH_TYPE_XDP;
+ }
+ return BPF_ATTACH_TYPE_UNKNOWN;
+}
+
+int
+bpf_prog_load(const char* file_name, enum bpf_prog_type type, struct bpf_object** object, int* program_fd)
+{
+ const ebpf_program_type_t* program_type = _get_ebpf_program_type(type);
+
+ if (program_type == nullptr) {
+ return EBPF_INVALID_ARGUMENT;
+ }
+
+ const char* log_buffer;
+ return (int)ebpf_program_load(
+ file_name, program_type, nullptr, EBPF_EXECUTION_ANY, object, (fd_t*)program_fd, &log_buffer);
+}
+
+int
+bpf_program__fd(const struct bpf_program* program)
+{
+ return (int)ebpf_program_get_fd(program);
+}
+
+const char*
+bpf_program__name(const struct bpf_program* program)
+{
+ return program->program_name;
+}
+
+const char*
+bpf_program__section_name(const struct bpf_program* program)
+{
+ return program->section_name;
+}
+
+size_t
+bpf_program__size(const struct bpf_program* program)
+{
+ return program->byte_code_size;
+}
+
+struct bpf_link*
+bpf_program__attach(struct bpf_program* program)
+{
+ if (program == nullptr) {
+ return nullptr;
+ }
+
+ ebpf_handle_t link_handle;
+ uint32_t result = ebpf_api_link_program(program->handle, program->attach_type, &link_handle);
+ if (result) {
+ errno = result;
+ return nullptr;
+ }
+
+ // The bpf_link structure is opaque so we can use the link handle directly.
+ // TODO(issue #81): return pointer to ebpf_link_t.
+ return (struct bpf_link*)link_handle;
+}
+
+struct bpf_link*
+bpf_program__attach_xdp(struct bpf_program* program, int ifindex)
+{
+ if (program == nullptr) {
+ return nullptr;
+ }
+
+ // TODO: use ifindex
+ UNREFERENCED_PARAMETER(ifindex);
+
+ ebpf_handle_t link_handle;
+ uint32_t result = ebpf_api_link_program(program->handle, EBPF_ATTACH_TYPE_XDP, &link_handle);
+ if (result) {
+ return nullptr;
+ }
+
+ // The bpf_link structure is opaque so we can use the link handle directly.
+ // TODO(issue #81): return pointer to ebpf_link_t.
+ return (struct bpf_link*)link_handle;
+}
+
+struct bpf_program*
+bpf_program__next(struct bpf_program* previous, const struct bpf_object* object)
+{
+ return ebpf_program_next(previous, object);
+}
+
+struct bpf_program*
+bpf_program__prev(struct bpf_program* next, const struct bpf_object* object)
+{
+ return ebpf_program_previous(next, object);
+}
+
+int
+bpf_program__unpin(struct bpf_program* prog, const char* path)
+{
+ int err;
+
+ if (prog == NULL) {
+ return libbpf_err(-EINVAL);
+ }
+
+ err = ebpf_api_unpin_object((const uint8_t*)path, (uint32_t)strlen(path));
+ if (err)
+ return libbpf_err(-err);
+
+ return 0;
+}
+
+int
+bpf_program__pin(struct bpf_program* prog, const char* path)
+{
+ int err;
+
+ if (prog == NULL) {
+ return libbpf_err(-EINVAL);
+ }
+
+ err = ebpf_api_pin_object(prog->handle, (const uint8_t*)path, (uint32_t)strlen(path));
+ if (err) {
+ return libbpf_err(err);
+ }
+
+ return 0;
+}
+
+static char*
+__bpf_program__pin_name(struct bpf_program* prog)
+{
+ char *name, *p;
+
+ name = p = strdup(prog->section_name);
+ while ((p = strchr(p, '/')) != NULL)
+ *p = '_';
+
+ return name;
+}
+
+int
+bpf_object__pin_programs(struct bpf_object* obj, const char* path)
+{
+ struct bpf_program* prog;
+ int err;
+
+ if (!obj)
+ return libbpf_err(-ENOENT);
+
+ bpf_object__for_each_program(prog, obj)
+ {
+ char buf[PATH_MAX];
+ int len;
+
+ len = snprintf(buf, PATH_MAX, "%s/%s", path, __bpf_program__pin_name(prog));
+ if (len < 0) {
+ err = -EINVAL;
+ goto err_unpin_programs;
+ } else if (len >= PATH_MAX) {
+ err = -ENAMETOOLONG;
+ goto err_unpin_programs;
+ }
+
+ err = bpf_program__pin(prog, buf);
+ if (err) {
+ goto err_unpin_programs;
+ }
+ }
+
+ return 0;
+
+err_unpin_programs:
+ while ((prog = bpf_program__prev(prog, obj)) != NULL) {
+ char buf[PATH_MAX];
+ int len;
+
+ len = snprintf(buf, PATH_MAX, "%s/%s", path, __bpf_program__pin_name(prog));
+ if (len < 0)
+ continue;
+ else if (len >= PATH_MAX)
+ continue;
+
+ bpf_program__unpin(prog, path);
+ }
+ return err;
+}
+
+int
+bpf_object__unpin_programs(struct bpf_object* obj, const char* path)
+{
+ struct bpf_program* prog;
+ int err;
+
+ if (!obj)
+ return libbpf_err(-ENOENT);
+
+ bpf_object__for_each_program(prog, obj)
+ {
+ char buf[PATH_MAX];
+ int len;
+
+ len = snprintf(buf, PATH_MAX, "%s/%s", path, __bpf_program__pin_name(prog));
+ if (len < 0)
+ return libbpf_err(-EINVAL);
+ else if (len >= PATH_MAX)
+ return libbpf_err(-ENAMETOOLONG);
+
+ err = bpf_program__unpin(prog, buf);
+ if (err)
+ return libbpf_err(err);
+ }
+
+ return 0;
+}
+
+int
+bpf_link__destroy(struct bpf_link* link)
+{
+ // TODO(issue #81): get handle from ebpf_link_t, and
+ // detach before closing the handle.
+ ebpf_handle_t link_handle = (ebpf_handle_t)link;
+ uint32_t result = ebpf_api_close_handle(link_handle);
+ return (int)result;
+}
+
+enum bpf_attach_type
+bpf_program__get_expected_attach_type(const struct bpf_program* program)
+{
+ return _get_bpf_attach_type(&program->attach_type);
+}
+
+void
+bpf_program__set_expected_attach_type(struct bpf_program* program, enum bpf_attach_type type)
+{
+ program->attach_type = *_get_ebpf_attach_type(type);
+}
diff --git a/tests/end_to_end/end_to_end.cpp b/tests/end_to_end/end_to_end.cpp
index 5efa2c1be..17742281a 100644
--- a/tests/end_to_end/end_to_end.cpp
+++ b/tests/end_to_end/end_to_end.cpp
@@ -11,6 +11,7 @@
#include "catch_wrapper.hpp"
#include "common_tests.h"
#include "ebpf_bind_program_data.h"
+#include "ebpf_core.h"
#include "ebpf_xdp_program_data.h"
#include "helpers.h"
#include "mock.h"
@@ -161,7 +162,7 @@ droppacket_test(ebpf_execution_type_t execution_type)
uint32_t result = 0;
const char* error_message = NULL;
- single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP);
+ single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP, EBPF_ATTACH_TYPE_XDP);
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
REQUIRE(
@@ -231,7 +232,7 @@ divide_by_zero_test(ebpf_execution_type_t execution_type)
uint32_t result = 0;
const char* error_message = NULL;
- single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP);
+ single_instance_hook_t hook(EBPF_PROGRAM_TYPE_XDP, EBPF_ATTACH_TYPE_XDP);
program_info_provider_t xdp_program_info(EBPF_PROGRAM_TYPE_XDP);
REQUIRE(
@@ -339,7 +340,7 @@ bindmonitor_test(ebpf_execution_type_t execution_type)
error_message = nullptr,
result == EBPF_SUCCESS));
- single_instance_hook_t hook(EBPF_PROGRAM_TYPE_BIND);
+ single_instance_hook_t hook(EBPF_PROGRAM_TYPE_BIND, EBPF_ATTACH_TYPE_BIND);
REQUIRE(hook.attach(program_handle) == EBPF_SUCCESS);
@@ -481,7 +482,7 @@ TEST_CASE("map_pinning_test", "[end_to_end]")
error_message = nullptr,
result == EBPF_SUCCESS));
- single_instance_hook_t hook(EBPF_PROGRAM_TYPE_BIND);
+ single_instance_hook_t hook(EBPF_PROGRAM_TYPE_BIND, EBPF_ATTACH_TYPE_BIND);
std::string process_maps_name = "bindmonitor::process_maps";
std::string limit_maps_name = "bindmonitor::limits_map";
@@ -562,7 +563,7 @@ TEST_CASE("enumerate_and_query_maps", "[end_to_end]")
error_message = nullptr,
result == EBPF_SUCCESS));
- single_instance_hook_t hook(EBPF_PROGRAM_TYPE_BIND);
+ single_instance_hook_t hook(EBPF_PROGRAM_TYPE_BIND, EBPF_ATTACH_TYPE_BIND);
std::string process_maps_name = "bindmonitor::process_maps";
std::string limit_maps_name = "bindmonitor::limits_map";
diff --git a/tests/end_to_end/helpers.h b/tests/end_to_end/helpers.h
index 6582af9da..d96d4c9b2 100644
--- a/tests/end_to_end/helpers.h
+++ b/tests/end_to_end/helpers.h
@@ -23,13 +23,13 @@ typedef std::unique_ptr ebpf_memory_t;
typedef class _single_instance_hook
{
public:
- _single_instance_hook(ebpf_program_type_t program_type)
+ _single_instance_hook(ebpf_program_type_t program_type, ebpf_attach_type_t attach_type)
: provider(nullptr), client_binding_context(nullptr), client_data(nullptr), client_dispatch_table(nullptr),
link_handle(nullptr)
{
- ebpf_guid_create(&attach_type);
ebpf_guid_create(&client_id);
attach_provider_data.supported_program_type = program_type;
+ this->attach_type = attach_type;
REQUIRE(
ebpf_provider_load(
&provider,
@@ -120,15 +120,13 @@ static ebpf_helper_function_prototype_t _ebpf_map_helper_function_prototype[] =
EBPF_RETURN_TYPE_INTEGER,
{EBPF_ARGUMENT_TYPE_PTR_TO_MAP, EBPF_ARGUMENT_TYPE_PTR_TO_MAP_KEY}}};
-static ebpf_context_descriptor_t _ebpf_xdp_context_descriptor = {
- sizeof(xdp_md_t),
- EBPF_OFFSET_OF(xdp_md_t, data),
- EBPF_OFFSET_OF(xdp_md_t, data_end),
- EBPF_OFFSET_OF(xdp_md_t, data_meta)};
-static ebpf_program_info_t _ebpf_xdp_program_info = {
- {"xdp", &_ebpf_xdp_context_descriptor, {0}},
- EBPF_COUNT_OF(_ebpf_map_helper_function_prototype),
- _ebpf_map_helper_function_prototype};
+static ebpf_context_descriptor_t _ebpf_xdp_context_descriptor = {sizeof(xdp_md_t),
+ EBPF_OFFSET_OF(xdp_md_t, data),
+ EBPF_OFFSET_OF(xdp_md_t, data_end),
+ EBPF_OFFSET_OF(xdp_md_t, data_meta)};
+static ebpf_program_info_t _ebpf_xdp_program_info = {{"xdp", &_ebpf_xdp_context_descriptor, {0}},
+ EBPF_COUNT_OF(_ebpf_map_helper_function_prototype),
+ _ebpf_map_helper_function_prototype};
static ebpf_program_data_t _ebpf_xdp_program_data = {&_ebpf_xdp_program_info, NULL};
@@ -137,10 +135,9 @@ static ebpf_extension_data_t _ebpf_xdp_program_info_provider_data = {
static ebpf_context_descriptor_t _ebpf_bind_context_descriptor = {
sizeof(bind_md_t), EBPF_OFFSET_OF(bind_md_t, app_id_start), EBPF_OFFSET_OF(bind_md_t, app_id_end), -1};
-static ebpf_program_info_t _ebpf_bind_program_info = {
- {"bind", &_ebpf_bind_context_descriptor, {0}},
- EBPF_COUNT_OF(_ebpf_map_helper_function_prototype),
- _ebpf_map_helper_function_prototype};
+static ebpf_program_info_t _ebpf_bind_program_info = {{"bind", &_ebpf_bind_context_descriptor, {0}},
+ EBPF_COUNT_OF(_ebpf_map_helper_function_prototype),
+ _ebpf_map_helper_function_prototype};
static ebpf_program_data_t _ebpf_bind_program_data = {&_ebpf_bind_program_info, NULL};
diff --git a/tests/end_to_end/test_helper.cpp b/tests/end_to_end/test_helper.cpp
new file mode 100644
index 000000000..74d99b883
--- /dev/null
+++ b/tests/end_to_end/test_helper.cpp
@@ -0,0 +1,67 @@
+// Copyright (c) Microsoft Corporation
+// SPDX-License-Identifier: MIT
+#include "catch_wrapper.hpp"
+#include "ebpf_api.h"
+#include "ebpf_core.h"
+#include "helpers.h"
+#include "mock.h"
+#include "test_helper.hpp"
+
+BOOL
+GlueCloseHandle(ebpf_handle_t hObject);
+
+ebpf_handle_t
+GlueCreateFileW(
+ PCWSTR lpFileName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ PSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDisposition,
+ DWORD dwFlagsAndAttributes,
+ ebpf_handle_t hTemplateFile);
+
+BOOL
+GlueDeviceIoControl(
+ ebpf_handle_t hDevice,
+ DWORD dwIoControlCode,
+ PVOID lpInBuffer,
+ DWORD nInBufferSize,
+ LPVOID lpOutBuffer,
+ DWORD nOutBufferSize,
+ PDWORD lpBytesReturned,
+ OVERLAPPED* lpOverlapped);
+
+_test_helper_end_to_end::_test_helper_end_to_end()
+{
+ device_io_control_handler = GlueDeviceIoControl;
+ create_file_handler = GlueCreateFileW;
+ close_handle_handler = GlueCloseHandle;
+ REQUIRE(ebpf_core_initiate() == EBPF_SUCCESS);
+ ec_initialized = true;
+ REQUIRE(ebpf_api_initiate() == EBPF_SUCCESS);
+ api_initialized = true;
+}
+
+_test_helper_end_to_end::~_test_helper_end_to_end()
+{
+ if (api_initialized)
+ ebpf_api_terminate();
+ if (ec_initialized)
+ ebpf_core_terminate();
+
+ device_io_control_handler = nullptr;
+ create_file_handler = nullptr;
+ close_handle_handler = nullptr;
+}
+
+_test_helper_libbpf::_test_helper_libbpf()
+{
+ xdp_program_info = new program_info_provider_t(EBPF_PROGRAM_TYPE_XDP);
+ hook = new single_instance_hook_t(EBPF_PROGRAM_TYPE_XDP, EBPF_ATTACH_TYPE_XDP);
+}
+
+_test_helper_libbpf::~_test_helper_libbpf()
+{
+ delete hook;
+ delete xdp_program_info;
+}
diff --git a/tests/end_to_end/test_helper.hpp b/tests/end_to_end/test_helper.hpp
index 88b64d708..c2a8a7814 100644
--- a/tests/end_to_end/test_helper.hpp
+++ b/tests/end_to_end/test_helper.hpp
@@ -1,60 +1,29 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
#pragma once
-#include "ebpf_api.h"
-#include "ebpf_core.h"
-#include "mock.h"
-
-BOOL
-GlueCloseHandle(ebpf_handle_t hObject);
-
-ebpf_handle_t
-GlueCreateFileW(
- PCWSTR lpFileName,
- DWORD dwDesiredAccess,
- DWORD dwShareMode,
- PSECURITY_ATTRIBUTES lpSecurityAttributes,
- DWORD dwCreationDisposition,
- DWORD dwFlagsAndAttributes,
- ebpf_handle_t hTemplateFile);
-
-BOOL
-GlueDeviceIoControl(
- ebpf_handle_t hDevice,
- DWORD dwIoControlCode,
- PVOID lpInBuffer,
- DWORD nInBufferSize,
- LPVOID lpOutBuffer,
- DWORD nOutBufferSize,
- PDWORD lpBytesReturned,
- OVERLAPPED* lpOverlapped);
class _test_helper_end_to_end
{
public:
- _test_helper_end_to_end()
- {
- device_io_control_handler = GlueDeviceIoControl;
- create_file_handler = GlueCreateFileW;
- close_handle_handler = GlueCloseHandle;
- REQUIRE(ebpf_core_initiate() == EBPF_SUCCESS);
- ec_initialized = true;
- REQUIRE(ebpf_api_initiate() == EBPF_SUCCESS);
- api_initialized = true;
- }
- ~_test_helper_end_to_end()
- {
- if (api_initialized)
- ebpf_api_terminate();
- if (ec_initialized)
- ebpf_core_terminate();
-
- device_io_control_handler = nullptr;
- create_file_handler = nullptr;
- close_handle_handler = nullptr;
- }
+ _test_helper_end_to_end();
+ ~_test_helper_end_to_end();
private:
bool ec_initialized = false;
bool api_initialized = false;
};
+
+class _program_info_provider;
+class _single_instance_hook;
+
+class _test_helper_libbpf
+{
+ public:
+ _test_helper_libbpf();
+ ~_test_helper_libbpf();
+
+ private:
+ _test_helper_end_to_end test_helper_end_to_end;
+ _program_info_provider* xdp_program_info;
+ _single_instance_hook* hook;
+};
diff --git a/tests/unit/libbpf_test.cpp b/tests/unit/libbpf_test.cpp
new file mode 100644
index 000000000..de4f7bf22
--- /dev/null
+++ b/tests/unit/libbpf_test.cpp
@@ -0,0 +1,251 @@
+// Copyright (c) Microsoft Corporation
+// SPDX-License-Identifier: MIT
+#include "catch_wrapper.hpp"
+#pragma warning(push)
+#pragma warning(disable : 4200)
+#include "libbpf.h"
+#pragma warning(pop)
+#include "test_helper.hpp"
+
+// libbpf.h uses enum types and generates the
+// following warning whenever an enum type is used below:
+// "The enum type 'bpf_attach_type' is unscoped.
+// Prefer 'enum class' over 'enum'"
+#pragma warning(disable : 26812)
+
+TEST_CASE("libbpf program", "[libbpf]")
+{
+ _test_helper_libbpf test_helper;
+
+ struct bpf_object* object;
+ int program_fd;
+ int result = bpf_prog_load("droppacket.o", BPF_PROG_TYPE_XDP, &object, &program_fd);
+ REQUIRE(result == 0);
+ REQUIRE(object != nullptr);
+ REQUIRE(program_fd != -1);
+
+ const char* name = bpf_object__name(object);
+ REQUIRE(strcmp(name, "droppacket.o") == 0);
+
+ struct bpf_program* program = bpf_object__find_program_by_name(object, "DropPacket");
+ REQUIRE(program != nullptr);
+
+ name = bpf_program__section_name(program);
+ REQUIRE(strcmp(name, "xdp") == 0);
+
+ name = bpf_program__name(program);
+ REQUIRE(strcmp(name, "DropPacket") == 0);
+
+ int fd2 = bpf_program__fd(program);
+ REQUIRE(fd2 == program_fd);
+
+ size_t size = bpf_program__size(program);
+ REQUIRE(size == 192);
+
+ REQUIRE(bpf_program__next(program, object) == nullptr);
+ REQUIRE(bpf_program__prev(program, object) == nullptr);
+ REQUIRE(bpf_program__next(nullptr, object) == program);
+ REQUIRE(bpf_program__prev(nullptr, object) == program);
+
+ bpf_object__close(object);
+}
+
+TEST_CASE("libbpf program pinning", "[libbpf]")
+{
+ _test_helper_libbpf test_helper;
+ const char* pin_path = "\\temp\\test";
+
+ struct bpf_object* object;
+ int program_fd;
+ int result = bpf_prog_load("droppacket.o", BPF_PROG_TYPE_XDP, &object, &program_fd);
+ REQUIRE(result == 0);
+ REQUIRE(object != nullptr);
+
+ struct bpf_program* program = bpf_object__find_program_by_name(object, "DropPacket");
+ REQUIRE(program != nullptr);
+
+ // Try to pin the program.
+ result = bpf_program__pin(program, pin_path);
+ REQUIRE(result == 0);
+
+ // Make sure a duplicate pin fails.
+ result = bpf_program__pin(program, pin_path);
+ REQUIRE(result != 0);
+
+ result = bpf_program__unpin(program, pin_path);
+ REQUIRE(result == 0);
+
+ // Make sure a duplicate unpin fails.
+ result = bpf_program__unpin(program, pin_path);
+ REQUIRE(result != 0);
+
+ // Try to pin all (1) programs in the object.
+ result = bpf_object__pin_programs(object, pin_path);
+ REQUIRE(result == 0);
+
+ // Make sure a duplicate pin fails.
+ result = bpf_object__pin_programs(object, pin_path);
+ REQUIRE(result != 0);
+
+ result = bpf_object__unpin_programs(object, pin_path);
+ REQUIRE(result == 0);
+
+ // Try to pin all programs and maps in the object.
+ result = bpf_object__pin(object, pin_path);
+ REQUIRE(result == 0);
+
+ // Make sure a duplicate pin fails.
+ result = bpf_object__pin_programs(object, pin_path);
+ REQUIRE(result != 0);
+
+ // There is no bpf_object__unpin API, so
+ // we have to unpin programs and maps separately.
+ result = bpf_object__unpin_programs(object, pin_path);
+ REQUIRE(result == 0);
+
+ result = bpf_object__unpin_maps(object, pin_path);
+ REQUIRE(result == 0);
+
+ bpf_object__close(object);
+}
+
+TEST_CASE("libbpf program attach", "[libbpf]")
+{
+ _test_helper_libbpf test_helper;
+
+ struct bpf_object* object;
+ int program_fd;
+ int result = bpf_prog_load("droppacket.o", BPF_PROG_TYPE_XDP, &object, &program_fd);
+ REQUIRE(result == 0);
+ REQUIRE(object != nullptr);
+
+ struct bpf_program* program = bpf_object__find_program_by_name(object, "DropPacket");
+ REQUIRE(program != nullptr);
+
+ // Based on the program type, verify that the
+ // default attach type is set correctly.
+ // TODO: it is not currently set. Update this
+ // test once it is set correctly.
+ enum bpf_attach_type type = bpf_program__get_expected_attach_type(program);
+ REQUIRE(type == BPF_ATTACH_TYPE_UNKNOWN);
+
+ bpf_program__set_expected_attach_type(program, BPF_ATTACH_TYPE_XDP);
+
+ type = bpf_program__get_expected_attach_type(program);
+ REQUIRE(type == BPF_ATTACH_TYPE_XDP);
+
+ bpf_link* link = bpf_program__attach(program);
+ REQUIRE(link != nullptr);
+
+ result = bpf_link__destroy(link);
+ REQUIRE(result == 0);
+
+ // Verify that a duplicate link destroy fails.
+ result = bpf_link__destroy(link);
+ REQUIRE(result != 0);
+
+ bpf_object__close(object);
+}
+
+TEST_CASE("libbpf map", "[libbpf]")
+{
+ _test_helper_libbpf test_helper;
+
+ struct bpf_object* object;
+ int program_fd;
+ int result = bpf_prog_load("droppacket.o", BPF_PROG_TYPE_XDP, &object, &program_fd);
+ REQUIRE(result == 0);
+ REQUIRE(object != nullptr);
+
+ // Get the first (and only) map.
+ struct bpf_map* map = bpf_map__next(nullptr, object);
+ REQUIRE(map != nullptr);
+
+ // Verify that it's the only map.
+ REQUIRE(bpf_map__next(map, object) == nullptr);
+ REQUIRE(bpf_map__prev(map, object) == nullptr);
+ REQUIRE(bpf_map__prev(nullptr, object) == map);
+
+ const char* name = bpf_map__name(map);
+ REQUIRE(name == nullptr); // droppacket.o has no map name.
+ REQUIRE(bpf_map__type(map) == BPF_MAP_TYPE_ARRAY);
+ REQUIRE(bpf_map__key_size(map) == 4);
+ REQUIRE(bpf_map__value_size(map) == 8);
+ REQUIRE(bpf_map__max_entries(map) == 1);
+ REQUIRE(bpf_map__fd(map) > 0);
+
+ bpf_object__close(object);
+}
+
+TEST_CASE("libbpf map pinning", "[libbpf]")
+{
+ _test_helper_libbpf test_helper;
+ const char* pin_path = "\\temp\\test";
+
+ struct bpf_object* object;
+ int program_fd;
+ int result = bpf_prog_load("droppacket.o", BPF_PROG_TYPE_XDP, &object, &program_fd);
+ REQUIRE(result == 0);
+ REQUIRE(object != nullptr);
+
+ struct bpf_map* map = bpf_map__next(nullptr, object);
+ REQUIRE(map != nullptr);
+
+ REQUIRE(bpf_map__is_pinned(map) == false);
+
+ // Try to pin the map.
+ result = bpf_map__pin(map, pin_path);
+ REQUIRE(result == 0);
+
+ REQUIRE(bpf_map__is_pinned(map) == true);
+
+ // Make sure a duplicate pin fails.
+ result = bpf_map__pin(map, pin_path);
+ REQUIRE(result != 0);
+
+ result = bpf_map__unpin(map, pin_path);
+ REQUIRE(result == 0);
+
+ REQUIRE(bpf_map__is_pinned(map) == false);
+
+ // Make sure a duplicate unpin fails.
+ result = bpf_map__unpin(map, pin_path);
+ REQUIRE(result != 0);
+
+ // Try to pin all (1) maps in the object.
+ result = bpf_object__pin_maps(object, pin_path);
+ REQUIRE(result == 0);
+
+ REQUIRE(bpf_map__is_pinned(map) == true);
+
+ // Make sure a duplicate pin fails.
+ result = bpf_object__pin_maps(object, pin_path);
+ REQUIRE(result != 0);
+
+ result = bpf_object__unpin_maps(object, pin_path);
+ REQUIRE(result == 0);
+
+ REQUIRE(bpf_map__is_pinned(map) == false);
+
+ // Try to pin all programs and maps in the object.
+ result = bpf_object__pin(object, pin_path);
+ REQUIRE(result == 0);
+
+ REQUIRE(bpf_map__is_pinned(map) == true);
+
+ // Make sure a duplicate pin fails.
+ result = bpf_object__pin_maps(object, pin_path);
+ REQUIRE(result != 0);
+
+ // There is no bpf_object__unpin API, so
+ // we have to unpin programs and maps separately.
+ result = bpf_object__unpin_programs(object, pin_path);
+ REQUIRE(result == 0);
+
+ result = bpf_object__unpin_maps(object, pin_path);
+ REQUIRE(result == 0);
+
+ REQUIRE(bpf_map__is_pinned(map) == false);
+
+ bpf_object__close(object);
+}
diff --git a/tests/unit/test.vcxproj b/tests/unit/test.vcxproj
index 26bab6936..a0c8d8e19 100644
--- a/tests/unit/test.vcxproj
+++ b/tests/unit/test.vcxproj
@@ -95,7 +95,7 @@
WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
MultiThreadedDebug
- $(SolutionDir)include;$(SolutionDir)libs\api;$(SolutionDir)libs\ebpfnetsh;$(SolutionDir)tests\libs\util;$(SolutionDir)tests\libs\common;$(OutDir);$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)libs\service;$(SolutionDir)rpc_interface;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)tests\end_to_end;%(AdditionalIncludeDirectories)
+ $(SolutionDir)include;$(SolutionDir)libs\api;$(SolutionDir)libs\ebpfnetsh;$(SolutionDir)tests\libs\util;$(SolutionDir)tests\libs\common;$(OutDir);$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)libs\service;$(SolutionDir)rpc_interface;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)tests\end_to_end;$(SolutionDir)external\libbpf\src;%(AdditionalIncludeDirectories)
Console
@@ -110,7 +110,7 @@
true
WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
- $(SolutionDir)include;$(SolutionDir)libs\api;$(SolutionDir)libs\ebpfnetsh;$(SolutionDir)tests\libs\util;$(SolutionDir)tests\libs\common;$(OutDir);$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)libs\service;$(SolutionDir)rpc_interface;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)tests\end_to_end;%(AdditionalIncludeDirectories)
+ $(SolutionDir)include;$(SolutionDir)libs\api;$(SolutionDir)libs\ebpfnetsh;$(SolutionDir)tests\libs\util;$(SolutionDir)tests\libs\common;$(OutDir);$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)libs\service;$(SolutionDir)rpc_interface;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)tests\end_to_end;$(SolutionDir)external\libbpf\src;%(AdditionalIncludeDirectories)
Console
@@ -125,7 +125,7 @@
true
_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
- $(SolutionDir)include;$(SolutionDir)libs\api;$(SolutionDir)libs\ebpfnetsh;$(SolutionDir)tests\libs\util;$(SolutionDir)tests\libs\common;$(OutDir);$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)libs\service;$(SolutionDir)rpc_interface;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)tests\end_to_end;%(AdditionalIncludeDirectories)
+ $(SolutionDir)include;$(SolutionDir)libs\api;$(SolutionDir)libs\ebpfnetsh;$(SolutionDir)tests\libs\util;$(SolutionDir)tests\libs\common;$(OutDir);$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)libs\service;$(SolutionDir)rpc_interface;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)tests\end_to_end;$(SolutionDir)external\libbpf\src;%(AdditionalIncludeDirectories)
true
stdcpp17
MultiThreadedDebug
@@ -144,7 +144,7 @@
true
NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
- $(SolutionDir)include;$(SolutionDir)libs\api;$(SolutionDir)libs\ebpfnetsh;$(SolutionDir)tests\libs\util;$(SolutionDir)tests\libs\common;$(OutDir);$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)libs\service;$(SolutionDir)rpc_interface;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)tests\end_to_end;%(AdditionalIncludeDirectories)
+ $(SolutionDir)include;$(SolutionDir)libs\api;$(SolutionDir)libs\ebpfnetsh;$(SolutionDir)tests\libs\util;$(SolutionDir)tests\libs\common;$(OutDir);$(SolutionDir)external\ebpf-verifier\src;$(SolutionDir)libs\service;$(SolutionDir)rpc_interface;$(SolutionDir)libs\platform;$(SolutionDir)libs\platform\user;$(SolutionDir)libs\execution_context;$(SolutionDir)tests\end_to_end;$(SolutionDir)external\libbpf\src;%(AdditionalIncludeDirectories)
true
stdcpp17
@@ -203,6 +203,8 @@
+
+
diff --git a/tests/unit/test.vcxproj.filters b/tests/unit/test.vcxproj.filters
index c0acc4f4b..3f23ad73b 100644
--- a/tests/unit/test.vcxproj.filters
+++ b/tests/unit/test.vcxproj.filters
@@ -40,6 +40,12 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+