1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <android-base/file.h> 18 #include <android-base/macros.h> 19 #include <gtest/gtest.h> 20 #include <libbpf.h> 21 #include <stdlib.h> 22 #include <unistd.h> 23 #include <iostream> 24 #include "bpf/BpfMap.h" 25 #include "bpf/BpfUtils.h" 26 #include "include/libbpf_android.h" 27 28 namespace android { 29 namespace bpf { 30 31 class BpfLoadTest : public ::testing::Test { 32 protected: BpfLoadTest()33 BpfLoadTest() {} 34 int mProgFd; 35 std::string mTpProgPath; 36 std::string mTpNeverLoadProgPath; 37 std::string mTpMapPath; 38 SetUp()39 void SetUp() { 40 /* 41 * b/326156952 42 * 43 * Kernels prior to 5.11 used rlimit memlock accounting for bpf memory 44 * allocations, and therefore require increasing the rlimit of this 45 * process for the maps to be created successfully. 46 * 47 * 5.11 introduces cgroup-based accounting as discussed here: 48 * https://lore.kernel.org/bpf/20201201215900.3569844-1-guro@fb.com/ 49 */ 50 if (!isAtLeastKernelVersion(5, 11, 0)) EXPECT_EQ(setrlimitForTest(), 0); 51 52 mTpProgPath = "/sys/fs/bpf/prog_bpfLoadTpProg_tracepoint_sched_sched_switch"; 53 unlink(mTpProgPath.c_str()); 54 55 mTpNeverLoadProgPath = "/sys/fs/bpf/prog_bpfLoadTpProg_tracepoint_sched_sched_wakeup"; 56 unlink(mTpNeverLoadProgPath.c_str()); 57 58 mTpMapPath = "/sys/fs/bpf/map_bpfLoadTpProg_cpu_pid_map"; 59 unlink(mTpMapPath.c_str()); 60 61 auto progPath = android::base::GetExecutableDirectory() + "/bpfLoadTpProg.o"; 62 bool critical = true; 63 64 bpf_prog_type kAllowed[] = { 65 BPF_PROG_TYPE_UNSPEC, 66 }; 67 68 Location loc = { 69 .dir = "", 70 .prefix = "", 71 .allowedProgTypes = kAllowed, 72 .allowedProgTypesLength = arraysize(kAllowed), 73 }; 74 EXPECT_EQ(android::bpf::loadProg(progPath.c_str(), &critical, loc), -1); 75 76 ASSERT_EQ(android::bpf::loadProg(progPath.c_str(), &critical), 0); 77 EXPECT_EQ(false, critical); 78 79 mProgFd = retrieveProgram(mTpProgPath.c_str()); 80 ASSERT_GT(mProgFd, 0); 81 82 int ret = bpf_attach_tracepoint(mProgFd, "sched", "sched_switch"); 83 EXPECT_NE(ret, 0); 84 } 85 TearDown()86 void TearDown() { 87 close(mProgFd); 88 unlink(mTpProgPath.c_str()); 89 unlink(mTpMapPath.c_str()); 90 } 91 checkMapNonZero()92 void checkMapNonZero() { 93 // The test program installs a tracepoint on sched:sched_switch 94 // and expects the kernel to populate a PID corresponding to CPU 95 android::bpf::BpfMap<uint32_t, uint32_t> m(mTpMapPath.c_str()); 96 97 // Wait for program to run a little 98 sleep(1); 99 100 int non_zero = 0; 101 const auto iterFunc = [&non_zero](const uint32_t& key, const uint32_t& val, 102 BpfMap<uint32_t, uint32_t>& map) { 103 if (val && !non_zero) { 104 non_zero = 1; 105 } 106 107 UNUSED(key); 108 UNUSED(map); 109 return base::Result<void>(); 110 }; 111 112 EXPECT_RESULT_OK(m.iterateWithValue(iterFunc)); 113 EXPECT_EQ(non_zero, 1); 114 } 115 checkKernelVersionEnforced()116 void checkKernelVersionEnforced() { 117 ASSERT_EQ(retrieveProgram(mTpNeverLoadProgPath.c_str()), -1); 118 ASSERT_EQ(errno, ENOENT); 119 } 120 }; 121 TEST_F(BpfLoadTest,bpfCheckMap)122 TEST_F(BpfLoadTest, bpfCheckMap) { 123 checkMapNonZero(); 124 } 125 TEST_F(BpfLoadTest,bpfCheckMinKernelVersionEnforced)126 TEST_F(BpfLoadTest, bpfCheckMinKernelVersionEnforced) { 127 checkKernelVersionEnforced(); 128 } 129 130 } // namespace bpf 131 } // namespace android 132