BpfMapTest.cpp 8.5 KB

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