• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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