From d7942ba3dca4361da0cf118e3d7657ee8268e22a Mon Sep 17 00:00:00 2001 From: Anurag Saxena <43585259+saxena-anurag@users.noreply.github.com> Date: Fri, 19 Jul 2024 12:07:14 -0700 Subject: [PATCH] Add test case for program order in native module (#3686) * add test for program order * Apply suggestions from code review Co-authored-by: Dave Thaler * cr comments --------- Co-authored-by: Dave Thaler --- tests/api_test/api_test.cpp | 46 +++++++++++++++++++++++++++++ tests/sample/multiple_programs.c | 43 +++++++++++++++++++++++++++ tests/sample/sample.vcxproj.filters | 5 +++- 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 tests/sample/multiple_programs.c diff --git a/tests/api_test/api_test.cpp b/tests/api_test/api_test.cpp index ae1b5f6f1f..08317b41af 100644 --- a/tests/api_test/api_test.cpp +++ b/tests/api_test/api_test.cpp @@ -1334,3 +1334,49 @@ TEST_CASE("test_ringbuffer_wraparound", "[stress]") // Clean up. bpf_object__close(object); } + +TEST_CASE("Test program order", "[native_tests]") +{ + struct bpf_object* object = nullptr; + fd_t program_fd; + uint32_t program_count = 4; + int result; + + REQUIRE( + _program_load_helper( + "multiple_programs.sys", BPF_PROG_TYPE_SAMPLE, EBPF_EXECUTION_NATIVE, &object, &program_fd) == 0); + + // Get all 4 programs in the native object, and invoke them using bpf_prog_test_run. + // + // If there is a mismatch in the sorting order of bpf2c and ebpfapi, the 4 eBPF programs + // in this object file will be initialized with wrong handles. That will cause wrong programs + // to be invoked when bpf_prog_test_run is called. Since each program returns a different value, + // we can validate that the correct / expected program was invoked by checking the return value. + for (uint32_t i = 0; i < program_count; i++) { + bpf_test_run_opts opts = {}; + bind_md_t ctx = {}; + std::string program_name = "program" + std::to_string(i + 1); + struct bpf_program* program = bpf_object__find_program_by_name(object, program_name.c_str()); + REQUIRE(program != nullptr); + program_fd = bpf_program__fd(program); + REQUIRE(program_fd > 0); + + std::string app_id = "api_test.exe"; + + opts.ctx_in = &ctx; + opts.ctx_size_in = sizeof(ctx); + opts.ctx_out = &ctx; + opts.ctx_size_out = sizeof(ctx); + opts.data_in = app_id.data(); + opts.data_size_in = static_cast(app_id.size()); + opts.data_out = app_id.data(); + opts.data_size_out = static_cast(app_id.size()); + + result = bpf_prog_test_run_opts(program_fd, &opts); + REQUIRE(result == 0); + REQUIRE(opts.retval == (i + 1)); + } + + // Clean up. + bpf_object__close(object); +} \ No newline at end of file diff --git a/tests/sample/multiple_programs.c b/tests/sample/multiple_programs.c new file mode 100644 index 0000000000..f6e8832822 --- /dev/null +++ b/tests/sample/multiple_programs.c @@ -0,0 +1,43 @@ +// Copyright (c) eBPF for Windows contributors +// SPDX-License-Identifier: MIT + +// Whenever this sample program changes, bpf2c_tests will fail unless the +// expected files in tests\bpf2c_tests\expected are updated. The following +// script can be used to regenerate the expected files: +// generate_expected_bpf2c_output.ps1 +// +// Usage: +// .\scripts\generate_expected_bpf2c_output.ps1 +// Example: +// .\scripts\generate_expected_bpf2c_output.ps1 .\x64\Debug\ + +#include "bpf_helpers.h" +#include "ebpf_nethooks.h" + +SEC("bind_2") +int +program3(bind_md_t* ctx) +{ + return 3; +} + +SEC("bind_4") +int +program1(bind_md_t* ctx) +{ + return 1; +} + +SEC("bind_3") +int +program2(bind_md_t* ctx) +{ + return 2; +} + +SEC("bind_1") +int +program4(bind_md_t* ctx) +{ + return 4; +} \ No newline at end of file diff --git a/tests/sample/sample.vcxproj.filters b/tests/sample/sample.vcxproj.filters index 0b5b64dacf..d9f6347fb6 100644 --- a/tests/sample/sample.vcxproj.filters +++ b/tests/sample/sample.vcxproj.filters @@ -1,4 +1,4 @@ - +