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:
BpfMapTest()54 BpfMapTest() {}
55
SetUp()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
TearDown()63 void TearDown() {
64 if (!access(PINNED_MAP_PATH, R_OK)) {
65 EXPECT_EQ(0, remove(PINNED_MAP_PATH));
66 }
67 }
68
checkMapInvalid(BpfMap<uint32_t,uint32_t> & map)69 void checkMapInvalid(BpfMap<uint32_t, uint32_t>& map) {
70 EXPECT_FALSE(map.isValid());
71 EXPECT_EQ(-1, map.getMap().get());
72 }
73
checkMapValid(BpfMap<uint32_t,uint32_t> & map)74 void checkMapValid(BpfMap<uint32_t, uint32_t>& map) {
75 EXPECT_LE(0, map.getMap().get());
76 EXPECT_TRUE(map.isValid());
77 }
78
writeToMapAndCheck(BpfMap<uint32_t,uint32_t> & map,uint32_t key,uint32_t value)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
checkValueAndStatus(uint32_t refValue,Result<uint32_t> value)86 void checkValueAndStatus(uint32_t refValue, Result<uint32_t> value) {
87 ASSERT_RESULT_OK(value);
88 ASSERT_EQ(refValue, value.value());
89 }
90
populateMap(uint32_t total,BpfMap<uint32_t,uint32_t> & map)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
expectMapEmpty(BpfMap<uint32_t,uint32_t> & map)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
TEST_F(BpfMapTest,constructor)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
TEST_F(BpfMapTest,basicHelpers)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
TEST_F(BpfMapTest,reset)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
TEST_F(BpfMapTest,moveConstructor)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
TEST_F(BpfMapTest,SetUpMap)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
TEST_F(BpfMapTest,iterate)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
TEST_F(BpfMapTest,iterateWithValue)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
TEST_F(BpfMapTest,mapIsEmpty)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
TEST_F(BpfMapTest,mapClear)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