blob: 94d273e2df8e1eedcba37d105262de100989c98f [file] [log] [blame]
Chenbo Feng75b410b2018-10-10 15:01:19 -07001/*
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
Chenbo Feng75b410b2018-10-10 15:01:19 -070036#include "bpf/BpfMap.h"
Chenbo Feng75b410b2018-10-10 15:01:19 -070037#include "bpf/BpfUtils.h"
38
Chenbo Feng75b410b2018-10-10 15:01:19 -070039using ::testing::Test;
40
41namespace android {
42namespace bpf {
43
44using base::unique_fd;
45using netdutils::StatusOr;
46
47constexpr uint32_t TEST_MAP_SIZE = 10;
48constexpr uint32_t TEST_KEY1 = 1;
49constexpr uint32_t TEST_VALUE1 = 10;
50constexpr const char PINNED_MAP_PATH[] = "/sys/fs/bpf/testMap";
51
52class BpfMapTest : public testing::Test {
53 protected:
54 BpfMapTest() {}
Maciej Żenczykowskie6cbd402019-08-09 18:20:26 -070055
56 // SetUp() will always populate this with a map, but only some tests will use it.
57 // They may use it once via 'mMapFd.release()', or multiple times via 'dup(mMapFd)'
58 // to initialize a BpfMap object.
59 // If it's not used or only dup'ed then TearDown() will close() it, otherwise
60 // whoever got ownership via mMapFd.release() will close() it - possibly much earlier.
61 unique_fd mMapFd;
Chenbo Feng75b410b2018-10-10 15:01:19 -070062
63 void SetUp() {
Chenbo Feng249e2f82018-11-20 17:37:00 -080064 SKIP_IF_BPF_NOT_SUPPORTED;
65
Chenbo Feng0a1a9a12019-04-09 12:05:04 -070066 EXPECT_EQ(0, setrlimitForTest());
Chenbo Feng75b410b2018-10-10 15:01:19 -070067 if (!access(PINNED_MAP_PATH, R_OK)) {
68 EXPECT_EQ(0, remove(PINNED_MAP_PATH));
69 }
Maciej Żenczykowskie6cbd402019-08-09 18:20:26 -070070 mMapFd.reset(createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint32_t), TEST_MAP_SIZE,
71 BPF_F_NO_PREALLOC));
72 ASSERT_LE(0, mMapFd);
Chenbo Feng75b410b2018-10-10 15:01:19 -070073 }
74
75 void TearDown() {
Chenbo Feng249e2f82018-11-20 17:37:00 -080076 SKIP_IF_BPF_NOT_SUPPORTED;
77
Chenbo Feng75b410b2018-10-10 15:01:19 -070078 if (!access(PINNED_MAP_PATH, R_OK)) {
79 EXPECT_EQ(0, remove(PINNED_MAP_PATH));
80 }
Maciej Żenczykowskie6cbd402019-08-09 18:20:26 -070081
82 mMapFd.reset(-1); // close(mMapFd) if still open
Chenbo Feng75b410b2018-10-10 15:01:19 -070083 }
84
85 void checkMapInvalid(BpfMap<uint32_t, uint32_t>& map) {
86 EXPECT_FALSE(map.isValid());
87 EXPECT_EQ(-1, map.getMap().get());
Chenbo Feng75b410b2018-10-10 15:01:19 -070088 }
89
90 void checkMapValid(BpfMap<uint32_t, uint32_t>& map) {
91 EXPECT_LE(0, map.getMap().get());
92 EXPECT_TRUE(map.isValid());
93 }
94
95 void writeToMapAndCheck(BpfMap<uint32_t, uint32_t>& map, uint32_t key, uint32_t value) {
96 ASSERT_TRUE(isOk(map.writeValue(key, value, BPF_ANY)));
97 uint32_t value_read;
98 ASSERT_EQ(0, findMapEntry(map.getMap(), &key, &value_read));
99 checkValueAndStatus(value, value_read);
100 }
101
102 void checkValueAndStatus(uint32_t refValue, StatusOr<uint32_t> value) {
103 ASSERT_TRUE(isOk(value.status()));
104 ASSERT_EQ(refValue, value.value());
105 }
106
107 void populateMap(uint32_t total, BpfMap<uint32_t, uint32_t>& map) {
108 for (uint32_t key = 0; key < total; key++) {
109 uint32_t value = key * 10;
110 EXPECT_TRUE(isOk(map.writeValue(key, value, BPF_ANY)));
111 }
112 }
113
114 void expectMapEmpty(BpfMap<uint32_t, uint32_t>& map) {
115 auto isEmpty = map.isEmpty();
116 ASSERT_TRUE(isOk(isEmpty));
117 ASSERT_TRUE(isEmpty.value());
118 }
119};
120
121TEST_F(BpfMapTest, constructor) {
Chenbo Feng249e2f82018-11-20 17:37:00 -0800122 SKIP_IF_BPF_NOT_SUPPORTED;
123
Chenbo Feng75b410b2018-10-10 15:01:19 -0700124 BpfMap<uint32_t, uint32_t> testMap1;
125 checkMapInvalid(testMap1);
126
Maciej Żenczykowskie6cbd402019-08-09 18:20:26 -0700127 BpfMap<uint32_t, uint32_t> testMap2(mMapFd.release());
Chenbo Feng75b410b2018-10-10 15:01:19 -0700128 checkMapValid(testMap2);
Chenbo Feng75b410b2018-10-10 15:01:19 -0700129
130 BpfMap<uint32_t, uint32_t> testMap3(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
131 checkMapValid(testMap3);
Chenbo Feng75b410b2018-10-10 15:01:19 -0700132}
133
134TEST_F(BpfMapTest, basicHelpers) {
Chenbo Feng249e2f82018-11-20 17:37:00 -0800135 SKIP_IF_BPF_NOT_SUPPORTED;
136
Maciej Żenczykowskie6cbd402019-08-09 18:20:26 -0700137 BpfMap<uint32_t, uint32_t> testMap(mMapFd.release());
Chenbo Feng75b410b2018-10-10 15:01:19 -0700138 uint32_t key = TEST_KEY1;
139 uint32_t value_write = TEST_VALUE1;
140 writeToMapAndCheck(testMap, key, value_write);
141 StatusOr<uint32_t> value_read = testMap.readValue(key);
142 checkValueAndStatus(value_write, value_read);
143 StatusOr<uint32_t> key_read = testMap.getFirstKey();
144 checkValueAndStatus(key, key_read);
145 ASSERT_TRUE(isOk(testMap.deleteValue(key)));
146 ASSERT_GT(0, findMapEntry(testMap.getMap(), &key, &value_read));
147 ASSERT_EQ(ENOENT, errno);
148}
149
150TEST_F(BpfMapTest, reset) {
Chenbo Feng249e2f82018-11-20 17:37:00 -0800151 SKIP_IF_BPF_NOT_SUPPORTED;
152
Chenbo Feng75b410b2018-10-10 15:01:19 -0700153 BpfMap<uint32_t, uint32_t> testMap;
Maciej Żenczykowskie6cbd402019-08-09 18:20:26 -0700154 testMap.reset(mMapFd.release());
Chenbo Feng75b410b2018-10-10 15:01:19 -0700155 uint32_t key = TEST_KEY1;
156 uint32_t value_write = TEST_VALUE1;
157 writeToMapAndCheck(testMap, key, value_write);
Maciej Żenczykowskie6cbd402019-08-09 18:20:26 -0700158
Chenbo Feng75b410b2018-10-10 15:01:19 -0700159 testMap.reset();
160 checkMapInvalid(testMap);
Maciej Żenczykowskie6cbd402019-08-09 18:20:26 -0700161 ASSERT_GT(0, findMapEntry(testMap.getMap(), &key, &value_write));
Chenbo Feng75b410b2018-10-10 15:01:19 -0700162 ASSERT_EQ(EBADF, errno);
163}
164
165TEST_F(BpfMapTest, moveConstructor) {
Chenbo Feng249e2f82018-11-20 17:37:00 -0800166 SKIP_IF_BPF_NOT_SUPPORTED;
167
Maciej Żenczykowskie6cbd402019-08-09 18:20:26 -0700168 BpfMap<uint32_t, uint32_t> testMap1(mMapFd.release());
Chenbo Feng75b410b2018-10-10 15:01:19 -0700169 BpfMap<uint32_t, uint32_t> testMap2;
170 testMap2 = std::move(testMap1);
171 uint32_t key = TEST_KEY1;
172 checkMapInvalid(testMap1);
173 uint32_t value = TEST_VALUE1;
174 writeToMapAndCheck(testMap2, key, value);
175}
176
Chenbo Feng75b410b2018-10-10 15:01:19 -0700177TEST_F(BpfMapTest, SetUpMap) {
Chenbo Feng249e2f82018-11-20 17:37:00 -0800178 SKIP_IF_BPF_NOT_SUPPORTED;
179
Maciej Żenczykowski04d88b72019-04-01 10:34:26 -0700180 EXPECT_NE(0, access(PINNED_MAP_PATH, R_OK));
181 BpfMap<uint32_t, uint32_t> testMap1(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
182 ASSERT_EQ(0, bpfFdPin(testMap1.getMap(), PINNED_MAP_PATH));
Chenbo Feng75b410b2018-10-10 15:01:19 -0700183 EXPECT_EQ(0, access(PINNED_MAP_PATH, R_OK));
184 checkMapValid(testMap1);
Chenbo Feng75b410b2018-10-10 15:01:19 -0700185 BpfMap<uint32_t, uint32_t> testMap2;
Maciej Żenczykowski52108bf2019-04-01 10:41:13 -0700186 EXPECT_OK(testMap2.init(PINNED_MAP_PATH));
Chenbo Feng75b410b2018-10-10 15:01:19 -0700187 checkMapValid(testMap2);
Chenbo Feng75b410b2018-10-10 15:01:19 -0700188 uint32_t key = TEST_KEY1;
189 uint32_t value = TEST_VALUE1;
190 writeToMapAndCheck(testMap1, key, value);
191 StatusOr<uint32_t> value_read = testMap2.readValue(key);
192 checkValueAndStatus(value, value_read);
193}
194
195TEST_F(BpfMapTest, iterate) {
Chenbo Feng249e2f82018-11-20 17:37:00 -0800196 SKIP_IF_BPF_NOT_SUPPORTED;
197
Maciej Żenczykowskie6cbd402019-08-09 18:20:26 -0700198 BpfMap<uint32_t, uint32_t> testMap(mMapFd.release());
Chenbo Feng75b410b2018-10-10 15:01:19 -0700199 populateMap(TEST_MAP_SIZE, testMap);
200 int totalCount = 0;
201 int totalSum = 0;
202 const auto iterateWithDeletion = [&totalCount, &totalSum](const uint32_t& key,
203 BpfMap<uint32_t, uint32_t>& map) {
204 EXPECT_GE((uint32_t)TEST_MAP_SIZE, key);
205 totalCount++;
206 totalSum += key;
207 return map.deleteValue(key);
208 };
209 EXPECT_OK(testMap.iterate(iterateWithDeletion));
210 EXPECT_EQ((int)TEST_MAP_SIZE, totalCount);
211 EXPECT_EQ(((1 + TEST_MAP_SIZE - 1) * (TEST_MAP_SIZE - 1)) / 2, (uint32_t)totalSum);
212 expectMapEmpty(testMap);
213}
214
215TEST_F(BpfMapTest, iterateWithValue) {
Chenbo Feng249e2f82018-11-20 17:37:00 -0800216 SKIP_IF_BPF_NOT_SUPPORTED;
217
Maciej Żenczykowskie6cbd402019-08-09 18:20:26 -0700218 BpfMap<uint32_t, uint32_t> testMap(mMapFd.release());
Chenbo Feng75b410b2018-10-10 15:01:19 -0700219 populateMap(TEST_MAP_SIZE, testMap);
220 int totalCount = 0;
221 int totalSum = 0;
222 const auto iterateWithDeletion = [&totalCount, &totalSum](const uint32_t& key,
223 const uint32_t& value,
224 BpfMap<uint32_t, uint32_t>& map) {
225 EXPECT_GE((uint32_t)TEST_MAP_SIZE, key);
226 EXPECT_EQ(value, key * 10);
227 totalCount++;
228 totalSum += value;
229 return map.deleteValue(key);
230 };
231 EXPECT_OK(testMap.iterateWithValue(iterateWithDeletion));
232 EXPECT_EQ((int)TEST_MAP_SIZE, totalCount);
233 EXPECT_EQ(((1 + TEST_MAP_SIZE - 1) * (TEST_MAP_SIZE - 1)) * 5, (uint32_t)totalSum);
234 expectMapEmpty(testMap);
235}
236
237TEST_F(BpfMapTest, mapIsEmpty) {
Chenbo Feng249e2f82018-11-20 17:37:00 -0800238 SKIP_IF_BPF_NOT_SUPPORTED;
239
Maciej Żenczykowskie6cbd402019-08-09 18:20:26 -0700240 BpfMap<uint32_t, uint32_t> testMap(mMapFd.release());
Chenbo Feng75b410b2018-10-10 15:01:19 -0700241 expectMapEmpty(testMap);
242 uint32_t key = TEST_KEY1;
243 uint32_t value_write = TEST_VALUE1;
244 writeToMapAndCheck(testMap, key, value_write);
245 auto isEmpty = testMap.isEmpty();
246 ASSERT_TRUE(isOk(isEmpty));
247 ASSERT_FALSE(isEmpty.value());
248 ASSERT_TRUE(isOk(testMap.deleteValue(key)));
249 ASSERT_GT(0, findMapEntry(testMap.getMap(), &key, &value_write));
250 ASSERT_EQ(ENOENT, errno);
251 expectMapEmpty(testMap);
252 int entriesSeen = 0;
253 EXPECT_OK(testMap.iterate(
Chenbo Feng1f20ad32018-11-26 15:18:46 -0800254 [&entriesSeen](const unsigned int&,
255 const BpfMap<unsigned int, unsigned int>&) -> netdutils::Status {
256 entriesSeen++;
257 return netdutils::status::ok;
258 }));
Chenbo Feng75b410b2018-10-10 15:01:19 -0700259 EXPECT_EQ(0, entriesSeen);
260 EXPECT_OK(testMap.iterateWithValue(
Chenbo Feng1f20ad32018-11-26 15:18:46 -0800261 [&entriesSeen](const unsigned int&, const unsigned int&,
262 const BpfMap<unsigned int, unsigned int>&) -> netdutils::Status {
263 entriesSeen++;
264 return netdutils::status::ok;
265 }));
Chenbo Feng75b410b2018-10-10 15:01:19 -0700266 EXPECT_EQ(0, entriesSeen);
267}
268
269TEST_F(BpfMapTest, mapClear) {
Chenbo Feng249e2f82018-11-20 17:37:00 -0800270 SKIP_IF_BPF_NOT_SUPPORTED;
271
Maciej Żenczykowskie6cbd402019-08-09 18:20:26 -0700272 BpfMap<uint32_t, uint32_t> testMap(mMapFd.release());
Chenbo Feng75b410b2018-10-10 15:01:19 -0700273 populateMap(TEST_MAP_SIZE, testMap);
274 auto isEmpty = testMap.isEmpty();
275 ASSERT_TRUE(isOk(isEmpty));
276 ASSERT_FALSE(isEmpty.value());
277 ASSERT_TRUE(isOk(testMap.clear()));
278 expectMapEmpty(testMap);
279}
280
281} // namespace bpf
282} // namespace android