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::unique_fd; 45 using netdutils::StatusOr; 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 int mMapFd; 56 57 void SetUp() { 58 SKIP_IF_BPF_NOT_SUPPORTED; 59 60 EXPECT_EQ(0, setrlimitForTest()); 61 if (!access(PINNED_MAP_PATH, R_OK)) { 62 EXPECT_EQ(0, remove(PINNED_MAP_PATH)); 63 } 64 mMapFd = createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint32_t), TEST_MAP_SIZE, 65 BPF_F_NO_PREALLOC); 66 EXPECT_LE(0, mMapFd); 67 } 68 69 void TearDown() { 70 SKIP_IF_BPF_NOT_SUPPORTED; 71 72 if (!access(PINNED_MAP_PATH, R_OK)) { 73 EXPECT_EQ(0, remove(PINNED_MAP_PATH)); 74 } 75 close(mMapFd); 76 } 77 78 void checkMapInvalid(BpfMap<uint32_t, uint32_t>& map) { 79 EXPECT_FALSE(map.isValid()); 80 EXPECT_EQ(-1, map.getMap().get()); 81 } 82 83 void checkMapValid(BpfMap<uint32_t, uint32_t>& map) { 84 EXPECT_LE(0, map.getMap().get()); 85 EXPECT_TRUE(map.isValid()); 86 } 87 88 void writeToMapAndCheck(BpfMap<uint32_t, uint32_t>& map, uint32_t key, uint32_t value) { 89 ASSERT_TRUE(isOk(map.writeValue(key, value, BPF_ANY))); 90 uint32_t value_read; 91 ASSERT_EQ(0, findMapEntry(map.getMap(), &key, &value_read)); 92 checkValueAndStatus(value, value_read); 93 } 94 95 void checkValueAndStatus(uint32_t refValue, StatusOr<uint32_t> value) { 96 ASSERT_TRUE(isOk(value.status())); 97 ASSERT_EQ(refValue, value.value()); 98 } 99 100 void populateMap(uint32_t total, BpfMap<uint32_t, uint32_t>& map) { 101 for (uint32_t key = 0; key < total; key++) { 102 uint32_t value = key * 10; 103 EXPECT_TRUE(isOk(map.writeValue(key, value, BPF_ANY))); 104 } 105 } 106 107 void expectMapEmpty(BpfMap<uint32_t, uint32_t>& map) { 108 auto isEmpty = map.isEmpty(); 109 ASSERT_TRUE(isOk(isEmpty)); 110 ASSERT_TRUE(isEmpty.value()); 111 } 112 }; 113 114 TEST_F(BpfMapTest, constructor) { 115 SKIP_IF_BPF_NOT_SUPPORTED; 116 117 BpfMap<uint32_t, uint32_t> testMap1; 118 checkMapInvalid(testMap1); 119 120 BpfMap<uint32_t, uint32_t> testMap2(mMapFd); 121 checkMapValid(testMap2); 122 123 BpfMap<uint32_t, uint32_t> testMap3(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); 124 checkMapValid(testMap3); 125 } 126 127 TEST_F(BpfMapTest, basicHelpers) { 128 SKIP_IF_BPF_NOT_SUPPORTED; 129 130 BpfMap<uint32_t, uint32_t> testMap(mMapFd); 131 uint32_t key = TEST_KEY1; 132 uint32_t value_write = TEST_VALUE1; 133 writeToMapAndCheck(testMap, key, value_write); 134 StatusOr<uint32_t> value_read = testMap.readValue(key); 135 checkValueAndStatus(value_write, value_read); 136 StatusOr<uint32_t> key_read = testMap.getFirstKey(); 137 checkValueAndStatus(key, key_read); 138 ASSERT_TRUE(isOk(testMap.deleteValue(key))); 139 ASSERT_GT(0, findMapEntry(testMap.getMap(), &key, &value_read)); 140 ASSERT_EQ(ENOENT, errno); 141 } 142 143 TEST_F(BpfMapTest, reset) { 144 SKIP_IF_BPF_NOT_SUPPORTED; 145 146 BpfMap<uint32_t, uint32_t> testMap; 147 testMap.reset(mMapFd); 148 uint32_t key = TEST_KEY1; 149 uint32_t value_write = TEST_VALUE1; 150 writeToMapAndCheck(testMap, key, value_write); 151 testMap.reset(); 152 checkMapInvalid(testMap); 153 unique_fd invalidFd(mMapFd); 154 ASSERT_GT(0, findMapEntry(invalidFd, &key, &value_write)); 155 ASSERT_EQ(EBADF, errno); 156 } 157 158 TEST_F(BpfMapTest, moveConstructor) { 159 SKIP_IF_BPF_NOT_SUPPORTED; 160 161 BpfMap<uint32_t, uint32_t> testMap1(mMapFd); 162 BpfMap<uint32_t, uint32_t> testMap2; 163 testMap2 = std::move(testMap1); 164 uint32_t key = TEST_KEY1; 165 checkMapInvalid(testMap1); 166 uint32_t value = TEST_VALUE1; 167 writeToMapAndCheck(testMap2, key, value); 168 } 169 170 TEST_F(BpfMapTest, SetUpMap) { 171 SKIP_IF_BPF_NOT_SUPPORTED; 172 173 EXPECT_NE(0, access(PINNED_MAP_PATH, R_OK)); 174 BpfMap<uint32_t, uint32_t> testMap1(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC); 175 ASSERT_EQ(0, bpfFdPin(testMap1.getMap(), PINNED_MAP_PATH)); 176 EXPECT_EQ(0, access(PINNED_MAP_PATH, R_OK)); 177 checkMapValid(testMap1); 178 BpfMap<uint32_t, uint32_t> testMap2; 179 EXPECT_OK(testMap2.init(PINNED_MAP_PATH)); 180 checkMapValid(testMap2); 181 uint32_t key = TEST_KEY1; 182 uint32_t value = TEST_VALUE1; 183 writeToMapAndCheck(testMap1, key, value); 184 StatusOr<uint32_t> value_read = testMap2.readValue(key); 185 checkValueAndStatus(value, value_read); 186 } 187 188 TEST_F(BpfMapTest, iterate) { 189 SKIP_IF_BPF_NOT_SUPPORTED; 190 191 BpfMap<uint32_t, uint32_t> testMap(mMapFd); 192 populateMap(TEST_MAP_SIZE, testMap); 193 int totalCount = 0; 194 int totalSum = 0; 195 const auto iterateWithDeletion = [&totalCount, &totalSum](const uint32_t& key, 196 BpfMap<uint32_t, uint32_t>& map) { 197 EXPECT_GE((uint32_t)TEST_MAP_SIZE, key); 198 totalCount++; 199 totalSum += key; 200 return map.deleteValue(key); 201 }; 202 EXPECT_OK(testMap.iterate(iterateWithDeletion)); 203 EXPECT_EQ((int)TEST_MAP_SIZE, totalCount); 204 EXPECT_EQ(((1 + TEST_MAP_SIZE - 1) * (TEST_MAP_SIZE - 1)) / 2, (uint32_t)totalSum); 205 expectMapEmpty(testMap); 206 } 207 208 TEST_F(BpfMapTest, iterateWithValue) { 209 SKIP_IF_BPF_NOT_SUPPORTED; 210 211 BpfMap<uint32_t, uint32_t> testMap(mMapFd); 212 populateMap(TEST_MAP_SIZE, testMap); 213 int totalCount = 0; 214 int totalSum = 0; 215 const auto iterateWithDeletion = [&totalCount, &totalSum](const uint32_t& key, 216 const uint32_t& value, 217 BpfMap<uint32_t, uint32_t>& map) { 218 EXPECT_GE((uint32_t)TEST_MAP_SIZE, key); 219 EXPECT_EQ(value, key * 10); 220 totalCount++; 221 totalSum += value; 222 return map.deleteValue(key); 223 }; 224 EXPECT_OK(testMap.iterateWithValue(iterateWithDeletion)); 225 EXPECT_EQ((int)TEST_MAP_SIZE, totalCount); 226 EXPECT_EQ(((1 + TEST_MAP_SIZE - 1) * (TEST_MAP_SIZE - 1)) * 5, (uint32_t)totalSum); 227 expectMapEmpty(testMap); 228 } 229 230 TEST_F(BpfMapTest, mapIsEmpty) { 231 SKIP_IF_BPF_NOT_SUPPORTED; 232 233 BpfMap<uint32_t, uint32_t> testMap(mMapFd); 234 expectMapEmpty(testMap); 235 uint32_t key = TEST_KEY1; 236 uint32_t value_write = TEST_VALUE1; 237 writeToMapAndCheck(testMap, key, value_write); 238 auto isEmpty = testMap.isEmpty(); 239 ASSERT_TRUE(isOk(isEmpty)); 240 ASSERT_FALSE(isEmpty.value()); 241 ASSERT_TRUE(isOk(testMap.deleteValue(key))); 242 ASSERT_GT(0, findMapEntry(testMap.getMap(), &key, &value_write)); 243 ASSERT_EQ(ENOENT, errno); 244 expectMapEmpty(testMap); 245 int entriesSeen = 0; 246 EXPECT_OK(testMap.iterate( 247 [&entriesSeen](const unsigned int&, 248 const BpfMap<unsigned int, unsigned int>&) -> netdutils::Status { 249 entriesSeen++; 250 return netdutils::status::ok; 251 })); 252 EXPECT_EQ(0, entriesSeen); 253 EXPECT_OK(testMap.iterateWithValue( 254 [&entriesSeen](const unsigned int&, const unsigned int&, 255 const BpfMap<unsigned int, unsigned int>&) -> netdutils::Status { 256 entriesSeen++; 257 return netdutils::status::ok; 258 })); 259 EXPECT_EQ(0, entriesSeen); 260 } 261 262 TEST_F(BpfMapTest, mapClear) { 263 SKIP_IF_BPF_NOT_SUPPORTED; 264 265 BpfMap<uint32_t, uint32_t> testMap(mMapFd); 266 populateMap(TEST_MAP_SIZE, testMap); 267 auto isEmpty = testMap.isEmpty(); 268 ASSERT_TRUE(isOk(isEmpty)); 269 ASSERT_FALSE(isEmpty.value()); 270 ASSERT_TRUE(isOk(testMap.clear())); 271 expectMapEmpty(testMap); 272 } 273 274 } // namespace bpf 275 } // namespace android 276