/* * Copyright (c) 2017 Politecnico di Torino * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "BPF.h" #include "catch.hpp" #include <random> #include <iostream> #include <linux/version.h> TEST_CASE("test array table", "[array_table]") { const std::string BPF_PROGRAM = R"( BPF_TABLE("hash", int, int, myhash, 128); BPF_TABLE("array", int, int, myarray, 128); )"; // turn off the rw_engine ebpf::BPF bpf(0, nullptr, false); ebpf::StatusTuple res(0); res = bpf.init(BPF_PROGRAM); REQUIRE(res.code() == 0); ebpf::BPFArrayTable<int> t = bpf.get_array_table<int>("myarray"); SECTION("bad table type") { // try to get table of wrong type auto f1 = [&](){ bpf.get_array_table<int>("myhash"); }; REQUIRE_THROWS(f1()); } SECTION("standard methods") { int i, v1, v2; i = 1; v1 = 42; // update element res = t.update_value(i, v1); REQUIRE(res.code() == 0); res = t.get_value(i, v2); REQUIRE(res.code() == 0); REQUIRE(v2 == 42); // update another element i = 2; v1 = 69; res = t.update_value(i, v1); REQUIRE(res.code() == 0); res = t.get_value(i, v2); REQUIRE(res.code() == 0); REQUIRE(v2 == 69); // get non existing element i = 1024; res = t.get_value(i, v2); REQUIRE(res.code() != 0); } SECTION("full table") { // random number generator std::mt19937 rng; rng.seed(std::random_device()()); std::uniform_int_distribution<int> dist; std::vector<int> localtable(128); for(int i = 0; i < 128; i++) { int v = dist(rng); res = t.update_value(i, v); REQUIRE(res.code() == 0); // save it in the local table to compare later on localtable[i] = v; } std::vector<int> offlinetable = t.get_table_offline(); REQUIRE(localtable == offlinetable); } } #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0) TEST_CASE("percpu array table", "[percpu_array_table]") { const std::string BPF_PROGRAM = R"( BPF_TABLE("percpu_hash", int, u64, myhash, 128); BPF_TABLE("percpu_array", int, u64, myarray, 64); )"; ebpf::BPF bpf; ebpf::StatusTuple res(0); res = bpf.init(BPF_PROGRAM); REQUIRE(res.code() == 0); ebpf::BPFPercpuArrayTable<uint64_t> t = bpf.get_percpu_array_table<uint64_t>("myarray"); size_t ncpus = ebpf::BPFTable::get_possible_cpu_count(); SECTION("bad table type") { // try to get table of wrong type auto f1 = [&](){ bpf.get_percpu_array_table<uint64_t>("myhash"); }; REQUIRE_THROWS(f1()); } SECTION("standard methods") { int i; std::vector<uint64_t> v1(ncpus); std::vector<uint64_t> v2; for (size_t j = 0; j < ncpus; j++) { v1[j] = 42 * j; } i = 1; // update element res = t.update_value(i, v1); REQUIRE(res.code() == 0); res = t.get_value(i, v2); REQUIRE(res.code() == 0); REQUIRE(v2.size() == ncpus); for (size_t j = 0; j < ncpus; j++) { REQUIRE(v2.at(j) == 42 * j); } // get non existing element i = 1024; res = t.get_value(i, v2); REQUIRE(res.code() != 0); } } #endif