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 <fstream> 18 #include <iostream> 19 #include <string> 20 #include <vector> 21 22 #include <fcntl.h> 23 #include <inttypes.h> 24 #include <linux/inet_diag.h> 25 #include <linux/sock_diag.h> 26 #include <net/if.h> 27 #include <sys/socket.h> 28 #include <sys/types.h> 29 #include <unistd.h> 30 31 #include <gtest/gtest.h> 32 33 #include <android-base/stringprintf.h> 34 #include <android-base/strings.h> 35 36 #include "bpf/BpfMap.h" 37 #include "bpf/BpfUtils.h" 38 39 using ::testing::Test; 40 41 namespace android { 42 namespace bpf { 43 44 using base::Result; 45 using base::unique_fd; 46 47 constexpr uint32_t TEST_MAP_SIZE = 10; 48 constexpr uint32_t TEST_KEY1 = 1; 49 constexpr uint32_t TEST_VALUE1 = 10; 50 constexpr const char PINNED_MAP_PATH[] = "/sys/fs/bpf/testMap"; 51 52 class BpfMapTest : public testing::Test { 53 protected: 54 BpfMapTest() {} 55 56 void SetUp() { 57 EXPECT_EQ(0, setrlimitForTest()); 58 if (!access(PINNED_MAP_PATH, R_OK)) { 59 EXPECT_EQ(0, remove(PINNED_MAP_PATH)); 60 } 61 } 62 63 void TearDown() { 64 if (!access(PINNED_MAP_PATH, R_OK)) { 65 EXPECT_EQ(0, remove(PINNED_MAP_PATH)); 66 } 67 } 68 69 void checkMapInvalid(BpfMap<uint32_t, uint32_t>& map) { 70 EXPECT_FALSE(map.isValid()); 71 EXPECT_EQ(-1, map.getMap().get()); 72 } 73 74 void checkMapValid(BpfMap<uint32_t, uint32_t>& map) { 75 EXPECT_LE(0, map.getMap().get()); 76 EXPECT_TRUE(map.isValid()); 77 } 78 79 void writeToMapAndCheck(BpfMap<uint32_t, uint32_t>& map, uint32_t key, uint32_t value) { 80 ASSERT_RESULT_OK(map.writeValue(key, value, BPF_ANY)); 81 uint32_t value_read; 82 ASSERT_EQ(0, findMapEntry(map.getMap(), &key, &value_read)); 83 checkValueAndStatus(value, value_read); 84 } 85 86 void checkValueAndStatus(uint32_t refValue, Result<uint32_t> value) { 87 ASSERT_RESULT_OK(value); 88 ASSERT_EQ(refValue, value.value()); 89 } 90 91 void populateMap(uint32_t total, BpfMap<uint32_t, uint32_t>& map) { 92 for (uint32_t key = 0; key < total; key++) { 93 uint32_t value = key * 10; 94 EXPECT_RESULT_OK(map.writeValue(key, value, BPF_ANY)); 95 } 96 } 97 98 void expectMapEmpty(BpfMap<uint32_t, uint32_t>& map) { 99 Result<bool> isEmpty = map.isEmpty(); 100 ASSERT_RESULT_OK(isEmpty); 101 ASSERT_TRUE(isEmpty.value()); 102 } 103 }; 104 105 TEST_F(BpfMapTest, constructor) { 106 BpfMap<uint32_t, uint32_t> testMap1; 107 checkMapInvalid(testMap1); 108 109 BpfMap<uint32_t, uint32_t> testMap2(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); 110 checkMapValid(testMap2); 111 } 112 113 TEST_F(BpfMapTest, basicHelpers) { 114 BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); 115 uint32_t key = TEST_KEY1; 116 uint32_t value_write = TEST_VALUE1; 117 writeToMapAndCheck(testMap, key, value_write); 118 Result<uint32_t> value_read = testMap.readValue(key); 119 checkValueAndStatus(value_write, value_read); 120 Result<uint32_t> key_read = testMap.getFirstKey(); 121 checkValueAndStatus(key, key_read); 122 ASSERT_RESULT_OK(testMap.deleteValue(key)); 123 ASSERT_GT(0, findMapEntry(testMap.getMap(), &key, &value_read)); 124 ASSERT_EQ(ENOENT, errno); 125 } 126 127 TEST_F(BpfMapTest, reset) { 128 BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); 129 uint32_t key = TEST_KEY1; 130 uint32_t value_write = TEST_VALUE1; 131 writeToMapAndCheck(testMap, key, value_write); 132 133 testMap.reset(-1); 134 checkMapInvalid(testMap); 135 ASSERT_GT(0, findMapEntry(testMap.getMap(), &key, &value_write)); 136 ASSERT_EQ(EBADF, errno); 137 } 138 139 TEST_F(BpfMapTest, moveConstructor) { 140 BpfMap<uint32_t, uint32_t> testMap1(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); 141 BpfMap<uint32_t, uint32_t> testMap2; 142 testMap2 = std::move(testMap1); 143 uint32_t key = TEST_KEY1; 144 checkMapInvalid(testMap1); 145 uint32_t value = TEST_VALUE1; 146 writeToMapAndCheck(testMap2, key, value); 147 } 148 149 TEST_F(BpfMapTest, SetUpMap) { 150 EXPECT_NE(0, access(PINNED_MAP_PATH, R_OK)); 151 BpfMap<uint32_t, uint32_t> testMap1(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); 152 ASSERT_EQ(0, bpfFdPin(testMap1.getMap(), PINNED_MAP_PATH)); 153 EXPECT_EQ(0, access(PINNED_MAP_PATH, R_OK)); 154 checkMapValid(testMap1); 155 BpfMap<uint32_t, uint32_t> testMap2; 156 EXPECT_RESULT_OK(testMap2.init(PINNED_MAP_PATH)); 157 checkMapValid(testMap2); 158 uint32_t key = TEST_KEY1; 159 uint32_t value = TEST_VALUE1; 160 writeToMapAndCheck(testMap1, key, value); 161 Result<uint32_t> value_read = testMap2.readValue(key); 162 checkValueAndStatus(value, value_read); 163 } 164 165 TEST_F(BpfMapTest, iterate) { 166 BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); 167 populateMap(TEST_MAP_SIZE, testMap); 168 int totalCount = 0; 169 int totalSum = 0; 170 const auto iterateWithDeletion = [&totalCount, &totalSum](const uint32_t& key, 171 BpfMap<uint32_t, uint32_t>& map) { 172 EXPECT_GE((uint32_t)TEST_MAP_SIZE, key); 173 totalCount++; 174 totalSum += key; 175 return map.deleteValue(key); 176 }; 177 EXPECT_RESULT_OK(testMap.iterate(iterateWithDeletion)); 178 EXPECT_EQ((int)TEST_MAP_SIZE, totalCount); 179 EXPECT_EQ(((1 + TEST_MAP_SIZE - 1) * (TEST_MAP_SIZE - 1)) / 2, (uint32_t)totalSum); 180 expectMapEmpty(testMap); 181 } 182 183 TEST_F(BpfMapTest, iterateWithValue) { 184 BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); 185 populateMap(TEST_MAP_SIZE, testMap); 186 int totalCount = 0; 187 int totalSum = 0; 188 const auto iterateWithDeletion = [&totalCount, &totalSum](const uint32_t& key, 189 const uint32_t& value, 190 BpfMap<uint32_t, uint32_t>& map) { 191 EXPECT_GE((uint32_t)TEST_MAP_SIZE, key); 192 EXPECT_EQ(value, key * 10); 193 totalCount++; 194 totalSum += value; 195 return map.deleteValue(key); 196 }; 197 EXPECT_RESULT_OK(testMap.iterateWithValue(iterateWithDeletion)); 198 EXPECT_EQ((int)TEST_MAP_SIZE, totalCount); 199 EXPECT_EQ(((1 + TEST_MAP_SIZE - 1) * (TEST_MAP_SIZE - 1)) * 5, (uint32_t)totalSum); 200 expectMapEmpty(testMap); 201 } 202 203 TEST_F(BpfMapTest, mapIsEmpty) { 204 BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); 205 expectMapEmpty(testMap); 206 uint32_t key = TEST_KEY1; 207 uint32_t value_write = TEST_VALUE1; 208 writeToMapAndCheck(testMap, key, value_write); 209 Result<bool> isEmpty = testMap.isEmpty(); 210 ASSERT_RESULT_OK(isEmpty); 211 ASSERT_FALSE(isEmpty.value()); 212 ASSERT_RESULT_OK(testMap.deleteValue(key)); 213 ASSERT_GT(0, findMapEntry(testMap.getMap(), &key, &value_write)); 214 ASSERT_EQ(ENOENT, errno); 215 expectMapEmpty(testMap); 216 int entriesSeen = 0; 217 EXPECT_RESULT_OK(testMap.iterate( 218 [&entriesSeen](const unsigned int&, 219 const BpfMap<unsigned int, unsigned int>&) -> Result<void> { 220 entriesSeen++; 221 return {}; 222 })); 223 EXPECT_EQ(0, entriesSeen); 224 EXPECT_RESULT_OK(testMap.iterateWithValue( 225 [&entriesSeen](const unsigned int&, const unsigned int&, 226 const BpfMap<unsigned int, unsigned int>&) -> Result<void> { 227 entriesSeen++; 228 return {}; 229 })); 230 EXPECT_EQ(0, entriesSeen); 231 } 232 233 TEST_F(BpfMapTest, mapClear) { 234 BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); 235 populateMap(TEST_MAP_SIZE, testMap); 236 Result<bool> isEmpty = testMap.isEmpty(); 237 ASSERT_RESULT_OK(isEmpty); 238 ASSERT_FALSE(*isEmpty); 239 ASSERT_RESULT_OK(testMap.clear()); 240 expectMapEmpty(testMap); 241 } 242 243 } // namespace bpf 244 } // namespace android 245